Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a55a9d811f | ||
|
|
d639fde539 | ||
|
|
b4b68df0ae | ||
|
|
981b6406c0 | ||
|
|
5e199cfa0b | ||
|
|
6eb6d385a4 | ||
|
|
39d402049c | ||
|
|
9cf78dc536 | ||
|
|
fb93911abd | ||
|
|
49e665774b | ||
|
|
25eda48a3e | ||
|
|
83121a9276 | ||
|
|
28216a08d0 | ||
|
|
c684505ebf | ||
|
|
07a15f62bc | ||
|
|
33d2011a27 | ||
|
|
3548df523b | ||
|
|
e7d8be2a22 | ||
|
|
ce833e16c2 | ||
|
|
bb43bedd1b | ||
|
|
78c5a4d7bf | ||
|
|
0029c4c6d2 | ||
|
|
243948cf49 | ||
|
|
f5b7cda053 | ||
|
|
c41fc95f00 | ||
|
|
e83805b300 | ||
|
|
72672dfcdf | ||
|
|
01ebdeece7 | ||
|
|
3804b350b0 | ||
|
|
a90c8256ac | ||
|
|
cbb1de0747 | ||
|
|
31c13515f0 | ||
|
|
e26c21ec6a | ||
|
|
4f4539934c | ||
|
|
65a141da5c | ||
|
|
22317a454d | ||
|
|
e620174fa1 | ||
|
|
49d33649df | ||
|
|
9fbf37481b | ||
|
|
0cea547c4f | ||
|
|
6e251f7173 | ||
|
|
ef91cf73a8 | ||
|
|
fad5d9842f | ||
|
|
9f26001bc8 | ||
|
|
bcb9781035 | ||
|
|
70189e5d59 | ||
|
|
e40d3d1b04 | ||
|
|
a5ab8472a9 | ||
|
|
f2bdfb14c9 | ||
|
|
b4e0bfae0a | ||
|
|
2c13f6dcb3 | ||
|
|
cd8b0e7093 | ||
|
|
250ce9b4c4 | ||
|
|
334233b8b4 | ||
|
|
b2d7d9d14d | ||
|
|
5603603668 | ||
|
|
74c946175b | ||
|
|
915e66bd59 | ||
|
|
9b741d7ec0 | ||
|
|
561379dac2 | ||
|
|
3074dfd9ae | ||
|
|
1bfd5c9ff9 | ||
|
|
22a45b74e4 | ||
|
|
0ea255a2a3 | ||
|
|
2d67fb19aa | ||
|
|
229d704bb1 | ||
|
|
3a77f3c766 | ||
|
|
7dee9083bf | ||
|
|
0c27d7d9bd | ||
|
|
0ea1c5b379 | ||
|
|
f4c4fc430b | ||
|
|
38706a4615 | ||
|
|
c6f34e97e1 | ||
|
|
babc2e0a42 | ||
|
|
b83801cd1d | ||
|
|
ab4c934b26 | ||
|
|
6b74a02b30 | ||
|
|
cdb1f790c6 | ||
|
|
b4bf7ee4d1 | ||
|
|
d7a9ee6fd1 | ||
|
|
5d97e97a02 | ||
|
|
46ab81d988 | ||
|
|
986a709b06 | ||
|
|
eaab261be9 | ||
|
|
b5920e7d76 | ||
|
|
9cebcace5a | ||
|
|
5497d301ef | ||
|
|
b47f852c7f | ||
|
|
05681171df | ||
|
|
1cb463b85f | ||
|
|
8ba6ef7870 | ||
|
|
80ddb1fd5f | ||
|
|
f9010b3041 | ||
|
|
5382f56c89 | ||
|
|
ab80400e05 | ||
|
|
2807a9a019 | ||
|
|
f212f570b5 | ||
|
|
6d84915363 | ||
|
|
725c1bf71e | ||
|
|
e4f3dfc970 | ||
|
|
b5253a6bc0 | ||
|
|
edc2939d62 | ||
|
|
6c66ad4264 | ||
|
|
be12ca902a | ||
|
|
532336c95f | ||
|
|
4760951963 | ||
|
|
49170e8ba4 | ||
|
|
51cb76965a | ||
|
|
5d8d8fda64 | ||
|
|
901155057d | ||
|
|
e7cc80f9c6 | ||
|
|
19214d2c92 | ||
|
|
b3f8dc4f39 | ||
|
|
c27e0498e3 | ||
|
|
f90b9a192c | ||
|
|
4783c97432 | ||
|
|
c47bb6dc12 | ||
|
|
5599962713 | ||
|
|
82d82a7487 | ||
|
|
4628e4d51d | ||
|
|
b19a3e8a2a | ||
|
|
1ca7c2f734 | ||
|
|
1a17308ebc | ||
|
|
bb3ee67256 | ||
|
|
e2c19a5c3f | ||
|
|
6f3a254a52 | ||
|
|
58d0f59832 | ||
|
|
13947616f2 | ||
|
|
933b58e2e5 | ||
|
|
e882e4aa17 | ||
|
|
48ead9b9fc | ||
|
|
9f7ee32765 | ||
|
|
d34d8125c5 | ||
|
|
64f3832257 | ||
|
|
71cf4c580f | ||
|
|
e4f46da8f9 | ||
|
|
acad839530 | ||
|
|
46f06c8da1 | ||
|
|
9205cd7410 | ||
|
|
770383635f | ||
|
|
6c6ab09596 | ||
|
|
5e5eb236f1 | ||
|
|
3f4609d2a2 | ||
|
|
fb119ec3a3 | ||
|
|
2589171a3e | ||
|
|
1b65ead4be | ||
|
|
eebe11c094 | ||
|
|
88164a3e93 | ||
|
|
5292bbecf6 | ||
|
|
e9e780a3ce | ||
|
|
b796fd2581 | ||
|
|
e3415ca597 | ||
|
|
a02d7a2553 | ||
|
|
0f1b6b083b | ||
|
|
c8e1090610 | ||
|
|
ddb5cec68b | ||
|
|
bd3536ffb9 | ||
|
|
d41c1ee841 | ||
|
|
ce1d11b55a | ||
|
|
6f38d7cb1c | ||
|
|
1d364a3cc1 | ||
|
|
f3eae752e7 | ||
|
|
f44fdf84f8 | ||
|
|
044b0cd9c4 | ||
|
|
052d173ca1 | ||
|
|
c412be02c8 | ||
|
|
daf931a5c1 | ||
|
|
f48db81990 | ||
|
|
968dc9d8d7 | ||
|
|
1ce0be81c7 | ||
|
|
c325df7d21 | ||
|
|
77ec0a7fa6 | ||
|
|
d991d3c6d8 | ||
|
|
330a4419da | ||
|
|
eec316ef37 | ||
|
|
6c83ccf15f | ||
|
|
ab57e73c85 | ||
|
|
939365f7f4 | ||
|
|
b32831853a | ||
|
|
2d8b1a472c | ||
|
|
34bd7d3456 | ||
|
|
bae4a48ed2 | ||
|
|
fe4e66a405 | ||
|
|
5173efe21d | ||
|
|
e94dc8f0bc | ||
|
|
edcfba0948 | ||
|
|
dbc0bda0d2 | ||
|
|
69a6d0c684 | ||
|
|
38f7164dca | ||
|
|
b25d7ed939 | ||
|
|
8cc4873063 | ||
|
|
9c416977cc | ||
|
|
df26b33c79 | ||
|
|
ccf61b13f5 | ||
|
|
7e29e89eec | ||
|
|
5163f1cee0 | ||
|
|
7427253fb3 | ||
|
|
7f4ee3df34 | ||
|
|
b56e857c8f | ||
|
|
a3f6bc8bc4 | ||
|
|
f1833b6ba5 | ||
|
|
89d5e93f0e | ||
|
|
a7af71f158 | ||
|
|
a64801809a | ||
|
|
0ef5b9635e | ||
|
|
7cf8719d3f | ||
|
|
285387f39a | ||
|
|
adc9f2d49d | ||
|
|
cc9d943769 | ||
|
|
c3aaf097fc | ||
|
|
69f78d5f76 | ||
|
|
a69c8cb53c | ||
|
|
b96b5476cd | ||
|
|
708024605b | ||
|
|
b495a0142a | ||
|
|
4c85b86231 | ||
|
|
e46c37c7a2 | ||
|
|
35e1d8c2eb | ||
|
|
2832cd657b | ||
|
|
00bdb0bf55 | ||
|
|
8b4b2ecb18 | ||
|
|
d2c15d88d7 | ||
|
|
04343af119 | ||
|
|
e771458a32 | ||
|
|
733cd009aa | ||
|
|
91ce33f075 | ||
|
|
0f451562a3 | ||
|
|
e99bae6b62 | ||
|
|
cfbf99befa | ||
|
|
c600f77b84 | ||
|
|
cbe390f0ba | ||
|
|
b689983799 | ||
|
|
8cf817342d | ||
|
|
0e5ab4fc9c | ||
|
|
3216188a7e | ||
|
|
f2369f10e9 | ||
|
|
03283c3746 | ||
|
|
af860e0084 | ||
|
|
2e6e2815d6 | ||
|
|
9ba5cb776c | ||
|
|
cb592731c5 | ||
|
|
82f1f64d65 | ||
|
|
a7adaa8abd | ||
|
|
ce49da77ac | ||
|
|
0e8bc6b0e1 | ||
|
|
2f95b6e7c8 | ||
|
|
762517f448 | ||
|
|
201dd62c81 | ||
|
|
f6ea959c01 | ||
|
|
1d71efeccc | ||
|
|
93310265a2 | ||
|
|
3803169987 | ||
|
|
173a4a0aa0 | ||
|
|
4a21ea2b1a | ||
|
|
002c7002e7 | ||
|
|
c9382e0c15 | ||
|
|
68318ba410 | ||
|
|
9def104a84 | ||
|
|
c52629cda2 | ||
|
|
95b763d9ed | ||
|
|
7ed3876d19 | ||
|
|
2935e989f7 | ||
|
|
5f182b7fb6 | ||
|
|
fdc7198274 | ||
|
|
d779b98eda | ||
|
|
74a4c7da77 | ||
|
|
c24227daab | ||
|
|
5695d038ce | ||
|
|
87fcc7793b | ||
|
|
9597fef6d4 | ||
|
|
04fc3f89f4 | ||
|
|
c276d6d9b8 | ||
|
|
58663b6968 | ||
|
|
0bea7d4ff4 | ||
|
|
e12959b97d | ||
|
|
b966f2e6a5 | ||
|
|
772c4fe326 | ||
|
|
e2e0784a4a | ||
|
|
b577dcc3d5 | ||
|
|
c741f8b2c4 | ||
|
|
09cb005c7a | ||
|
|
c4aa0fd4b1 | ||
|
|
efe38cae1a | ||
|
|
50b1a9d422 | ||
|
|
4817cd48d6 | ||
|
|
d6b3b161d4 | ||
|
|
4205a510ca | ||
|
|
b2af4fe021 | ||
|
|
f916a40ebb | ||
|
|
d8dd7f6f17 | ||
|
|
0116657897 | ||
|
|
333220bc4a | ||
|
|
66f422bf68 | ||
|
|
4b3654d4a4 | ||
|
|
2da3d2955e | ||
|
|
3bde6ee880 | ||
|
|
1bbe09a7d0 | ||
|
|
577fb7cfab | ||
|
|
d4df6f7b78 | ||
|
|
cf121c24b6 | ||
|
|
690f4a7a76 | ||
|
|
56ed632842 | ||
|
|
314386131f | ||
|
|
c2a6938339 | ||
|
|
4433eadae3 | ||
|
|
53422cbd74 | ||
|
|
f128c58b03 | ||
|
|
34c7ce3913 | ||
|
|
93b0da92e1 | ||
|
|
1a4ce7b1d6 | ||
|
|
11d9ce5a53 | ||
|
|
90813f382f | ||
|
|
44e9bb95c5 | ||
|
|
4eb633389d | ||
|
|
77bff33162 | ||
|
|
524c9ec28a | ||
|
|
dfca398d7a | ||
|
|
0b17ec8bd9 | ||
|
|
14d4ba3c6c | ||
|
|
15997b3136 | ||
|
|
55abcc302e | ||
|
|
326186e7e8 | ||
|
|
8c89eabc2c | ||
|
|
6bd88aeaae | ||
|
|
f20c93e0b7 | ||
|
|
d0ec82b68e | ||
|
|
d571630134 | ||
|
|
fae6f15d19 | ||
|
|
4e9af8fb7b | ||
|
|
bf82bae8de | ||
|
|
93e49639fd | ||
|
|
ce8f209917 | ||
|
|
0d6a16ecaa | ||
|
|
00d1b622ef | ||
|
|
59d242507c | ||
|
|
3f770ebc9e | ||
|
|
88e83a37ee | ||
|
|
2558318d6c | ||
|
|
3d73a122ef | ||
|
|
0d5615a7a8 | ||
|
|
67fccaae2d | ||
|
|
7590fd7418 | ||
|
|
a25148bc06 | ||
|
|
7fd8bc825c | ||
|
|
4cab274e96 | ||
|
|
2fbb0153b4 | ||
|
|
212217b4e7 | ||
|
|
681145c147 | ||
|
|
f318bcdf15 | ||
|
|
43d2be6e99 | ||
|
|
7dc3916e1b | ||
|
|
69d8b89783 | ||
|
|
1ec774e13e | ||
|
|
071a07a8e3 | ||
|
|
480d4121da | ||
|
|
3ea94bec9a | ||
|
|
8f334577c7 | ||
|
|
359c667d84 | ||
|
|
58cba6552d | ||
|
|
0e47d23766 | ||
|
|
5309042a27 | ||
|
|
539a6db158 | ||
|
|
36aee4dc5c | ||
|
|
fa582bc835 | ||
|
|
dbe860e5b4 | ||
|
|
783a29c5db | ||
|
|
f7d3fffa8e | ||
|
|
01581b84b4 | ||
|
|
0162fc71d5 | ||
|
|
b63e1f6b18 | ||
|
|
53b0712a95 | ||
|
|
84b6111315 | ||
|
|
50d5f11580 | ||
|
|
8d8d90f355 | ||
|
|
e292f6b2e2 | ||
|
|
bdb58dc906 | ||
|
|
fc06f763e3 | ||
|
|
8a31dc797b | ||
|
|
e67b535296 | ||
|
|
898e582bcb | ||
|
|
f99f4d6f87 | ||
|
|
2aab1e1f92 | ||
|
|
ea4f012989 | ||
|
|
21dff1472f | ||
|
|
cfe8511ca1 | ||
|
|
9ea7cfeb2c | ||
|
|
eea548eeca | ||
|
|
541a269f80 | ||
|
|
63e0a2342e | ||
|
|
866911abfe | ||
|
|
e31699a3a4 | ||
|
|
88c3958419 | ||
|
|
8557b7b02e | ||
|
|
aa7c6a01b7 | ||
|
|
0b855bed3e | ||
|
|
7b938a2393 | ||
|
|
5b91325106 | ||
|
|
0659ec6155 | ||
|
|
19f10649c9 | ||
|
|
d226529b82 | ||
|
|
a3918baf18 | ||
|
|
bbbd24e310 | ||
|
|
763c92e8cc | ||
|
|
b5967a341b | ||
|
|
ce8606c24c | ||
|
|
8c18a8e1bf | ||
|
|
fa3ccac520 | ||
|
|
5388464f3a | ||
|
|
9650e2cb25 | ||
|
|
e1d781fdb3 | ||
|
|
565f0cd4bc | ||
|
|
b820044d80 | ||
|
|
d69dd39690 | ||
|
|
8cac5c213e | ||
|
|
d96b91ca95 | ||
|
|
485329b0a9 | ||
|
|
e3ca9fb4e0 | ||
|
|
04f3299873 | ||
|
|
f1de715996 | ||
|
|
10cd28c29e | ||
|
|
9a9b22679f | ||
|
|
75b438079e | ||
|
|
a42497d16a | ||
|
|
c21540f4ea | ||
|
|
48b1b93b6d | ||
|
|
7f0380c7de | ||
|
|
caa82de2cd | ||
|
|
14365690c4 | ||
|
|
3749f9fc85 | ||
|
|
19ec4a9c3f | ||
|
|
81b93abb6f | ||
|
|
aa0a63a9be | ||
|
|
a981e8c99a | ||
|
|
60ed742106 | ||
|
|
e2db0246fc | ||
|
|
48150741f1 | ||
|
|
ec88c54514 | ||
|
|
d88d0821b0 | ||
|
|
15c7610aa5 | ||
|
|
3860747977 | ||
|
|
85608f7f63 | ||
|
|
125d3db595 | ||
|
|
a9e4c5a7fc | ||
|
|
1433c04dfb | ||
|
|
c493e7249f | ||
|
|
79361eb451 | ||
|
|
1613e78eff | ||
|
|
6691cfbcf6 | ||
|
|
6fdcd8934d | ||
|
|
f6bff57092 | ||
|
|
1f0e6a4e98 | ||
|
|
d271c11821 | ||
|
|
38fb6e3860 | ||
|
|
148e8e9140 | ||
|
|
ebab7d9e7d | ||
|
|
6e781d876b | ||
|
|
df476b69cf | ||
|
|
1c438848cd | ||
|
|
813b5ee0e6 | ||
|
|
1a4b11f4f3 | ||
|
|
0559ca0f88 | ||
|
|
f37399a73b | ||
|
|
4af071ae4a | ||
|
|
5bee1671da | ||
|
|
49b015dca6 | ||
|
|
7c9a9f7b48 | ||
|
|
f8bb5e55dc | ||
|
|
eb5556a33d | ||
|
|
25f5d6fda4 | ||
|
|
96578a1860 | ||
|
|
bf1b04e615 | ||
|
|
782aea452e | ||
|
|
e72df550cd | ||
|
|
1842f1b810 | ||
|
|
0a1363a040 | ||
|
|
c8b3c9c5e7 | ||
|
|
0359638061 | ||
|
|
af79109a0e | ||
|
|
71124874c0 | ||
|
|
c4561a09ed | ||
|
|
f4ff8a4956 | ||
|
|
3a6acecfc9 | ||
|
|
335637cb09 | ||
|
|
a2b78e1b35 | ||
|
|
9a0ce7ae68 | ||
|
|
4f394ed8f3 | ||
|
|
4618a46783 | ||
|
|
f509cc1f84 | ||
|
|
7b14f88986 | ||
|
|
04ff8b9ee1 | ||
|
|
91342ecdf6 | ||
|
|
d3827cf6e3 | ||
|
|
cd7edc9a77 | ||
|
|
6071d68c10 | ||
|
|
c225e70858 | ||
|
|
6167bb8173 | ||
|
|
f3e2b74dcf | ||
|
|
ac8ea8eebe | ||
|
|
d9d2586972 | ||
|
|
e4ba174084 | ||
|
|
271996e4db | ||
|
|
beae77dcfb | ||
|
|
f3af733856 | ||
|
|
40c651dd75 | ||
|
|
e8750f030d | ||
|
|
ef0fa3c360 | ||
|
|
257399d155 | ||
|
|
50f553324e | ||
|
|
ed66d9dc23 | ||
|
|
f6fd9d85c1 | ||
|
|
c691a8f6c2 | ||
|
|
49ed4b4e53 | ||
|
|
d364000463 | ||
|
|
b5bb247431 | ||
|
|
1be6670171 | ||
|
|
977035bad8 | ||
|
|
5065927474 | ||
|
|
dc8a933345 | ||
|
|
75f81cb144 | ||
|
|
c5c4f545e3 | ||
|
|
e2624a31f8 | ||
|
|
382b47dc7f | ||
|
|
b5d87dd1eb | ||
|
|
2ff182a4df | ||
|
|
0c7a26d42b | ||
|
|
e8eb447f49 | ||
|
|
1d5cc615e1 | ||
|
|
926dd38018 | ||
|
|
e718d7c923 | ||
|
|
15fad14f3e | ||
|
|
6fd383265e | ||
|
|
11baeece23 | ||
|
|
f302f4e0ba | ||
|
|
0e9e0beba5 | ||
|
|
12742b0d08 | ||
|
|
39c21a926e | ||
|
|
f7de4a1fab | ||
|
|
d8701f2e2d | ||
|
|
e3d1e17db8 | ||
|
|
511c2f8c04 | ||
|
|
4118f01d35 | ||
|
|
7788792cd7 | ||
|
|
5d6a47d666 | ||
|
|
4d263c6246 | ||
|
|
ed59406d6a | ||
|
|
366f668eeb | ||
|
|
3eef2423e5 | ||
|
|
c002a8034a | ||
|
|
3e811e2992 | ||
|
|
48388eff58 | ||
|
|
7039030ccf | ||
|
|
1806f3bb1c | ||
|
|
31b9372ea6 | ||
|
|
092b34b4bc | ||
|
|
11ae97fa98 | ||
|
|
0cb53d51bd | ||
|
|
6ab26e6529 | ||
|
|
7e339667e6 | ||
|
|
b3c51cd7c9 | ||
|
|
6260efcff6 | ||
|
|
7d663ef35f | ||
|
|
b6bbe24b18 | ||
|
|
f99a1d2f5d | ||
|
|
21778b22c7 | ||
|
|
210ba0d73a | ||
|
|
babeb1ec36 | ||
|
|
3f05fdb3b9 | ||
|
|
d378e14c1d | ||
|
|
34b47ea5d1 | ||
|
|
c084418cbf | ||
|
|
e5e441065c | ||
|
|
7a228e85ae | ||
|
|
bc52f7cd58 | ||
|
|
e9d9685237 | ||
|
|
a62e170a43 | ||
|
|
a72b1bc8d4 | ||
|
|
aeb5d28327 | ||
|
|
0d18a3f53e | ||
|
|
c872f6d1ba | ||
|
|
0423793d30 | ||
|
|
2220e87f5a | ||
|
|
a4184f96b7 | ||
|
|
734a20570d | ||
|
|
370c502539 | ||
|
|
f91a3386cf | ||
|
|
ebc139bee6 | ||
|
|
b91018071e | ||
|
|
031dbdbe25 | ||
|
|
b182a98558 | ||
|
|
e8f9eec93b | ||
|
|
36dcb05eba | ||
|
|
fe7916b518 | ||
|
|
7b0475e21e | ||
|
|
dfc5075616 | ||
|
|
bf1f9caefc | ||
|
|
083c63e515 | ||
|
|
accd4b19a7 | ||
|
|
9b7051ec71 | ||
|
|
a113e50cad | ||
|
|
0932a5ac5f | ||
|
|
61e7142c7f | ||
|
|
b273cd7090 | ||
|
|
18790f5a70 | ||
|
|
6d4957d102 | ||
|
|
0070eb1f9b | ||
|
|
7dac7798dc | ||
|
|
f7da9b49fe | ||
|
|
f6928ce39a | ||
|
|
1460e36146 | ||
|
|
de55081bd2 | ||
|
|
28b4394e4b | ||
|
|
5556d96d68 | ||
|
|
47ca035497 | ||
|
|
f651462730 | ||
|
|
c895d6ba80 | ||
|
|
83c3e0cf6e | ||
|
|
fbb52a2eb0 | ||
|
|
a9adf7bf7a | ||
|
|
6f6447b728 | ||
|
|
63afc13705 | ||
|
|
40c8afcbd2 | ||
|
|
68258e27f0 | ||
|
|
ea397ff3b7 |
No files matched your search
@@ -0,0 +1,18 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 180
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 7
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- pinned
|
||||||
|
- security
|
||||||
|
- improvement
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: stale
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
||||||
@@ -20,3 +20,4 @@ launch.json
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
.idea
|
.idea
|
||||||
dist
|
dist
|
||||||
|
/nbproject/private/
|
||||||
Vendored
+2
-1
@@ -21,5 +21,6 @@
|
|||||||
"**/My-Data-Storage": true,
|
"**/My-Data-Storage": true,
|
||||||
"**/My-Log-Files": true,
|
"**/My-Log-Files": true,
|
||||||
},
|
},
|
||||||
"search.maintainFileSearchCache": true
|
"search.maintainFileSearchCache": true,
|
||||||
|
"editor.mouseWheelZoom": true
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ exports.newDesktopApp = function newDesktopApp() {
|
|||||||
|
|
||||||
let thisObject = {
|
let thisObject = {
|
||||||
userProfiles: undefined,
|
userProfiles: undefined,
|
||||||
p2pNetworkClient: undefined,
|
p2pNetworkClientIdentity: undefined,
|
||||||
p2pNetwork: undefined,
|
p2pNetwork: undefined,
|
||||||
p2pNetworkPeers: undefined,
|
p2pNetworkPeers: undefined,
|
||||||
webSocketsInterface: undefined,
|
webSocketsInterface: undefined,
|
||||||
@@ -25,13 +25,13 @@ exports.newDesktopApp = function newDesktopApp() {
|
|||||||
/*
|
/*
|
||||||
We set up ourselves as a Network Client.
|
We set up ourselves as a Network Client.
|
||||||
*/
|
*/
|
||||||
thisObject.p2pNetworkClient = SA.projects.network.modules.p2pNetworkClient.newNetworkModulesP2PNetworkClient()
|
thisObject.p2pNetworkClientIdentity = SA.projects.network.modules.p2pNetworkClientIdentity.newNetworkModulesP2PNetworkClientIdentity()
|
||||||
await thisObject.p2pNetworkClient.initialize()
|
await thisObject.p2pNetworkClientIdentity.initialize()
|
||||||
/*
|
/*
|
||||||
We will read all user profiles plugins and get from there our network identity.
|
We will read all user profiles plugins and get from there our network identity.
|
||||||
*/
|
*/
|
||||||
thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles()
|
thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles()
|
||||||
await thisObject.userProfiles.initialize(global.env.DESKTOP_APP_SIGNING_ACCOUNT, thisObject.p2pNetworkClient)
|
await thisObject.userProfiles.initialize(global.env.DESKTOP_APP_SIGNING_ACCOUNT, thisObject.p2pNetworkClientIdentity)
|
||||||
/*
|
/*
|
||||||
We set up the P2P Network.
|
We set up the P2P Network.
|
||||||
*/
|
*/
|
||||||
@@ -43,7 +43,7 @@ exports.newDesktopApp = function newDesktopApp() {
|
|||||||
thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers()
|
thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers()
|
||||||
await thisObject.p2pNetworkPeers.initialize(
|
await thisObject.p2pNetworkPeers.initialize(
|
||||||
'Network Client',
|
'Network Client',
|
||||||
thisObject.p2pNetworkClient,
|
thisObject.p2pNetworkClientIdentity,
|
||||||
thisObject.p2pNetwork,
|
thisObject.p2pNetwork,
|
||||||
global.env.DESKTOP_APP_MAX_OUTGOING_PEERS
|
global.env.DESKTOP_APP_MAX_OUTGOING_PEERS
|
||||||
)
|
)
|
||||||
@@ -68,11 +68,11 @@ exports.newDesktopApp = function newDesktopApp() {
|
|||||||
*/
|
*/
|
||||||
thisObject.webSocketsInterface = DK.projects.socialTrading.modules.webSocketsInterface.newDesktopModulesWebSocketsInterface()
|
thisObject.webSocketsInterface = DK.projects.socialTrading.modules.webSocketsInterface.newDesktopModulesWebSocketsInterface()
|
||||||
thisObject.webSocketsInterface.initialize()
|
thisObject.webSocketsInterface.initialize()
|
||||||
console.log('Desktop Client Web Sockets Interface ......................................... Listening at port ' + JSON.parse(DK.desktopApp.p2pNetworkClient.node.config).webSocketsPort)
|
console.log('Desktop Client Web Sockets Interface ......................................... Listening at port ' + JSON.parse(DK.desktopApp.p2pNetworkClientIdentity.node.config).webSocketsPort)
|
||||||
|
|
||||||
thisObject.httpInterface = DK.projects.socialTrading.modules.httpInterface.newDesktopModulesHttpInterface()
|
thisObject.httpInterface = DK.projects.socialTrading.modules.httpInterface.newDesktopModulesHttpInterface()
|
||||||
thisObject.httpInterface.initialize()
|
thisObject.httpInterface.initialize()
|
||||||
console.log('Desktop Client Http Interface ................................................ Listening at port ' + JSON.parse(DK.desktopApp.p2pNetworkClient.node.config).webPort)
|
console.log('Desktop Client Http Interface ................................................ Listening at port ' + JSON.parse(DK.desktopApp.p2pNetworkClientIdentity.node.config).webPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
const express = require("./backend/src/index");
|
||||||
|
exports.newDesktopApp = function newDesktopApp() {
|
||||||
|
|
||||||
|
let thisObject = {
|
||||||
|
userProfiles: undefined,
|
||||||
|
p2pNetworkClientIdentity: undefined,
|
||||||
|
p2pNetwork: undefined,
|
||||||
|
p2pNetworkPeers: undefined,
|
||||||
|
webSocketsInterface: undefined,
|
||||||
|
webAppInterface: undefined,
|
||||||
|
p2pNetworkInterface: undefined,
|
||||||
|
socialGraph: undefined,
|
||||||
|
run: run
|
||||||
|
}
|
||||||
|
|
||||||
|
DK.desktopApp = thisObject
|
||||||
|
|
||||||
|
return thisObject
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
|
||||||
|
await setupNetwork()
|
||||||
|
await setupServices()
|
||||||
|
|
||||||
|
async function setupNetwork() {
|
||||||
|
/*
|
||||||
|
We set up ourselves as a Network Client.
|
||||||
|
*/
|
||||||
|
thisObject.p2pNetworkClientIdentity = SA.projects.network.modules.p2pNetworkClientIdentity.newNetworkModulesP2PNetworkClientIdentity()
|
||||||
|
await thisObject.p2pNetworkClientIdentity.initialize()
|
||||||
|
/*
|
||||||
|
We will read all user profiles plugins and get from there our network identity.
|
||||||
|
*/
|
||||||
|
thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles()
|
||||||
|
await thisObject.userProfiles.initialize(global.env.DESKTOP_APP_SIGNING_ACCOUNT, thisObject.p2pNetworkClientIdentity)
|
||||||
|
/*
|
||||||
|
We set up the P2P Network.
|
||||||
|
*/
|
||||||
|
thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork()
|
||||||
|
await thisObject.p2pNetwork.initialize('Network Client')
|
||||||
|
/*
|
||||||
|
Set up the connections to network nodes.
|
||||||
|
*/
|
||||||
|
thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers()
|
||||||
|
await thisObject.p2pNetworkPeers.initialize(
|
||||||
|
'Network Client',
|
||||||
|
thisObject.p2pNetworkClientIdentity,
|
||||||
|
thisObject.p2pNetwork,
|
||||||
|
global.env.DESKTOP_APP_MAX_OUTGOING_PEERS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupServices() {
|
||||||
|
/*
|
||||||
|
This is where we will process all the messages comming from our web app.
|
||||||
|
*/
|
||||||
|
thisObject.webAppInterface = DK.projects.socialTrading.modules.webAppInterface.newSocialTradingModulesWebAppInterface() // this sends events to the p2p network
|
||||||
|
/*
|
||||||
|
This is where we will process all the events comming from the p2p network.
|
||||||
|
*/
|
||||||
|
thisObject.p2pNetworkInterface = DK.projects.socialTrading.modules.p2pNetworkInterface.newSocialTradingModulesP2PNetworkInterface() // this receives events from p2p network
|
||||||
|
/*
|
||||||
|
This is the Personal Social Graph for the user running this App.
|
||||||
|
*/
|
||||||
|
thisObject.socialGraph = DK.projects.socialTrading.modules.socialGraph.newSocialTradingModulesSocialGraph() //
|
||||||
|
await thisObject.socialGraph.initialize()
|
||||||
|
|
||||||
|
|
||||||
|
let express = require('./backend/src/index')
|
||||||
|
let expressPort = JSON.parse(DK.desktopApp.p2pNetworkClientIdentity.node.config).webPort;
|
||||||
|
express.startExpress(expressPort,SA);
|
||||||
|
console.log('express Interface ................................................ Listening at port ' + expressPort);
|
||||||
|
|
||||||
|
/*TODO change this to have a definite port number*/
|
||||||
|
let react = require('./frontend/scripts/start')
|
||||||
|
let reactPort = (+JSON.parse(DK.desktopApp.p2pNetworkClientIdentity.node.config).webPort + 1);
|
||||||
|
react.start(reactPort);
|
||||||
|
console.log('react Interface ................................................ Listening at port ' + reactPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,367 @@
|
|||||||
|
function newWebApp() {
|
||||||
|
/*
|
||||||
|
In it's current state of development, the Web App only has one module.
|
||||||
|
|
||||||
|
Everything is being coded here until some structure emerges.
|
||||||
|
*/
|
||||||
|
let thisObject = {
|
||||||
|
messageReceived: messageReceived,
|
||||||
|
initialize: initialize,
|
||||||
|
finalize: finalize
|
||||||
|
}
|
||||||
|
|
||||||
|
return thisObject
|
||||||
|
|
||||||
|
function finalize() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initialize() {
|
||||||
|
try {
|
||||||
|
setupRootObject(UI, 'UI')
|
||||||
|
setupRootObject(SA, 'SA')
|
||||||
|
await UI.projects.socialTrading.modules.webSocketsWebAppClient.initialize()
|
||||||
|
loadWUserProfileTimeline()
|
||||||
|
loadWhoToFollow()
|
||||||
|
setupEventHandlers()
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[ERROR] initialize -> err.stack = ' + err.stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function setupRootObject(rootObject, rootObjectName) {
|
||||||
|
/!*
|
||||||
|
Here we will setup the UI object, with all the
|
||||||
|
projects and spaces.
|
||||||
|
*!/
|
||||||
|
for (let i = 0; i < UI.schemas.projectSchema.length; i++) {
|
||||||
|
let projectDefinition = UI.schemas.projectSchema[i]
|
||||||
|
rootObject.projects[projectDefinition.propertyName] = {}
|
||||||
|
let projectInstance = rootObject.projects[projectDefinition.propertyName]
|
||||||
|
|
||||||
|
projectInstance.utilities = {}
|
||||||
|
projectInstance.globals = {}
|
||||||
|
projectInstance.functionLibraries = {}
|
||||||
|
projectInstance.modules = {}
|
||||||
|
|
||||||
|
if (projectDefinition[rootObjectName] === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
/!* Set up Globals of this Project *!/
|
||||||
|
if (projectDefinition[rootObjectName].globals !== undefined) {
|
||||||
|
for (let j = 0; j < projectDefinition[rootObjectName].globals.length; j++) {
|
||||||
|
let globalDefinition = projectDefinition[rootObjectName].globals[j]
|
||||||
|
|
||||||
|
if (exports[globalDefinition.functionName] === undefined) {
|
||||||
|
projectInstance.globals[globalDefinition.propertyName] = eval(globalDefinition.functionName + '()')
|
||||||
|
} else {
|
||||||
|
projectInstance.globals[globalDefinition.propertyName] = eval('exports.' + globalDefinition.functionName + '()')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/!* Set up Utilities of this Project *!/
|
||||||
|
if (projectDefinition[rootObjectName].utilities !== undefined) {
|
||||||
|
for (let j = 0; j < projectDefinition[rootObjectName].utilities.length; j++) {
|
||||||
|
let utilityDefinition = projectDefinition[rootObjectName].utilities[j]
|
||||||
|
|
||||||
|
if (exports[utilityDefinition.functionName] === undefined) {
|
||||||
|
projectInstance.utilities[utilityDefinition.propertyName] = eval(utilityDefinition.functionName + '()')
|
||||||
|
} else {
|
||||||
|
projectInstance.utilities[utilityDefinition.propertyName] = eval('exports.' + utilityDefinition.functionName + '()')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/!* Set up Function Libraries of this Project *!/
|
||||||
|
if (projectDefinition[rootObjectName].functionLibraries !== undefined) {
|
||||||
|
for (let j = 0; j < projectDefinition[rootObjectName].functionLibraries.length; j++) {
|
||||||
|
let functionLibraryDefinition = projectDefinition[rootObjectName].functionLibraries[j]
|
||||||
|
|
||||||
|
if (exports[functionLibraryDefinition.functionName] === undefined) {
|
||||||
|
projectInstance.functionLibraries[functionLibraryDefinition.propertyName] = eval(functionLibraryDefinition.functionName + '()')
|
||||||
|
} else {
|
||||||
|
projectInstance.functionLibraries[functionLibraryDefinition.propertyName] = eval('exports.' + functionLibraryDefinition.functionName + '()')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/!* Set up Modules of this Project *!/
|
||||||
|
if (projectDefinition[rootObjectName].modules !== undefined) {
|
||||||
|
for (let j = 0; j < projectDefinition[rootObjectName].modules.length; j++) {
|
||||||
|
let functionLibraryDefinition = projectDefinition[rootObjectName].modules[j]
|
||||||
|
|
||||||
|
if (exports[functionLibraryDefinition.functionName] === undefined) {
|
||||||
|
projectInstance.modules[functionLibraryDefinition.propertyName] = eval(functionLibraryDefinition.functionName + '()')
|
||||||
|
} else {
|
||||||
|
projectInstance.modules[functionLibraryDefinition.propertyName] = eval('exports.' + functionLibraryDefinition.functionName + '()')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
async function loadWUserProfileTimeline() {
|
||||||
|
let queryMessage = {
|
||||||
|
queryType: SA.projects.socialTrading.globals.queryTypes.EVENTS,
|
||||||
|
emitterUserProfileId: undefined,
|
||||||
|
initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_LAST,
|
||||||
|
amountRequested: 100,
|
||||||
|
direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_PAST
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = {
|
||||||
|
requestType: 'Query',
|
||||||
|
queryMessage: JSON.stringify(queryMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
|
||||||
|
JSON.stringify(query)
|
||||||
|
)
|
||||||
|
.then(console.log)
|
||||||
|
.catch(onError)
|
||||||
|
|
||||||
|
function onError(errorMessage) {
|
||||||
|
console.log('[ERROR] Query not executed. ' + errorMessage)
|
||||||
|
console.log('[ERROR] query = ' + JSON.stringify(query))
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToContentDiv(events) {
|
||||||
|
try {
|
||||||
|
let contentDiv = document.getElementById('content-div')
|
||||||
|
/!*
|
||||||
|
Delete al current content.
|
||||||
|
*!/
|
||||||
|
while (contentDiv.childNodes.length > 4) {
|
||||||
|
let childToRemove = contentDiv.childNodes[contentDiv.childNodes.length - 1]
|
||||||
|
contentDiv.removeChild(childToRemove)
|
||||||
|
}
|
||||||
|
/!*
|
||||||
|
Render the timeline.
|
||||||
|
*!/
|
||||||
|
for (let i = 0; i < events.length; i++) {
|
||||||
|
let event = events[i]
|
||||||
|
|
||||||
|
let postDiv = document.createElement("div")
|
||||||
|
postDiv.setAttribute("class", "post-div")
|
||||||
|
let textNode
|
||||||
|
|
||||||
|
switch (event.eventType) {
|
||||||
|
case SA.projects.socialTrading.globals.eventTypes.NEW_USER_POST: {
|
||||||
|
textNode = document.createTextNode(event.emitterUserProfile.userProfileHandle + " POSTED " + event.postText)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case SA.projects.socialTrading.globals.eventTypes.FOLLOW_USER_PROFILE: {
|
||||||
|
textNode = document.createTextNode(event.emitterUserProfile.userProfileHandle + " FOLLOWED " + event.targetUserProfile.userProfileHandle)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case SA.projects.socialTrading.globals.eventTypes.UNFOLLOW_USER_PROFILE: {
|
||||||
|
textNode = document.createTextNode(event.emitterUserProfile.userProfileHandle + " UNFOLLOWED " + event.targetUserProfile.userProfileHandle)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postDiv.appendChild(textNode)
|
||||||
|
contentDiv.appendChild(postDiv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log('[ERROR] err.stack = ' + err.stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
async function loadWhoToFollow() {
|
||||||
|
let queryMessage = {
|
||||||
|
queryType: SA.projects.socialTrading.globals.queryTypes.UNFOLLOWED_USER_PROFILES,
|
||||||
|
emitterUserProfileId: undefined,
|
||||||
|
initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_FIRST,
|
||||||
|
amountRequested: 3,
|
||||||
|
direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_UP
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = {
|
||||||
|
requestType: 'Query',
|
||||||
|
queryMessage: JSON.stringify(queryMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
|
||||||
|
JSON.stringify(query)
|
||||||
|
)
|
||||||
|
.then(addWhoToFollowTable)
|
||||||
|
.catch(onError)
|
||||||
|
|
||||||
|
function onError(errorMessage) {
|
||||||
|
console.log('[ERROR] Query not executed. ' + errorMessage)
|
||||||
|
console.log('[ERROR] query = ' + JSON.stringify(query))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function setupEventHandlers() {
|
||||||
|
/*
|
||||||
|
Add events to process button clicks , and mouseWheel.
|
||||||
|
*/
|
||||||
|
document.addEventListener("click", onClick)
|
||||||
|
document.addEventListener('mousewheel', onMouseWheel, false)
|
||||||
|
|
||||||
|
async function onClick(event) {
|
||||||
|
|
||||||
|
if (event.target && event.target.nodeName === "BUTTON") {
|
||||||
|
switch (event.target.name) {
|
||||||
|
case 'New Post': {
|
||||||
|
let textArea = document.getElementById("new-post-text-area")
|
||||||
|
await sendNewPostEvent(
|
||||||
|
textArea.value
|
||||||
|
)
|
||||||
|
.then(updateTextArea)
|
||||||
|
.catch(onError)
|
||||||
|
|
||||||
|
function updateTextArea() {
|
||||||
|
textArea.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'Follow Profile': {
|
||||||
|
await sendTargetUserProfileEvent(
|
||||||
|
event.target.userProfileId,
|
||||||
|
SA.projects.socialTrading.globals.eventTypes.FOLLOW_USER_PROFILE
|
||||||
|
)
|
||||||
|
.then(updateButton)
|
||||||
|
.catch(onError)
|
||||||
|
|
||||||
|
function updateButton() {
|
||||||
|
let span = document.getElementById('profile-to-follow-span-' + event.target.userProfileId)
|
||||||
|
let button = document.getElementById('profile-to-follow-button-' + event.target.userProfileId)
|
||||||
|
span.setAttribute("class", "profile-to-unfollow-span")
|
||||||
|
button.setAttribute("class", "profile-to-unfollow-button")
|
||||||
|
button.name = 'Unfollow Profile'
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'Unfollow Profile': {
|
||||||
|
await sendTargetUserProfileEvent(
|
||||||
|
event.target.userProfileId,
|
||||||
|
SA.projects.socialTrading.globals.eventTypes.UNFOLLOW_USER_PROFILE
|
||||||
|
)
|
||||||
|
.then(updateButton)
|
||||||
|
.catch(onError)
|
||||||
|
|
||||||
|
/*
|
||||||
|
function updateButton() {
|
||||||
|
let span = document.getElementById('profile-to-follow-span-' + event.target.userProfileId)
|
||||||
|
let button = document.getElementById('profile-to-follow-button-' + event.target.userProfileId)
|
||||||
|
span.setAttribute("class", "profile-to-follow-span")
|
||||||
|
button.setAttribute("class", "profile-to-follow-button")
|
||||||
|
button.name = 'Follow Profile'
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Error Handling
|
||||||
|
*/
|
||||||
|
function onError(errorMessage) {
|
||||||
|
console.log('[ERROR] Click event failed. ' + errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseWheel(event) {
|
||||||
|
let scrollDiv = document.getElementById("scroll-div")
|
||||||
|
scrollDiv.scrollTop = scrollDiv.scrollTop + event.deltaY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendTargetUserProfileEvent(
|
||||||
|
userProfileId,
|
||||||
|
eventType
|
||||||
|
) {
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
asyncCall(resolve, reject)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function asyncCall(resolve, reject) {
|
||||||
|
let eventMessage
|
||||||
|
let event
|
||||||
|
|
||||||
|
eventMessage = {
|
||||||
|
eventType: eventType,
|
||||||
|
eventId: SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId(),
|
||||||
|
targetUserProfileId: userProfileId,
|
||||||
|
timestamp: (new Date()).valueOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
event = {
|
||||||
|
requestType: 'Event',
|
||||||
|
eventMessage: JSON.stringify(eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
|
||||||
|
JSON.stringify(event)
|
||||||
|
)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(onError)
|
||||||
|
|
||||||
|
function onError(errorMessage) {
|
||||||
|
console.log('[ERROR] Event not executed. ' + errorMessage)
|
||||||
|
console.log('[ERROR] event = ' + JSON.stringify(event))
|
||||||
|
reject(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendNewPostEvent(
|
||||||
|
postText
|
||||||
|
) {
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
asyncCall(resolve, reject)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function asyncCall(resolve, reject) {
|
||||||
|
let eventMessage
|
||||||
|
let event
|
||||||
|
|
||||||
|
eventMessage = {
|
||||||
|
eventType: SA.projects.socialTrading.globals.eventTypes.NEW_USER_POST,
|
||||||
|
eventId: SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId(),
|
||||||
|
postText: postText,
|
||||||
|
timestamp: (new Date()).valueOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
event = {
|
||||||
|
requestType: 'Event',
|
||||||
|
eventMessage: JSON.stringify(eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
|
||||||
|
JSON.stringify(event)
|
||||||
|
)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(onError)
|
||||||
|
|
||||||
|
function onError(errorMessage) {
|
||||||
|
console.log('[ERROR] Event not executed. ' + errorMessage)
|
||||||
|
console.log('[ERROR] event = ' + JSON.stringify(event))
|
||||||
|
reject(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageReceived(message) {
|
||||||
|
window.alert(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
exports.startExpress = (port, SA) => {
|
||||||
|
const express = require("express");
|
||||||
|
const app = express();
|
||||||
|
const webAppInterface = DK.projects.socialTrading.modules.webAppInterface.newSocialTradingModulesWebAppInterface();
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
// define a route handler for the default home page
|
||||||
|
app.get("/health-check", (req, res) => {
|
||||||
|
res.send("all good");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/profiles", async (req, res) => {
|
||||||
|
let profiles = await whoToFollow();
|
||||||
|
console.log(profiles)
|
||||||
|
res.send(profiles);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/follow", async (req, res) => {
|
||||||
|
let follow = followProfile(req.body.userProfileId, SA.projects.socialTrading.globals.eventTypes.FOLLOW_USER_PROFILE);
|
||||||
|
res.send("Followed")
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/unFollow", async (req, res) => {
|
||||||
|
let follow = followProfile(req.body.userProfileId, SA.projects.socialTrading.globals.eventTypes.UNFOLLOW_USER_PROFILE);
|
||||||
|
res.send("UnFollow")
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.post("/post", async (req, res) => {
|
||||||
|
console.log(req)
|
||||||
|
let post = createPost(req);
|
||||||
|
res.send(post)
|
||||||
|
});
|
||||||
|
|
||||||
|
// start the Express server
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`server started at http://localhost:${port}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function createPost(postText) {
|
||||||
|
try {
|
||||||
|
let eventMessage;
|
||||||
|
let event;
|
||||||
|
|
||||||
|
eventMessage = {
|
||||||
|
eventType: SA.projects.socialTrading.globals.eventTypes.NEW_USER_POST,
|
||||||
|
eventId: SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId(),
|
||||||
|
postText: postText,
|
||||||
|
timestamp: (new Date()).valueOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
event = {
|
||||||
|
requestType: 'Event',
|
||||||
|
eventMessage: JSON.stringify(eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await webAppInterface.sendMessage(
|
||||||
|
JSON.stringify(event)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function whoToFollow() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
let queryMessage = {
|
||||||
|
queryType: SA.projects.socialTrading.globals.queryTypes.UNFOLLOWED_USER_PROFILES,
|
||||||
|
emitterUserProfileId: undefined,
|
||||||
|
initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_FIRST,
|
||||||
|
amountRequested: 3,
|
||||||
|
direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_UP
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = {
|
||||||
|
requestType: 'Query',
|
||||||
|
queryMessage: JSON.stringify(queryMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await webAppInterface.messageReceived(
|
||||||
|
JSON.stringify(query)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function followProfile(userProfileId, eventType) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
let queryMessage = {
|
||||||
|
queryType: SA.projects.socialTrading.globals.queryTypes.UNFOLLOWED_USER_PROFILES,
|
||||||
|
emitterUserProfileId: undefined,
|
||||||
|
initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_FIRST,
|
||||||
|
amountRequested: 3,
|
||||||
|
direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_UP
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = {
|
||||||
|
requestType: 'Query',
|
||||||
|
queryMessage: JSON.stringify(queryMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await webAppInterface.messageReceived(
|
||||||
|
JSON.stringify(query)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const paths = require('./paths');
|
||||||
|
|
||||||
|
// Make sure that including paths.js after env.js will read .env variables.
|
||||||
|
delete require.cache[require.resolve('./paths')];
|
||||||
|
|
||||||
|
const NODE_ENV = process.env.NODE_ENV;
|
||||||
|
if (!NODE_ENV) {
|
||||||
|
throw new Error(
|
||||||
|
'The NODE_ENV environment variable is required but was not specified.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
||||||
|
const dotenvFiles = [
|
||||||
|
`${paths.dotenv}.${NODE_ENV}.local`,
|
||||||
|
// Don't include `.env.local` for `test` environment
|
||||||
|
// since normally you expect tests to produce the same
|
||||||
|
// results for everyone
|
||||||
|
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
|
||||||
|
`${paths.dotenv}.${NODE_ENV}`,
|
||||||
|
paths.dotenv,
|
||||||
|
].filter(Boolean);
|
||||||
|
|
||||||
|
// Load environment variables from .env* files. Suppress warnings using silent
|
||||||
|
// if this file is missing. dotenv will never modify any environment variables
|
||||||
|
// that have already been set. Variable expansion is supported in .env files.
|
||||||
|
// https://github.com/motdotla/dotenv
|
||||||
|
// https://github.com/motdotla/dotenv-expand
|
||||||
|
dotenvFiles.forEach(dotenvFile => {
|
||||||
|
if (fs.existsSync(dotenvFile)) {
|
||||||
|
require('dotenv-expand')(
|
||||||
|
require('dotenv').config({
|
||||||
|
path: dotenvFile,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// We support resolving modules according to `NODE_PATH`.
|
||||||
|
// This lets you use absolute paths in imports inside large monorepos:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/253.
|
||||||
|
// It works similar to `NODE_PATH` in Node itself:
|
||||||
|
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
|
||||||
|
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
|
||||||
|
// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
|
||||||
|
// We also resolve them to make sure all tools using them work consistently.
|
||||||
|
const appDirectory = fs.realpathSync(process.cwd());
|
||||||
|
process.env.NODE_PATH = (process.env.NODE_PATH || '')
|
||||||
|
.split(path.delimiter)
|
||||||
|
.filter(folder => folder && !path.isAbsolute(folder))
|
||||||
|
.map(folder => path.resolve(appDirectory, folder))
|
||||||
|
.join(path.delimiter);
|
||||||
|
|
||||||
|
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
|
||||||
|
// injected into the application via DefinePlugin in webpack configuration.
|
||||||
|
const REACT_APP = /^REACT_APP_/i;
|
||||||
|
|
||||||
|
function getClientEnvironment(publicUrl) {
|
||||||
|
const raw = Object.keys(process.env)
|
||||||
|
.filter(key => REACT_APP.test(key))
|
||||||
|
.reduce(
|
||||||
|
(env, key) => {
|
||||||
|
env[key] = process.env[key];
|
||||||
|
return env;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Useful for determining whether we’re running in production mode.
|
||||||
|
// Most importantly, it switches React into the correct mode.
|
||||||
|
NODE_ENV: process.env.NODE_ENV || 'development',
|
||||||
|
// Useful for resolving the correct path to static assets in `public`.
|
||||||
|
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
|
||||||
|
// This should only be used as an escape hatch. Normally you would put
|
||||||
|
// images into the `src` and `import` them in code to get their paths.
|
||||||
|
PUBLIC_URL: publicUrl,
|
||||||
|
// We support configuring the sockjs pathname during development.
|
||||||
|
// These settings let a developer run multiple simultaneous projects.
|
||||||
|
// They are used as the connection `hostname`, `pathname` and `port`
|
||||||
|
// in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
|
||||||
|
// and `sockPort` options in webpack-dev-server.
|
||||||
|
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
||||||
|
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
||||||
|
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
||||||
|
// Whether or not react-refresh is enabled.
|
||||||
|
// react-refresh is not 100% stable at this time,
|
||||||
|
// which is why it's disabled by default.
|
||||||
|
// It is defined here so it is available in the webpackHotDevClient.
|
||||||
|
FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Stringify all values so we can feed into webpack DefinePlugin
|
||||||
|
const stringified = {
|
||||||
|
'process.env': Object.keys(raw).reduce((env, key) => {
|
||||||
|
env[key] = JSON.stringify(raw[key]);
|
||||||
|
return env;
|
||||||
|
}, {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return { raw, stringified };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getClientEnvironment;
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const paths = require('./paths');
|
||||||
|
|
||||||
|
// Ensure the certificate and key provided are valid and if not
|
||||||
|
// throw an easy to debug error
|
||||||
|
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
|
||||||
|
let encrypted;
|
||||||
|
try {
|
||||||
|
// publicEncrypt will throw an error with an invalid cert
|
||||||
|
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(
|
||||||
|
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// privateDecrypt will throw an error with an invalid key
|
||||||
|
crypto.privateDecrypt(key, encrypted);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(
|
||||||
|
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
|
||||||
|
err.message
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file and throw an error if it doesn't exist
|
||||||
|
function readEnvFile(file, type) {
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
throw new Error(
|
||||||
|
`You specified ${chalk.cyan(
|
||||||
|
type
|
||||||
|
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return fs.readFileSync(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the https config
|
||||||
|
// Return cert files if provided in env, otherwise just true or false
|
||||||
|
function getHttpsConfig() {
|
||||||
|
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
|
||||||
|
const isHttps = HTTPS === 'true';
|
||||||
|
|
||||||
|
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
|
||||||
|
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
|
||||||
|
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
|
||||||
|
const config = {
|
||||||
|
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
|
||||||
|
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
|
||||||
|
};
|
||||||
|
|
||||||
|
validateKeyAndCerts({ ...config, keyFile, crtFile });
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return isHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getHttpsConfig;
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const paths = require('./paths');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const resolve = require('resolve');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get additional module paths based on the baseUrl of a compilerOptions object.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
*/
|
||||||
|
function getAdditionalModulePaths(options = {}) {
|
||||||
|
const baseUrl = options.baseUrl;
|
||||||
|
|
||||||
|
if (!baseUrl) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||||
|
|
||||||
|
// We don't need to do anything if `baseUrl` is set to `node_modules`. This is
|
||||||
|
// the default behavior.
|
||||||
|
if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the user set the `baseUrl` to `appSrc`.
|
||||||
|
if (path.relative(paths.appSrc, baseUrlResolved) === '') {
|
||||||
|
return [paths.appSrc];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the path is equal to the root directory we ignore it here.
|
||||||
|
// We don't want to allow importing from the root directly as source files are
|
||||||
|
// not transpiled outside of `src`. We do allow importing them with the
|
||||||
|
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
|
||||||
|
// an alias.
|
||||||
|
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
throw new Error(
|
||||||
|
chalk.red.bold(
|
||||||
|
"Your project's `baseUrl` can only be set to `src` or `node_modules`." +
|
||||||
|
' Create React App does not support other values at this time.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get webpack aliases based on the baseUrl of a compilerOptions object.
|
||||||
|
*
|
||||||
|
* @param {*} options
|
||||||
|
*/
|
||||||
|
function getWebpackAliases(options = {}) {
|
||||||
|
const baseUrl = options.baseUrl;
|
||||||
|
|
||||||
|
if (!baseUrl) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||||
|
|
||||||
|
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||||
|
return {
|
||||||
|
src: paths.appSrc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get jest aliases based on the baseUrl of a compilerOptions object.
|
||||||
|
*
|
||||||
|
* @param {*} options
|
||||||
|
*/
|
||||||
|
function getJestAliases(options = {}) {
|
||||||
|
const baseUrl = options.baseUrl;
|
||||||
|
|
||||||
|
if (!baseUrl) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||||
|
|
||||||
|
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||||
|
return {
|
||||||
|
'^src/(.*)$': '<rootDir>/src/$1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getModules() {
|
||||||
|
// Check if TypeScript is setup
|
||||||
|
const hasTsConfig = fs.existsSync(paths.appTsConfig);
|
||||||
|
const hasJsConfig = fs.existsSync(paths.appJsConfig);
|
||||||
|
|
||||||
|
if (hasTsConfig && hasJsConfig) {
|
||||||
|
throw new Error(
|
||||||
|
'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let config;
|
||||||
|
|
||||||
|
// If there's a tsconfig.json we assume it's a
|
||||||
|
// TypeScript project and set up the config
|
||||||
|
// based on tsconfig.json
|
||||||
|
if (hasTsConfig) {
|
||||||
|
const ts = require(resolve.sync('typescript', {
|
||||||
|
basedir: paths.appNodeModules,
|
||||||
|
}));
|
||||||
|
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
|
||||||
|
// Otherwise we'll check if there is jsconfig.json
|
||||||
|
// for non TS projects.
|
||||||
|
} else if (hasJsConfig) {
|
||||||
|
config = require(paths.appJsConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
config = config || {};
|
||||||
|
const options = config.compilerOptions || {};
|
||||||
|
|
||||||
|
const additionalModulePaths = getAdditionalModulePaths(options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
additionalModulePaths: additionalModulePaths,
|
||||||
|
webpackAliases: getWebpackAliases(options),
|
||||||
|
jestAliases: getJestAliases(options),
|
||||||
|
hasTsConfig,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getModules();
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
|
||||||
|
const {appPublic} = require("./paths");
|
||||||
|
|
||||||
|
// Make sure any symlinks in the project folder are resolved:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/637
|
||||||
|
const appDirectory = fs.realpathSync(process.cwd());
|
||||||
|
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
|
||||||
|
|
||||||
|
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
||||||
|
// "public path" at which the app is served.
|
||||||
|
// webpack needs to know it to put the right <script> hrefs into HTML even in
|
||||||
|
// single-page apps that may serve index.html for nested URLs like /todos/42.
|
||||||
|
// We can't use a relative path in HTML because we don't want to load something
|
||||||
|
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
||||||
|
const publicUrlOrPath = getPublicUrlOrPath(
|
||||||
|
process.env.NODE_ENV === 'development',
|
||||||
|
require(resolveApp('package.json')).homepage,
|
||||||
|
process.env.PUBLIC_URL
|
||||||
|
);
|
||||||
|
|
||||||
|
const buildPath = process.env.BUILD_PATH || 'DesktopReact/build';
|
||||||
|
|
||||||
|
const moduleFileExtensions = [
|
||||||
|
'web.mjs',
|
||||||
|
'mjs',
|
||||||
|
'web.js',
|
||||||
|
'js',
|
||||||
|
'web.ts',
|
||||||
|
'ts',
|
||||||
|
'web.tsx',
|
||||||
|
'tsx',
|
||||||
|
'json',
|
||||||
|
'web.jsx',
|
||||||
|
'jsx',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Resolve file paths in the same order as webpack
|
||||||
|
const resolveModule = (resolveFn, filePath) => {
|
||||||
|
const extension = moduleFileExtensions.find(extension =>
|
||||||
|
fs.existsSync(resolveFn(`${filePath}.${extension}`))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (extension) {
|
||||||
|
return resolveFn(`${filePath}.${extension}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveFn(`${filePath}.js`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// config after eject: we're in ./config/
|
||||||
|
module.exports = {
|
||||||
|
dotenv: resolveApp('.env'),
|
||||||
|
appPath: resolveApp('.'),
|
||||||
|
appBuild: resolveApp(buildPath),
|
||||||
|
appPublic: resolveApp('DesktopReact/frontend/public'),
|
||||||
|
appHtml: resolveApp('DesktopReact/frontend/public/index.html'),
|
||||||
|
appIndexJs: resolveModule(resolveApp, 'DesktopReact/frontend/src/index'),
|
||||||
|
appPackageJson: resolveApp('package.json'),
|
||||||
|
appSrc: resolveApp('DesktopReact/frontend/src'),
|
||||||
|
appNodeModules: resolveApp('node_modules'),
|
||||||
|
publicUrlOrPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.moduleFileExtensions = moduleFileExtensions;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const { resolveModuleName } = require('ts-pnp');
|
||||||
|
|
||||||
|
exports.resolveModuleName = (
|
||||||
|
typescript,
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost
|
||||||
|
) => {
|
||||||
|
return resolveModuleName(
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost,
|
||||||
|
typescript.resolveModuleName
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.resolveTypeReferenceDirective = (
|
||||||
|
typescript,
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost
|
||||||
|
) => {
|
||||||
|
return resolveModuleName(
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost,
|
||||||
|
typescript.resolveTypeReferenceDirective
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,757 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const resolve = require('resolve');
|
||||||
|
const PnpWebpackPlugin = require('pnp-webpack-plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
||||||
|
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
|
||||||
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||||
|
const safePostCssParser = require('postcss-safe-parser');
|
||||||
|
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||||
|
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
||||||
|
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
|
||||||
|
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
|
||||||
|
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
||||||
|
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
||||||
|
const ESLintPlugin = require('eslint-webpack-plugin');
|
||||||
|
const paths = require('./paths');
|
||||||
|
const modules = require('./modules');
|
||||||
|
const getClientEnvironment = require('./env');
|
||||||
|
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
||||||
|
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
|
||||||
|
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
|
||||||
|
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||||
|
|
||||||
|
const postcssNormalize = require('postcss-normalize');
|
||||||
|
|
||||||
|
const appPackageJson = require(paths.appPackageJson);
|
||||||
|
|
||||||
|
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||||
|
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
|
||||||
|
|
||||||
|
const webpackDevClientEntry = require.resolve(
|
||||||
|
'react-dev-utils/webpackHotDevClient'
|
||||||
|
);
|
||||||
|
const reactRefreshOverlayEntry = require.resolve(
|
||||||
|
'react-dev-utils/refreshOverlayInterop'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
|
||||||
|
// makes for a smoother build process.
|
||||||
|
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
||||||
|
|
||||||
|
const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === 'true';
|
||||||
|
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true';
|
||||||
|
|
||||||
|
const imageInlineSizeLimit = parseInt(
|
||||||
|
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if TypeScript is setup
|
||||||
|
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||||
|
|
||||||
|
// Get the path to the uncompiled service worker (if it exists).
|
||||||
|
const swSrc = paths.swSrc;
|
||||||
|
|
||||||
|
// style files regexes
|
||||||
|
const cssRegex = /\.css$/;
|
||||||
|
const cssModuleRegex = /\.module\.css$/;
|
||||||
|
const sassRegex = /\.(scss|sass)$/;
|
||||||
|
const sassModuleRegex = /\.module\.(scss|sass)$/;
|
||||||
|
|
||||||
|
const hasJsxRuntime = (() => {
|
||||||
|
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
require.resolve('react/jsx-runtime');
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
// This is the production and development configuration.
|
||||||
|
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
|
||||||
|
module.exports = function (webpackEnv) {
|
||||||
|
const isEnvDevelopment = webpackEnv === 'development';
|
||||||
|
const isEnvProduction = webpackEnv === 'production';
|
||||||
|
|
||||||
|
// Variable used for enabling profiling in Production
|
||||||
|
// passed into alias object. Uses a flag if passed into the build command
|
||||||
|
const isEnvProductionProfile =
|
||||||
|
isEnvProduction && process.argv.includes('--profile');
|
||||||
|
|
||||||
|
// We will provide `paths.publicUrlOrPath` to our app
|
||||||
|
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||||
|
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||||||
|
// Get environment variables to inject into our app.
|
||||||
|
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
||||||
|
|
||||||
|
const shouldUseReactRefresh = env.raw.FAST_REFRESH;
|
||||||
|
|
||||||
|
// common function to get style loaders
|
||||||
|
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||||
|
const loaders = [
|
||||||
|
isEnvDevelopment && require.resolve('style-loader'),
|
||||||
|
isEnvProduction && {
|
||||||
|
loader: MiniCssExtractPlugin.loader,
|
||||||
|
// css is located in `static/css`, use '../../' to locate index.html folder
|
||||||
|
// in production `paths.publicUrlOrPath` can be a relative path
|
||||||
|
options: paths.publicUrlOrPath.startsWith('.')
|
||||||
|
? { publicPath: '../../' }
|
||||||
|
: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: require.resolve('css-loader'),
|
||||||
|
options: cssOptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Options for PostCSS as we reference these options twice
|
||||||
|
// Adds vendor prefixing based on your specified browser support in
|
||||||
|
// package.json
|
||||||
|
loader: require.resolve('postcss-loader'),
|
||||||
|
options: {
|
||||||
|
// Necessary for external CSS imports to work
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2677
|
||||||
|
ident: 'postcss',
|
||||||
|
plugins: () => [
|
||||||
|
require('postcss-flexbugs-fixes'),
|
||||||
|
require('postcss-preset-env')({
|
||||||
|
autoprefixer: {
|
||||||
|
flexbox: 'no-2009',
|
||||||
|
},
|
||||||
|
stage: 3,
|
||||||
|
}),
|
||||||
|
// Adds PostCSS Normalize as the reset css with default options,
|
||||||
|
// so that it honors browserslist config in package.json
|
||||||
|
// which in turn let's users customize the target behavior as per their needs.
|
||||||
|
postcssNormalize(),
|
||||||
|
],
|
||||||
|
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
].filter(Boolean);
|
||||||
|
if (preProcessor) {
|
||||||
|
loaders.push(
|
||||||
|
{
|
||||||
|
loader: require.resolve('resolve-url-loader'),
|
||||||
|
options: {
|
||||||
|
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
|
||||||
|
root: paths.appSrc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: require.resolve(preProcessor),
|
||||||
|
options: {
|
||||||
|
sourceMap: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return loaders;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
|
||||||
|
// Stop compilation early in production
|
||||||
|
bail: isEnvProduction,
|
||||||
|
devtool: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
? 'source-map'
|
||||||
|
: false
|
||||||
|
: isEnvDevelopment && 'cheap-module-source-map',
|
||||||
|
// These are the "entry points" to our application.
|
||||||
|
// This means they will be the "root" imports that are included in JS bundle.
|
||||||
|
entry:
|
||||||
|
isEnvDevelopment && !shouldUseReactRefresh
|
||||||
|
? [
|
||||||
|
// Include an alternative client for WebpackDevServer. A client's job is to
|
||||||
|
// connect to WebpackDevServer by a socket and get notified about changes.
|
||||||
|
// When you save a file, the client will either apply hot updates (in case
|
||||||
|
// of CSS changes), or refresh the page (in case of JS changes). When you
|
||||||
|
// make a syntax error, this client will display a syntax error overlay.
|
||||||
|
// Note: instead of the default WebpackDevServer client, we use a custom one
|
||||||
|
// to bring better experience for Create React App users. You can replace
|
||||||
|
// the line below with these two lines if you prefer the stock client:
|
||||||
|
//
|
||||||
|
// require.resolve('webpack-dev-server/client') + '?/',
|
||||||
|
// require.resolve('webpack/hot/dev-server'),
|
||||||
|
//
|
||||||
|
// When using the experimental react-refresh integration,
|
||||||
|
// the webpack plugin takes care of injecting the dev client for us.
|
||||||
|
webpackDevClientEntry,
|
||||||
|
// Finally, this is your app's code:
|
||||||
|
paths.appIndexJs,
|
||||||
|
// We include the app code last so that if there is a runtime error during
|
||||||
|
// initialization, it doesn't blow up the WebpackDevServer client, and
|
||||||
|
// changing JS code would still trigger a refresh.
|
||||||
|
]
|
||||||
|
: paths.appIndexJs,
|
||||||
|
output: {
|
||||||
|
// The build folder.
|
||||||
|
path: isEnvProduction ? paths.appBuild : undefined,
|
||||||
|
// Add /* filename */ comments to generated require()s in the output.
|
||||||
|
pathinfo: isEnvDevelopment,
|
||||||
|
// There will be one main bundle, and one file per asynchronous chunk.
|
||||||
|
// In development, it does not produce real files.
|
||||||
|
filename: isEnvProduction
|
||||||
|
? 'static/js/[name].[contenthash:8].js'
|
||||||
|
: isEnvDevelopment && 'static/js/bundle.js',
|
||||||
|
// TODO: remove this when upgrading to webpack 5
|
||||||
|
futureEmitAssets: true,
|
||||||
|
// There are also additional JS chunk files if you use code splitting.
|
||||||
|
chunkFilename: isEnvProduction
|
||||||
|
? 'static/js/[name].[contenthash:8].chunk.js'
|
||||||
|
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
||||||
|
// webpack uses `publicPath` to determine where the app is being served from.
|
||||||
|
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||||
|
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||||
|
publicPath: paths.publicUrlOrPath,
|
||||||
|
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||||
|
devtoolModuleFilenameTemplate: isEnvProduction
|
||||||
|
? info =>
|
||||||
|
path
|
||||||
|
.relative(paths.appSrc, info.absoluteResourcePath)
|
||||||
|
.replace(/\\/g, '/')
|
||||||
|
: isEnvDevelopment &&
|
||||||
|
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
||||||
|
// Prevents conflicts when multiple webpack runtimes (from different apps)
|
||||||
|
// are used on the same page.
|
||||||
|
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
|
||||||
|
// this defaults to 'window', but by setting it to 'this' then
|
||||||
|
// module chunks which are built will work in web workers as well.
|
||||||
|
globalObject: 'this',
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: isEnvProduction,
|
||||||
|
minimizer: [
|
||||||
|
// This is only used in production mode
|
||||||
|
new TerserPlugin({
|
||||||
|
terserOptions: {
|
||||||
|
parse: {
|
||||||
|
// We want terser to parse ecma 8 code. However, we don't want it
|
||||||
|
// to apply any minification steps that turns valid ecma 5 code
|
||||||
|
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
||||||
|
// sections only apply transformations that are ecma 5 safe
|
||||||
|
// https://github.com/facebook/create-react-app/pull/4234
|
||||||
|
ecma: 8,
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
ecma: 5,
|
||||||
|
warnings: false,
|
||||||
|
// Disabled because of an issue with Uglify breaking seemingly valid code:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2376
|
||||||
|
// Pending further investigation:
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/2011
|
||||||
|
comparisons: false,
|
||||||
|
// Disabled because of an issue with Terser breaking valid code:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5250
|
||||||
|
// Pending further investigation:
|
||||||
|
// https://github.com/terser-js/terser/issues/120
|
||||||
|
inline: 2,
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
safari10: true,
|
||||||
|
},
|
||||||
|
// Added for profiling in devtools
|
||||||
|
keep_classnames: isEnvProductionProfile,
|
||||||
|
keep_fnames: isEnvProductionProfile,
|
||||||
|
output: {
|
||||||
|
ecma: 5,
|
||||||
|
comments: false,
|
||||||
|
// Turned on because emoji and regex is not minified properly using default
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2488
|
||||||
|
ascii_only: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sourceMap: shouldUseSourceMap,
|
||||||
|
}),
|
||||||
|
// This is only used in production mode
|
||||||
|
new OptimizeCSSAssetsPlugin({
|
||||||
|
cssProcessorOptions: {
|
||||||
|
parser: safePostCssParser,
|
||||||
|
map: shouldUseSourceMap
|
||||||
|
? {
|
||||||
|
// `inline: false` forces the sourcemap to be output into a
|
||||||
|
// separate file
|
||||||
|
inline: false,
|
||||||
|
// `annotation: true` appends the sourceMappingURL to the end of
|
||||||
|
// the css file, helping the browser find the sourcemap
|
||||||
|
annotation: true,
|
||||||
|
}
|
||||||
|
: false,
|
||||||
|
},
|
||||||
|
cssProcessorPluginOptions: {
|
||||||
|
preset: ['default', { minifyFontValues: { removeQuotes: false } }],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
// Automatically split vendor and commons
|
||||||
|
// https://twitter.com/wSokra/status/969633336732905474
|
||||||
|
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||||
|
splitChunks: {
|
||||||
|
chunks: 'all',
|
||||||
|
name: isEnvDevelopment,
|
||||||
|
},
|
||||||
|
// Keep the runtime chunk separated to enable long term caching
|
||||||
|
// https://twitter.com/wSokra/status/969679223278505985
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5358
|
||||||
|
runtimeChunk: {
|
||||||
|
name: entrypoint => `runtime-${entrypoint.name}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
// This allows you to set a fallback for where webpack should look for modules.
|
||||||
|
// We placed these paths second because we want `node_modules` to "win"
|
||||||
|
// if there are any conflicts. This matches Node resolution mechanism.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/253
|
||||||
|
modules: ['node_modules', paths.appNodeModules].concat(
|
||||||
|
modules.additionalModulePaths || []
|
||||||
|
),
|
||||||
|
// These are the reasonable defaults supported by the Node ecosystem.
|
||||||
|
// We also include JSX as a common component filename extension to support
|
||||||
|
// some tools, although we do not recommend using it, see:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/290
|
||||||
|
// `web` extension prefixes have been added for better support
|
||||||
|
// for React Native Web.
|
||||||
|
extensions: paths.moduleFileExtensions
|
||||||
|
.map(ext => `.${ext}`)
|
||||||
|
.filter(ext => useTypeScript || !ext.includes('ts')),
|
||||||
|
alias: {
|
||||||
|
// Support React Native Web
|
||||||
|
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||||
|
'react-native': 'react-native-web',
|
||||||
|
// Allows for better profiling with ReactDevTools
|
||||||
|
...(isEnvProductionProfile && {
|
||||||
|
'react-dom$': 'react-dom/profiling',
|
||||||
|
'scheduler/tracing': 'scheduler/tracing-profiling',
|
||||||
|
}),
|
||||||
|
...(modules.webpackAliases || {}),
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||||
|
// guards against forgotten dependencies and such.
|
||||||
|
PnpWebpackPlugin,
|
||||||
|
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||||
|
// This often causes confusion because we only process files within src/ with babel.
|
||||||
|
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||||
|
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||||
|
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||||
|
new ModuleScopePlugin(paths.appSrc, [
|
||||||
|
paths.appPackageJson,
|
||||||
|
reactRefreshOverlayEntry,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolveLoader: {
|
||||||
|
plugins: [
|
||||||
|
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders
|
||||||
|
// from the current package.
|
||||||
|
PnpWebpackPlugin.moduleLoader(module),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
strictExportPresence: true,
|
||||||
|
rules: [
|
||||||
|
// Disable require.ensure as it's not a standard language feature.
|
||||||
|
{ parser: { requireEnsure: false } },
|
||||||
|
{
|
||||||
|
// "oneOf" will traverse all following loaders until one will
|
||||||
|
// match the requirements. When no loader matches it will fall
|
||||||
|
// back to the "file" loader at the end of the loader list.
|
||||||
|
oneOf: [
|
||||||
|
// TODO: Merge this config once `image/avif` is in the mime-db
|
||||||
|
// https://github.com/jshttp/mime-db
|
||||||
|
{
|
||||||
|
test: [/\.avif$/],
|
||||||
|
loader: require.resolve('url-loader'),
|
||||||
|
options: {
|
||||||
|
limit: imageInlineSizeLimit,
|
||||||
|
mimetype: 'image/avif',
|
||||||
|
name: 'static/media/[name].[hash:8].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// "url" loader works like "file" loader except that it embeds assets
|
||||||
|
// smaller than specified limit in bytes as data URLs to avoid requests.
|
||||||
|
// A missing `test` is equivalent to a match.
|
||||||
|
{
|
||||||
|
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||||
|
loader: require.resolve('url-loader'),
|
||||||
|
options: {
|
||||||
|
limit: imageInlineSizeLimit,
|
||||||
|
name: 'static/media/[name].[hash:8].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Process application JS with Babel.
|
||||||
|
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
|
||||||
|
{
|
||||||
|
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
||||||
|
include: paths.appSrc,
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: {
|
||||||
|
customize: require.resolve(
|
||||||
|
'babel-preset-react-app/webpack-overrides'
|
||||||
|
),
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
require.resolve('babel-preset-react-app'),
|
||||||
|
{
|
||||||
|
runtime: hasJsxRuntime ? 'automatic' : 'classic',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
require.resolve('babel-plugin-named-asset-import'),
|
||||||
|
{
|
||||||
|
loaderMap: {
|
||||||
|
svg: {
|
||||||
|
ReactComponent:
|
||||||
|
'@svgr/webpack?-svgo,+titleProp,+ref![path]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isEnvDevelopment &&
|
||||||
|
shouldUseReactRefresh &&
|
||||||
|
require.resolve('react-refresh/babel'),
|
||||||
|
].filter(Boolean),
|
||||||
|
// This is a feature of `babel-loader` for webpack (not Babel itself).
|
||||||
|
// It enables caching results in ./node_modules/.cache/babel-loader/
|
||||||
|
// directory for faster rebuilds.
|
||||||
|
cacheDirectory: true,
|
||||||
|
// See #6846 for context on why cacheCompression is disabled
|
||||||
|
cacheCompression: false,
|
||||||
|
compact: isEnvProduction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Process any JS outside of the app with Babel.
|
||||||
|
// Unlike the application JS, we only compile the standard ES features.
|
||||||
|
{
|
||||||
|
test: /\.(js|mjs)$/,
|
||||||
|
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: {
|
||||||
|
babelrc: false,
|
||||||
|
configFile: false,
|
||||||
|
compact: false,
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
require.resolve('babel-preset-react-app/dependencies'),
|
||||||
|
{ helpers: true },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
cacheDirectory: true,
|
||||||
|
// See #6846 for context on why cacheCompression is disabled
|
||||||
|
cacheCompression: false,
|
||||||
|
|
||||||
|
// Babel sourcemaps are needed for debugging into node_modules
|
||||||
|
// code. Without the options below, debuggers like VSCode
|
||||||
|
// show incorrect code and set breakpoints on the wrong lines.
|
||||||
|
sourceMaps: shouldUseSourceMap,
|
||||||
|
inputSourceMap: shouldUseSourceMap,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// "postcss" loader applies autoprefixer to our CSS.
|
||||||
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||||
|
// "style" loader turns CSS into JS modules that inject <style> tags.
|
||||||
|
// In production, we use MiniCSSExtractPlugin to extract that CSS
|
||||||
|
// to a file, but in development "style" loader enables hot editing
|
||||||
|
// of CSS.
|
||||||
|
// By default we support CSS Modules with the extension .module.css
|
||||||
|
{
|
||||||
|
test: cssRegex,
|
||||||
|
exclude: cssModuleRegex,
|
||||||
|
use: getStyleLoaders({
|
||||||
|
importLoaders: 1,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
}),
|
||||||
|
// Don't consider CSS imports dead code even if the
|
||||||
|
// containing package claims to have no side effects.
|
||||||
|
// Remove this when webpack adds a warning or an error for this.
|
||||||
|
// See https://github.com/webpack/webpack/issues/6571
|
||||||
|
sideEffects: true,
|
||||||
|
},
|
||||||
|
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||||
|
// using the extension .module.css
|
||||||
|
{
|
||||||
|
test: cssModuleRegex,
|
||||||
|
use: getStyleLoaders({
|
||||||
|
importLoaders: 1,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
modules: {
|
||||||
|
getLocalIdent: getCSSModuleLocalIdent,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
// Opt-in support for SASS (using .scss or .sass extensions).
|
||||||
|
// By default we support SASS Modules with the
|
||||||
|
// extensions .module.scss or .module.sass
|
||||||
|
{
|
||||||
|
test: sassRegex,
|
||||||
|
exclude: sassModuleRegex,
|
||||||
|
use: getStyleLoaders(
|
||||||
|
{
|
||||||
|
importLoaders: 3,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
},
|
||||||
|
'sass-loader'
|
||||||
|
),
|
||||||
|
// Don't consider CSS imports dead code even if the
|
||||||
|
// containing package claims to have no side effects.
|
||||||
|
// Remove this when webpack adds a warning or an error for this.
|
||||||
|
// See https://github.com/webpack/webpack/issues/6571
|
||||||
|
sideEffects: true,
|
||||||
|
},
|
||||||
|
// Adds support for CSS Modules, but using SASS
|
||||||
|
// using the extension .module.scss or .module.sass
|
||||||
|
{
|
||||||
|
test: sassModuleRegex,
|
||||||
|
use: getStyleLoaders(
|
||||||
|
{
|
||||||
|
importLoaders: 3,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
modules: {
|
||||||
|
getLocalIdent: getCSSModuleLocalIdent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'sass-loader'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
// "file" loader makes sure those assets get served by WebpackDevServer.
|
||||||
|
// When you `import` an asset, you get its (virtual) filename.
|
||||||
|
// In production, they would get copied to the `build` folder.
|
||||||
|
// This loader doesn't use a "test" so it will catch all modules
|
||||||
|
// that fall through the other loaders.
|
||||||
|
{
|
||||||
|
loader: require.resolve('file-loader'),
|
||||||
|
// Exclude `js` files to keep "css" loader working as it injects
|
||||||
|
// its runtime that would otherwise be processed through "file" loader.
|
||||||
|
// Also exclude `html` and `json` extensions so they get processed
|
||||||
|
// by webpacks internal loaders.
|
||||||
|
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
|
||||||
|
options: {
|
||||||
|
name: 'static/media/[name].[hash:8].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ** STOP ** Are you adding a new loader?
|
||||||
|
// Make sure to add the new loader(s) before the "file" loader.
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// Generates an `index.html` file with the <script> injected.
|
||||||
|
new HtmlWebpackPlugin(
|
||||||
|
Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
inject: true,
|
||||||
|
template: paths.appHtml,
|
||||||
|
},
|
||||||
|
isEnvProduction
|
||||||
|
? {
|
||||||
|
minify: {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
useShortDoctype: true,
|
||||||
|
removeEmptyAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
keepClosingSlash: true,
|
||||||
|
minifyJS: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyURLs: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Inlines the webpack runtime script. This script is too small to warrant
|
||||||
|
// a network request.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5358
|
||||||
|
isEnvProduction &&
|
||||||
|
shouldInlineRuntimeChunk &&
|
||||||
|
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
|
||||||
|
// Makes some environment variables available in index.html.
|
||||||
|
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||||
|
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
// It will be an empty string unless you specify "homepage"
|
||||||
|
// in `package.json`, in which case it will be the pathname of that URL.
|
||||||
|
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||||
|
// This gives some necessary context to module not found errors, such as
|
||||||
|
// the requesting resource.
|
||||||
|
new ModuleNotFoundPlugin(paths.appPath),
|
||||||
|
// Makes some environment variables available to the JS code, for example:
|
||||||
|
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
|
||||||
|
// It is absolutely essential that NODE_ENV is set to production
|
||||||
|
// during a production build.
|
||||||
|
// Otherwise React will be compiled in the very slow development mode.
|
||||||
|
new webpack.DefinePlugin(env.stringified),
|
||||||
|
// This is necessary to emit hot updates (CSS and Fast Refresh):
|
||||||
|
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
|
||||||
|
// Experimental hot reloading for React .
|
||||||
|
// https://github.com/facebook/react/tree/master/packages/react-refresh
|
||||||
|
isEnvDevelopment &&
|
||||||
|
shouldUseReactRefresh &&
|
||||||
|
new ReactRefreshWebpackPlugin({
|
||||||
|
overlay: {
|
||||||
|
entry: webpackDevClientEntry,
|
||||||
|
// The expected exports are slightly different from what the overlay exports,
|
||||||
|
// so an interop is included here to enable feedback on module-level errors.
|
||||||
|
module: reactRefreshOverlayEntry,
|
||||||
|
// Since we ship a custom dev client and overlay integration,
|
||||||
|
// the bundled socket handling logic can be eliminated.
|
||||||
|
sockIntegration: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// Watcher doesn't work well if you mistype casing in a path so we use
|
||||||
|
// a plugin that prints an error when you attempt to do this.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/240
|
||||||
|
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
||||||
|
// If you require a missing module and then `npm install` it, you still have
|
||||||
|
// to restart the development server for webpack to discover it. This plugin
|
||||||
|
// makes the discovery automatic so you don't have to restart.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/186
|
||||||
|
isEnvDevelopment &&
|
||||||
|
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
|
||||||
|
isEnvProduction &&
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
// Options similar to the same options in webpackOptions.output
|
||||||
|
// both options are optional
|
||||||
|
filename: 'static/css/[name].[contenthash:8].css',
|
||||||
|
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
|
||||||
|
}),
|
||||||
|
// Generate an asset manifest file with the following content:
|
||||||
|
// - "files" key: Mapping of all asset filenames to their corresponding
|
||||||
|
// output file so that tools can pick it up without having to parse
|
||||||
|
// `index.html`
|
||||||
|
// - "entrypoints" key: Array of files which are included in `index.html`,
|
||||||
|
// can be used to reconstruct the HTML if necessary
|
||||||
|
new ManifestPlugin({
|
||||||
|
fileName: 'asset-manifest.json',
|
||||||
|
publicPath: paths.publicUrlOrPath,
|
||||||
|
generate: (seed, files, entrypoints) => {
|
||||||
|
const manifestFiles = files.reduce((manifest, file) => {
|
||||||
|
manifest[file.name] = file.path;
|
||||||
|
return manifest;
|
||||||
|
}, seed);
|
||||||
|
const entrypointFiles = entrypoints.main.filter(
|
||||||
|
fileName => !fileName.endsWith('.map')
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
files: manifestFiles,
|
||||||
|
entrypoints: entrypointFiles,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// Moment.js is an extremely popular library that bundles large locale files
|
||||||
|
// by default due to how webpack interprets its code. This is a practical
|
||||||
|
// solution that requires the user to opt into importing specific locales.
|
||||||
|
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||||
|
// You can remove this if you don't use Moment.js:
|
||||||
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||||
|
// Generate a service worker script that will precache, and keep up to date,
|
||||||
|
// the HTML & assets that are part of the webpack build.
|
||||||
|
isEnvProduction &&
|
||||||
|
fs.existsSync(swSrc) &&
|
||||||
|
new WorkboxWebpackPlugin.InjectManifest({
|
||||||
|
swSrc,
|
||||||
|
dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
|
||||||
|
exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
|
||||||
|
// Bump up the default maximum size (2mb) that's precached,
|
||||||
|
// to make lazy-loading failure scenarios less likely.
|
||||||
|
// See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270
|
||||||
|
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
|
||||||
|
}),
|
||||||
|
// TypeScript type checking
|
||||||
|
useTypeScript &&
|
||||||
|
new ForkTsCheckerWebpackPlugin({
|
||||||
|
typescript: resolve.sync('typescript', {
|
||||||
|
basedir: paths.appNodeModules,
|
||||||
|
}),
|
||||||
|
async: isEnvDevelopment,
|
||||||
|
checkSyntacticErrors: true,
|
||||||
|
resolveModuleNameModule: process.versions.pnp
|
||||||
|
? `${__dirname}/pnpTs.js`
|
||||||
|
: undefined,
|
||||||
|
resolveTypeReferenceDirectiveModule: process.versions.pnp
|
||||||
|
? `${__dirname}/pnpTs.js`
|
||||||
|
: undefined,
|
||||||
|
tsconfig: paths.appTsConfig,
|
||||||
|
reportFiles: [
|
||||||
|
// This one is specifically to match during CI tests,
|
||||||
|
// as micromatch doesn't match
|
||||||
|
// '../cra-template-typescript/template/src/App.tsx'
|
||||||
|
// otherwise.
|
||||||
|
'../**/src/**/*.{ts,tsx}',
|
||||||
|
'**/src/**/*.{ts,tsx}',
|
||||||
|
'!**/src/**/__tests__/**',
|
||||||
|
'!**/src/**/?(*.)(spec|test).*',
|
||||||
|
'!**/src/setupProxy.*',
|
||||||
|
'!**/src/setupTests.*',
|
||||||
|
],
|
||||||
|
silent: true,
|
||||||
|
// The formatter is invoked directly in WebpackDevServerUtils during development
|
||||||
|
formatter: isEnvProduction ? typescriptFormatter : undefined,
|
||||||
|
}),
|
||||||
|
!disableESLintPlugin &&
|
||||||
|
new ESLintPlugin({
|
||||||
|
// Plugin options
|
||||||
|
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
|
||||||
|
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||||
|
eslintPath: require.resolve('eslint'),
|
||||||
|
failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
|
||||||
|
context: paths.appSrc,
|
||||||
|
cache: true,
|
||||||
|
cacheLocation: path.resolve(
|
||||||
|
paths.appNodeModules,
|
||||||
|
'.cache/.eslintcache'
|
||||||
|
),
|
||||||
|
// ESLint class options
|
||||||
|
cwd: paths.appPath,
|
||||||
|
resolvePluginsRelativeTo: __dirname,
|
||||||
|
baseConfig: {
|
||||||
|
extends: [require.resolve('eslint-config-react-app/base')],
|
||||||
|
rules: {
|
||||||
|
...(!hasJsxRuntime && {
|
||||||
|
'react/react-in-jsx-scope': 'error',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
].filter(Boolean),
|
||||||
|
// Some libraries import Node modules but don't use them in the browser.
|
||||||
|
// Tell webpack to provide empty mocks for them so importing them works.
|
||||||
|
node: {
|
||||||
|
module: 'empty',
|
||||||
|
dgram: 'empty',
|
||||||
|
dns: 'mock',
|
||||||
|
fs: 'empty',
|
||||||
|
http2: 'empty',
|
||||||
|
net: 'empty',
|
||||||
|
tls: 'empty',
|
||||||
|
child_process: 'empty',
|
||||||
|
},
|
||||||
|
// Turn off performance processing because we utilize
|
||||||
|
// our own hints via the FileSizeReporter
|
||||||
|
performance: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
|
||||||
|
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
|
||||||
|
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
|
||||||
|
const ignoredFiles = require('react-dev-utils/ignoredFiles');
|
||||||
|
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
|
||||||
|
const paths = require('./paths');
|
||||||
|
const getHttpsConfig = require('./getHttpsConfig');
|
||||||
|
|
||||||
|
const host = process.env.HOST || '0.0.0.0';
|
||||||
|
const sockHost = process.env.WDS_SOCKET_HOST;
|
||||||
|
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node'
|
||||||
|
const sockPort = process.env.WDS_SOCKET_PORT;
|
||||||
|
|
||||||
|
module.exports = function (proxy, allowedHost) {
|
||||||
|
return {
|
||||||
|
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
|
||||||
|
// websites from potentially accessing local content through DNS rebinding:
|
||||||
|
// https://github.com/webpack/webpack-dev-server/issues/887
|
||||||
|
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
|
||||||
|
// However, it made several existing use cases such as development in cloud
|
||||||
|
// environment or subdomains in development significantly more complicated:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2271
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2233
|
||||||
|
// While we're investigating better solutions, for now we will take a
|
||||||
|
// compromise. Since our WDS configuration only serves files in the `public`
|
||||||
|
// folder we won't consider accessing them a vulnerability. However, if you
|
||||||
|
// use the `proxy` feature, it gets more dangerous because it can expose
|
||||||
|
// remote code execution vulnerabilities in backends like Django and Rails.
|
||||||
|
// So we will disable the host check normally, but enable it if you have
|
||||||
|
// specified the `proxy` setting. Finally, we let you override it if you
|
||||||
|
// really know what you're doing with a special environment variable.
|
||||||
|
disableHostCheck:
|
||||||
|
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
|
||||||
|
// Enable gzip compression of generated files.
|
||||||
|
compress: true,
|
||||||
|
// Silence WebpackDevServer's own logs since they're generally not useful.
|
||||||
|
// It will still show compile warnings and errors with this setting.
|
||||||
|
clientLogLevel: 'none',
|
||||||
|
// By default WebpackDevServer serves physical files from current directory
|
||||||
|
// in addition to all the virtual build products that it serves from memory.
|
||||||
|
// This is confusing because those files won’t automatically be available in
|
||||||
|
// production build folder unless we copy them. However, copying the whole
|
||||||
|
// project directory is dangerous because we may expose sensitive files.
|
||||||
|
// Instead, we establish a convention that only files in `public` directory
|
||||||
|
// get served. Our build script will copy `public` into the `build` folder.
|
||||||
|
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
|
||||||
|
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
|
||||||
|
// Note that we only recommend to use `public` folder as an escape hatch
|
||||||
|
// for files like `favicon.ico`, `manifest.json`, and libraries that are
|
||||||
|
// for some reason broken when imported through webpack. If you just want to
|
||||||
|
// use an image, put it in `src` and `import` it from JavaScript instead.
|
||||||
|
contentBase: paths.appPublic,
|
||||||
|
contentBasePublicPath: paths.publicUrlOrPath,
|
||||||
|
// By default files from `contentBase` will not trigger a page reload.
|
||||||
|
watchContentBase: true,
|
||||||
|
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
|
||||||
|
// for the WebpackDevServer client so it can learn when the files were
|
||||||
|
// updated. The WebpackDevServer client is included as an entry point
|
||||||
|
// in the webpack development configuration. Note that only changes
|
||||||
|
// to CSS are currently hot reloaded. JS changes will refresh the browser.
|
||||||
|
hot: true,
|
||||||
|
// Use 'ws' instead of 'sockjs-node' on server since we're using native
|
||||||
|
// websockets in `webpackHotDevClient`.
|
||||||
|
transportMode: 'ws',
|
||||||
|
// Prevent a WS client from getting injected as we're already including
|
||||||
|
// `webpackHotDevClient`.
|
||||||
|
injectClient: false,
|
||||||
|
// Enable custom sockjs pathname for websocket connection to hot reloading server.
|
||||||
|
// Enable custom sockjs hostname, pathname and port for websocket connection
|
||||||
|
// to hot reloading server.
|
||||||
|
sockHost,
|
||||||
|
sockPath,
|
||||||
|
sockPort,
|
||||||
|
// It is important to tell WebpackDevServer to use the same "publicPath" path as
|
||||||
|
// we specified in the webpack config. When homepage is '.', default to serving
|
||||||
|
// from the root.
|
||||||
|
// remove last slash so user can land on `/test` instead of `/test/`
|
||||||
|
publicPath: paths.publicUrlOrPath.slice(0, -1),
|
||||||
|
// WebpackDevServer is noisy by default so we emit custom message instead
|
||||||
|
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
|
||||||
|
quiet: true,
|
||||||
|
// Reportedly, this avoids CPU overload on some systems.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/293
|
||||||
|
// src/node_modules is not ignored to support absolute imports
|
||||||
|
// https://github.com/facebook/create-react-app/issues/1065
|
||||||
|
watchOptions: {
|
||||||
|
ignored: ignoredFiles(paths.appSrc),
|
||||||
|
},
|
||||||
|
https: getHttpsConfig(),
|
||||||
|
host,
|
||||||
|
overlay: false,
|
||||||
|
historyApiFallback: {
|
||||||
|
// Paths with dots should still use the history fallback.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/387.
|
||||||
|
disableDotRule: true,
|
||||||
|
index: paths.publicUrlOrPath,
|
||||||
|
},
|
||||||
|
public: allowedHost,
|
||||||
|
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
|
||||||
|
proxy,
|
||||||
|
before(app, server) {
|
||||||
|
// Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`
|
||||||
|
// middlewares before `redirectServedPath` otherwise will not have any effect
|
||||||
|
// This lets us fetch source contents from webpack for the error overlay
|
||||||
|
app.use(evalSourceMapMiddleware(server));
|
||||||
|
// This lets us open files from the runtime error overlay.
|
||||||
|
app.use(errorOverlayMiddleware());
|
||||||
|
|
||||||
|
if (fs.existsSync(paths.proxySetup)) {
|
||||||
|
// This registers user provided middleware for proxy reasons
|
||||||
|
require(paths.proxySetup)(app);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
after(app) {
|
||||||
|
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
|
||||||
|
app.use(redirectServedPath(paths.publicUrlOrPath));
|
||||||
|
|
||||||
|
// This service worker file is effectively a 'no-op' that will reset any
|
||||||
|
// previous service worker registered for the same host:port combination.
|
||||||
|
// We do this in development to avoid hitting the production cache if
|
||||||
|
// it used the same host and port.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
||||||
|
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>Superalgos Desktop</title>
|
||||||
|
<meta name="description" content="Free and Open Source Crypto Social Trading">
|
||||||
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function loadApp() {
|
||||||
|
// Prevent click-jacking
|
||||||
|
try {
|
||||||
|
if (window === window.top || window.chrome && chrome.app && chrome.app.window) {
|
||||||
|
document.documentElement.style.display = 'block'
|
||||||
|
} else {
|
||||||
|
top.location = self.location
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('CJ protection', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="body" onload="loadApp()">
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"short_name": "React App",
|
||||||
|
"name": "Create React App Sample",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "favicon.ico",
|
||||||
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
|
"type": "image/x-icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo192.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo512.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'production';
|
||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', err => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env');
|
||||||
|
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const bfj = require('bfj');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const configFactory = require('../config/webpack.config');
|
||||||
|
const paths = require('../config/paths');
|
||||||
|
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||||
|
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
|
||||||
|
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
|
||||||
|
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
|
||||||
|
const printBuildError = require('react-dev-utils/printBuildError');
|
||||||
|
|
||||||
|
const measureFileSizesBeforeBuild =
|
||||||
|
FileSizeReporter.measureFileSizesBeforeBuild;
|
||||||
|
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
|
||||||
|
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||||
|
|
||||||
|
// These sizes are pretty large. We'll warn for bundles exceeding them.
|
||||||
|
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
|
||||||
|
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
|
||||||
|
|
||||||
|
const isInteractive = process.stdout.isTTY;
|
||||||
|
|
||||||
|
// Warn and crash if required files are missing
|
||||||
|
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const argv = process.argv.slice(2);
|
||||||
|
const writeStatsJson = argv.indexOf('--stats') !== -1;
|
||||||
|
|
||||||
|
// Generate configuration
|
||||||
|
const config = configFactory('production');
|
||||||
|
|
||||||
|
// We require that you explicitly set browsers and do not fall back to
|
||||||
|
// browserslist defaults.
|
||||||
|
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
||||||
|
checkBrowsers(paths.appPath, isInteractive)
|
||||||
|
.then(() => {
|
||||||
|
// First, read the current file sizes in build directory.
|
||||||
|
// This lets us display how much they changed later.
|
||||||
|
return measureFileSizesBeforeBuild(paths.appBuild);
|
||||||
|
})
|
||||||
|
.then(previousFileSizes => {
|
||||||
|
// Remove all content but keep the directory so that
|
||||||
|
// if you're in it, you don't end up in Trash
|
||||||
|
fs.emptyDirSync(paths.appBuild);
|
||||||
|
// Merge with the public folder
|
||||||
|
copyPublicFolder();
|
||||||
|
// Start the webpack build
|
||||||
|
return build(previousFileSizes);
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
({ stats, previousFileSizes, warnings }) => {
|
||||||
|
if (warnings.length) {
|
||||||
|
console.log(chalk.yellow('Compiled with warnings.\n'));
|
||||||
|
console.log(warnings.join('\n\n'));
|
||||||
|
console.log(
|
||||||
|
'\nSearch for the ' +
|
||||||
|
chalk.underline(chalk.yellow('keywords')) +
|
||||||
|
' to learn more about each warning.'
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'To ignore, add ' +
|
||||||
|
chalk.cyan('// eslint-disable-next-line') +
|
||||||
|
' to the line before.\n'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log(chalk.green('Compiled successfully.\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('File sizes after gzip:\n');
|
||||||
|
printFileSizesAfterBuild(
|
||||||
|
stats,
|
||||||
|
previousFileSizes,
|
||||||
|
paths.appBuild,
|
||||||
|
WARN_AFTER_BUNDLE_GZIP_SIZE,
|
||||||
|
WARN_AFTER_CHUNK_GZIP_SIZE
|
||||||
|
);
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
const appPackage = require(paths.appPackageJson);
|
||||||
|
const publicUrl = paths.publicUrlOrPath;
|
||||||
|
const publicPath = config.output.publicPath;
|
||||||
|
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
||||||
|
printHostingInstructions(
|
||||||
|
appPackage,
|
||||||
|
publicUrl,
|
||||||
|
publicPath,
|
||||||
|
buildFolder,
|
||||||
|
useYarn
|
||||||
|
);
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
||||||
|
if (tscCompileOnError) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
printBuildError(err);
|
||||||
|
} else {
|
||||||
|
console.log(chalk.red('Failed to compile.\n'));
|
||||||
|
printBuildError(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch(err => {
|
||||||
|
if (err && err.message) {
|
||||||
|
console.log(err.message);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the production build and print the deployment instructions.
|
||||||
|
function build(previousFileSizes) {
|
||||||
|
console.log('Creating an optimized production build...');
|
||||||
|
|
||||||
|
const compiler = webpack(config);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
compiler.run((err, stats) => {
|
||||||
|
let messages;
|
||||||
|
if (err) {
|
||||||
|
if (!err.message) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let errMessage = err.message;
|
||||||
|
|
||||||
|
// Add additional information for postcss errors
|
||||||
|
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
|
||||||
|
errMessage +=
|
||||||
|
'\nCompileError: Begins at CSS selector ' +
|
||||||
|
err['postcssNode'].selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
messages = formatWebpackMessages({
|
||||||
|
errors: [errMessage],
|
||||||
|
warnings: [],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
messages = formatWebpackMessages(
|
||||||
|
stats.toJson({ all: false, warnings: true, errors: true })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (messages.errors.length) {
|
||||||
|
// Only keep the first error. Others are often indicative
|
||||||
|
// of the same problem, but confuse the reader with noise.
|
||||||
|
if (messages.errors.length > 1) {
|
||||||
|
messages.errors.length = 1;
|
||||||
|
}
|
||||||
|
return reject(new Error(messages.errors.join('\n\n')));
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
process.env.CI &&
|
||||||
|
(typeof process.env.CI !== 'string' ||
|
||||||
|
process.env.CI.toLowerCase() !== 'false') &&
|
||||||
|
messages.warnings.length
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
'\nTreating warnings as errors because process.env.CI = true.\n' +
|
||||||
|
'Most CI servers set it automatically.\n'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return reject(new Error(messages.warnings.join('\n\n')));
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolveArgs = {
|
||||||
|
stats,
|
||||||
|
previousFileSizes,
|
||||||
|
warnings: messages.warnings,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (writeStatsJson) {
|
||||||
|
return bfj
|
||||||
|
.write(paths.appBuild + '/bundle-stats.json', stats.toJson())
|
||||||
|
.then(() => resolve(resolveArgs))
|
||||||
|
.catch(error => reject(new Error(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(resolveArgs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyPublicFolder() {
|
||||||
|
fs.copySync(paths.appPublic, paths.appBuild, {
|
||||||
|
dereference: true,
|
||||||
|
filter: file => file !== paths.appHtml,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
exports.start = (port) => {
|
||||||
|
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'development';
|
||||||
|
process.env.NODE_ENV = 'development';
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', err => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env');
|
||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const WebpackDevServer = require('webpack-dev-server');
|
||||||
|
const clearConsole = require('react-dev-utils/clearConsole');
|
||||||
|
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||||
|
const {
|
||||||
|
choosePort,
|
||||||
|
createCompiler,
|
||||||
|
prepareProxy,
|
||||||
|
prepareUrls,
|
||||||
|
} = require('react-dev-utils/WebpackDevServerUtils');
|
||||||
|
const openBrowser = require('react-dev-utils/openBrowser');
|
||||||
|
const semver = require('semver');
|
||||||
|
const paths = require('../config/paths');
|
||||||
|
const configFactory = require('../config/webpack.config');
|
||||||
|
const createDevServerConfig = require('../config/webpackDevServer.config');
|
||||||
|
const getClientEnvironment = require('../config/env');
|
||||||
|
const react = require(require.resolve('react', {paths: [paths.appPath]}));
|
||||||
|
|
||||||
|
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
||||||
|
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||||
|
const isInteractive = process.stdout.isTTY;
|
||||||
|
|
||||||
|
// Warn and crash if required files are missing
|
||||||
|
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tools like Cloud9 rely on this.
|
||||||
|
const DEFAULT_PORT = port;
|
||||||
|
const HOST = '0.0.0.0';
|
||||||
|
|
||||||
|
if (process.env.HOST) {
|
||||||
|
console.log(
|
||||||
|
chalk.cyan(
|
||||||
|
`Attempting to bind to HOST environment variable: ${chalk.yellow(
|
||||||
|
chalk.bold(process.env.HOST)
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We require that you explicitly set browsers and do not fall back to
|
||||||
|
// browserslist defaults.
|
||||||
|
const {checkBrowsers} = require('react-dev-utils/browsersHelper');
|
||||||
|
checkBrowsers(paths.appPath, isInteractive)
|
||||||
|
.then(() => {
|
||||||
|
// We attempt to use the default port but if it is busy, we offer the user to
|
||||||
|
// run on a different port. `choosePort()` Promise resolves to the next free port.
|
||||||
|
return choosePort(HOST, DEFAULT_PORT);
|
||||||
|
})
|
||||||
|
.then(port => {
|
||||||
|
if (port == null) {
|
||||||
|
// We have not found a port.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = configFactory('development');
|
||||||
|
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
||||||
|
const appName = require(paths.appPackageJson).name;
|
||||||
|
|
||||||
|
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||||
|
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
||||||
|
const urls = prepareUrls(
|
||||||
|
protocol,
|
||||||
|
HOST,
|
||||||
|
port,
|
||||||
|
paths.publicUrlOrPath.slice(0, -1)
|
||||||
|
);
|
||||||
|
const devSocket = {
|
||||||
|
warnings: warnings =>
|
||||||
|
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
|
||||||
|
errors: errors =>
|
||||||
|
devServer.sockWrite(devServer.sockets, 'errors', errors),
|
||||||
|
};
|
||||||
|
// Create a webpack compiler that is configured with custom messages.
|
||||||
|
const compiler = createCompiler({
|
||||||
|
appName,
|
||||||
|
config,
|
||||||
|
devSocket,
|
||||||
|
urls,
|
||||||
|
useYarn,
|
||||||
|
useTypeScript,
|
||||||
|
tscCompileOnError,
|
||||||
|
webpack,
|
||||||
|
});
|
||||||
|
// Load proxy config
|
||||||
|
const proxySetting = require(paths.appPackageJson).proxy;
|
||||||
|
const proxyConfig = prepareProxy(
|
||||||
|
proxySetting,
|
||||||
|
paths.appPublic,
|
||||||
|
paths.publicUrlOrPath
|
||||||
|
);
|
||||||
|
// Serve webpack assets generated by the compiler over a web server.
|
||||||
|
const serverConfig = createDevServerConfig(
|
||||||
|
proxyConfig,
|
||||||
|
urls.lanUrlForConfig
|
||||||
|
);
|
||||||
|
const devServer = new WebpackDevServer(compiler, serverConfig);
|
||||||
|
// Launch WebpackDevServer.
|
||||||
|
devServer.listen(port, HOST, err => {
|
||||||
|
if (err) {
|
||||||
|
return console.log(err);
|
||||||
|
}
|
||||||
|
if (isInteractive) {
|
||||||
|
clearConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env.raw.FAST_REFRESH && semver.lt(react.version, '16.10.0')) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
`Fast Refresh requires React 16.10 or higher. You are using React ${react.version}.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.cyan('Starting the development server...\n'));
|
||||||
|
openBrowser(urls.localUrlForBrowser);
|
||||||
|
});
|
||||||
|
|
||||||
|
['SIGINT', 'SIGTERM'].forEach(function (sig) {
|
||||||
|
process.on(sig, function () {
|
||||||
|
devServer.close();
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.CI !== 'true') {
|
||||||
|
// Gracefully exit when stdin ends
|
||||||
|
process.stdin.on('end', function () {
|
||||||
|
devServer.close();
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (err && err.message) {
|
||||||
|
console.log(err.message);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'test';
|
||||||
|
process.env.NODE_ENV = 'test';
|
||||||
|
process.env.PUBLIC_URL = '';
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', err => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env');
|
||||||
|
|
||||||
|
|
||||||
|
const jest = require('jest');
|
||||||
|
const execSync = require('child_process').execSync;
|
||||||
|
let argv = process.argv.slice(2);
|
||||||
|
|
||||||
|
function isInGitRepository() {
|
||||||
|
try {
|
||||||
|
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInMercurialRepository() {
|
||||||
|
try {
|
||||||
|
execSync('hg --cwd . root', { stdio: 'ignore' });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch unless on CI or explicitly running all tests
|
||||||
|
if (
|
||||||
|
!process.env.CI &&
|
||||||
|
argv.indexOf('--watchAll') === -1 &&
|
||||||
|
argv.indexOf('--watchAll=false') === -1
|
||||||
|
) {
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5210
|
||||||
|
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
|
||||||
|
argv.push(hasSourceControl ? '--watch' : '--watchAll');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
jest.run(argv);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
const baseURL = 'http://localhost:33249'
|
||||||
|
const GET = 'GET'
|
||||||
|
const POST = 'POST'
|
||||||
|
const DELETE = 'DELETE'
|
||||||
|
const UPDATE = 'UPDATE'
|
||||||
|
|
||||||
|
function getProfiles(){
|
||||||
|
return call('/profiles', GET);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getClientNode(){
|
||||||
|
return call('/ClientNode', GET);
|
||||||
|
}
|
||||||
|
|
||||||
|
function call(endpoint, method, body){
|
||||||
|
return new Promise(async(resolve, reject) => {
|
||||||
|
fetch(baseURL + endpoint, { method:method, body:body })
|
||||||
|
.then(response => resolve(response))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getProfiles,
|
||||||
|
getClientNode
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {BrowserRouter, Route, Routes} from 'react-router-dom';
|
||||||
|
import App from './home/App';
|
||||||
|
import UserProfile from "./userProfile/UserProfile";
|
||||||
|
import NotFound from "./notFound/NotFound";
|
||||||
|
import Feed from "./feed/Feed";
|
||||||
|
import PostPlaceholder from "./postPlaceholder/PostPlaceholder";
|
||||||
|
|
||||||
|
|
||||||
|
const Root = () => {
|
||||||
|
return (
|
||||||
|
<BrowserRouter>
|
||||||
|
<Routes>
|
||||||
|
<Route path='/' element={<App/>}>
|
||||||
|
<Route path='' element={<Feed/>}/>
|
||||||
|
<Route path='Profile' element={<UserProfile/>}>
|
||||||
|
{/*<Route path=':profileId' element={<UserProfile/>}/>*/}
|
||||||
|
</Route>
|
||||||
|
<Route path='Post' element={<PostPlaceholder/>}/>
|
||||||
|
</Route>
|
||||||
|
<Route
|
||||||
|
path="*"
|
||||||
|
element={
|
||||||
|
<NotFound/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Routes>
|
||||||
|
</BrowserRouter>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Root;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
.followButton {
|
||||||
|
margin: 0.5rem;
|
||||||
|
width: 3rem;
|
||||||
|
max-height: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userCard {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.25rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
height: 3rem;
|
||||||
|
width: 3rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import "./UserCard.css"
|
||||||
|
import React, {useEffect} from 'react';
|
||||||
|
import {Button, Card, CardContent, CardMedia, Typography} from "@mui/material";
|
||||||
|
import pic from "../../images/superalgos.png"
|
||||||
|
|
||||||
|
const UserCard = ({name, id,followCallback}) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(`created user with id ${id}`)
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="userCard" variant="outlined">
|
||||||
|
<CardMedia className="avatar"
|
||||||
|
component="img"
|
||||||
|
image={pic}
|
||||||
|
alt="PP"
|
||||||
|
|
||||||
|
/>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="body2">{name}</Typography>
|
||||||
|
</CardContent>
|
||||||
|
<Button className="followButton" size="small" disableElevation variant="outlined" onClick={followCallback}>
|
||||||
|
Follow
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserCard;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.showMore {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import './UsersSidebar.css';
|
||||||
|
import {Stack} from "@mui/material";
|
||||||
|
import SearchBox from "../searchBox/SearchBox";
|
||||||
|
import SuggestedUsers from "../suggestedUsers/SuggestedUsers";
|
||||||
|
|
||||||
|
|
||||||
|
const UsersSidebar = () => {
|
||||||
|
|
||||||
|
const showMoreCallback = () => console.log("clicked show more");
|
||||||
|
return (
|
||||||
|
<Stack direction="column"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
alignItems="center"
|
||||||
|
spacing={2}
|
||||||
|
sx={{minWidth: "max-content"}}>
|
||||||
|
|
||||||
|
<SearchBox/>
|
||||||
|
<SuggestedUsers showMoreCallback={showMoreCallback}/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UsersSidebar;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.feed {
|
||||||
|
width: 40rem;
|
||||||
|
height: 95vh;
|
||||||
|
overflow: auto;
|
||||||
|
-ms-overflow-style: none; /* Hide scrollbar for IE and Edge */
|
||||||
|
scrollbar-width: none; /* Hide scrollbar for Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.feed::-webkit-scrollbar { /* Hide scrollbar for Chrome, Safari and Opera */
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import './Feed.css';
|
||||||
|
import PostPlaceholder from "../postPlaceholder/PostPlaceholder";
|
||||||
|
import PostsFeed from "../postsFeed/PostsFeed";
|
||||||
|
|
||||||
|
const Feed = () => {
|
||||||
|
return (
|
||||||
|
<div className="feed">
|
||||||
|
<PostPlaceholder/>
|
||||||
|
<PostsFeed/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Feed;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.app {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.middleSection{
|
||||||
|
width: 40rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import './App.css';
|
||||||
|
import Sidebar from "../sidebar/Sidebar";
|
||||||
|
import UsersSidebar from "../UsersSidebar/UsersSidebar";
|
||||||
|
import {Stack} from "@mui/material";
|
||||||
|
import {Outlet} from "react-router-dom";
|
||||||
|
import {getProfiles} from '../../api/service'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
getProfiles().then( response => {
|
||||||
|
console.log(response)
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
|
||||||
|
<Stack className="app"
|
||||||
|
direction="row"
|
||||||
|
justifyContent="space-around">
|
||||||
|
<Sidebar/>
|
||||||
|
<Outlet className="middleSection"/>
|
||||||
|
<UsersSidebar/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*noinspection CssInvalidPropertyValue*/
|
||||||
|
.logo {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 3rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import './Logo.css';
|
||||||
|
import React from 'react';
|
||||||
|
import {Avatar, Stack} from "@mui/material";
|
||||||
|
import pic from "../../images/superalgos.png"
|
||||||
|
|
||||||
|
|
||||||
|
const Logo = props => {
|
||||||
|
/* TODO add on click redirect to / */
|
||||||
|
return (
|
||||||
|
<Stack direction="row" className="logo">
|
||||||
|
<Avatar className="icon" alt="SuperAlgos" src={pic}/>
|
||||||
|
<div>SuperAlgos</div>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Logo;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import React, {useEffect} from 'react';
|
||||||
|
import {useNavigate} from "react-router-dom";
|
||||||
|
|
||||||
|
const NotFound = () => {
|
||||||
|
let navigate = useNavigate();
|
||||||
|
useEffect(() => navigate("/"), [navigate])
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NotFound;
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
.post {
|
||||||
|
min-width: 5rem; /* todo needs to set a minimum width, but overriding from parent*/
|
||||||
|
max-width: 100%;
|
||||||
|
min-height: 5rem; /* todo needs tbd. needed actually? */
|
||||||
|
max-height: 100%; /* todo need to be 8rem, but is collapsing without scroll. need fix*/
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postAvatarContainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
.postBody {
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 1.5rem;
|
||||||
|
min-height: 1.5rem;
|
||||||
|
padding-left: 2.8rem;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postUserName {
|
||||||
|
padding: 0.75rem;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postFooterContainer {
|
||||||
|
justify-content: flex-start;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 0.50rem;
|
||||||
|
padding-bottom: 0.50rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postFooterLikeDislike {
|
||||||
|
justify-content: space-evenly;
|
||||||
|
display: flex;
|
||||||
|
width: 30%;
|
||||||
|
padding-left: 0.50rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postFooterRepost {
|
||||||
|
justify-content: flex-end;
|
||||||
|
display: flex;
|
||||||
|
width: 65%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import "./Post.css"
|
||||||
|
import React, {useState} from 'react';
|
||||||
|
import {Avatar, Card, IconButton, Stack, Typography} from "@mui/material";
|
||||||
|
import {Autorenew, ThumbDown, ThumbUp} from "@mui/icons-material";
|
||||||
|
import pic from "../../images/superalgos.png"
|
||||||
|
|
||||||
|
const Post = () => {
|
||||||
|
|
||||||
|
const userName = "User Name",
|
||||||
|
postBody = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||||||
|
|
||||||
|
const [count, setCount] = useState(0); /* todo define one more for dislike button */
|
||||||
|
|
||||||
|
function onLikeButtonClick() { {/* todo console log print need a fix */}
|
||||||
|
console.log("Liked " + count + " times")
|
||||||
|
}
|
||||||
|
|
||||||
|
function onButtonClick(){ /* todo dislike button function necessary? */
|
||||||
|
console.log("Liked " + count + " times")
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="post">
|
||||||
|
<Stack direction="row">
|
||||||
|
<Stack className="postAvatarContainer">
|
||||||
|
<Avatar src={pic}/>
|
||||||
|
</Stack>
|
||||||
|
<Stack className="postUserName">
|
||||||
|
{userName}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
<Stack className="postBody">
|
||||||
|
{postBody}
|
||||||
|
</Stack>
|
||||||
|
<Stack className="postFooterContainer" direction="row">
|
||||||
|
<Stack className="postFooterLikeDislike" direction="row">
|
||||||
|
<IconButton
|
||||||
|
onClick={() => setCount(count + 1)}
|
||||||
|
>
|
||||||
|
<ThumbUp/>
|
||||||
|
</IconButton><Typography>{count}</Typography>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {/* TODO remove unnecessary arrow function*/
|
||||||
|
onButtonClick()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThumbDown/>
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
<Stack className="postFooterRepost" direction="row">
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {/* TODO remove unnecessary arrow function*/
|
||||||
|
onButtonClick()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Autorenew/>
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Post;
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
.postPlaceholder {
|
||||||
|
width: 39rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postPlaceholderContainer {
|
||||||
|
min-width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postPlaceholderInputBoxContainer {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.postPlaceholderAvatar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postPlaceholderTextField {
|
||||||
|
width: 90%;
|
||||||
|
border: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postPlaceholderInputBox {
|
||||||
|
width: auto;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postFeedAccountCircle {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.postPlaceholderButtonStyle {
|
||||||
|
padding: 0.75rem;
|
||||||
|
display: flex;
|
||||||
|
width: auto;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postPlaceholderButton {
|
||||||
|
height: 1.5rem;
|
||||||
|
width: 5rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import "./PostPlaceholder.css"
|
||||||
|
import React from 'react';
|
||||||
|
import {Avatar, Button, Card, Stack, TextField, Typography} from "@mui/material";
|
||||||
|
import pic from "../../images/superalgos.png"
|
||||||
|
|
||||||
|
const PostPlaceholder = () => {
|
||||||
|
|
||||||
|
function onButtonClick() {
|
||||||
|
console.log("Clicked Post button");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="postPlaceholder">
|
||||||
|
<h4>Posts</h4>
|
||||||
|
<div className="postPlaceholderContainer">
|
||||||
|
<Card>
|
||||||
|
<Stack
|
||||||
|
className="postPlaceholderInputBox"
|
||||||
|
direction="row"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
alignItems="center"
|
||||||
|
spacing={1}
|
||||||
|
justify="flex-end">
|
||||||
|
<Stack className="postPlaceholderAvatar">
|
||||||
|
<Avatar src={pic}/>
|
||||||
|
</Stack>
|
||||||
|
<Stack className="postPlaceholderTextField">
|
||||||
|
<Typography gutterBottom variant="subtitle1" component="div">
|
||||||
|
<TextField
|
||||||
|
id="outlined-multiline-flexible"
|
||||||
|
label="what's happening?"
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
maxRows={6}
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
<Stack className="postPlaceholderButtonStyle" direction="row">
|
||||||
|
<Button
|
||||||
|
onClick={() => { /* TODO remove unnecessary arrow function call*/
|
||||||
|
onButtonClick()
|
||||||
|
}}
|
||||||
|
className="postPlaceholderButton" variant="outlined">
|
||||||
|
Post
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PostPlaceholder;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.postFeedContainer {
|
||||||
|
max-width: 39rem;
|
||||||
|
padding: 0.5rem ;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import './PostsFeed.css';
|
||||||
|
import React from 'react';
|
||||||
|
import {Stack} from "@mui/material";
|
||||||
|
import Post from "../post/Post";
|
||||||
|
|
||||||
|
const PostsFeed = () => {
|
||||||
|
const postFeed = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
const posts = postFeed.map(
|
||||||
|
value => {
|
||||||
|
return <Post key={value} id={value} name={`user${value}`}/>
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="postFeedContainer">
|
||||||
|
<Stack direction="column"
|
||||||
|
spacing={2}>
|
||||||
|
{posts}
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PostsFeed;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.searchIcon {
|
||||||
|
margin: 1rem 0.5rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Box, TextField} from "@mui/material";
|
||||||
|
import {Search} from "@mui/icons-material";
|
||||||
|
|
||||||
|
const SearchBox = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Box sx={{display: 'flex', alignItems: 'flex-end'}}>
|
||||||
|
<Search className="searchIcon"/>
|
||||||
|
<TextField id="users-search" label="Search" variant="standard" type="search"/>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchBox;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Link} from "@mui/material";
|
||||||
|
|
||||||
|
const ShowMoreUsers = ({showMoreCallback}) => {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
component="button"
|
||||||
|
variant="body2"
|
||||||
|
onClick={showMoreCallback}>
|
||||||
|
Show more
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default ShowMoreUsers;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.sidebar{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import './Sidebar.css';
|
||||||
|
import {Divider, Stack} from "@mui/material";
|
||||||
|
import SidebarItem from "../sidebarItem/SidebarItem";
|
||||||
|
import Logo from "../logo/Logo";
|
||||||
|
import HomeIcon from '@mui/icons-material/Home';
|
||||||
|
import PostAddIcon from '@mui/icons-material/PostAdd';
|
||||||
|
import PersonIcon from '@mui/icons-material/Person';
|
||||||
|
|
||||||
|
const Sidebar = props => {
|
||||||
|
const menuOptions = [{name: "Home", icon: HomeIcon},
|
||||||
|
{name: "Profile", icon: PersonIcon},
|
||||||
|
{name: "Post", icon: PostAddIcon}
|
||||||
|
/*, "Explore", "Notifications", "Messages", "Bookmarks", "Lists", "More"*/]
|
||||||
|
|
||||||
|
const menuItems = menuOptions.map(option => {
|
||||||
|
return <SidebarItem key={option.name} Icon={option.icon} value={option.name}/>
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="sidebar">
|
||||||
|
<Stack direction="column"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
alignItems="center"
|
||||||
|
spacing={5}
|
||||||
|
sx={{minWidth: "max-content"}}>
|
||||||
|
<Logo/>
|
||||||
|
<Stack
|
||||||
|
direction="column"
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
spacing={2}
|
||||||
|
divider={<Divider orientation="horizontal" flexItem/>}>
|
||||||
|
{menuItems}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Sidebar;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
.sidebarItem {
|
||||||
|
/*TODO add on hover*/
|
||||||
|
/*TODO add breakpoints*/
|
||||||
|
width: 15vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sidebarText {
|
||||||
|
/*TODO hide when too small*/
|
||||||
|
|
||||||
|
width: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarIcon {
|
||||||
|
width: auto;
|
||||||
|
padding: 0 1rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import './SidebarItem.css';
|
||||||
|
import {Stack} from "@mui/material";
|
||||||
|
import {useNavigate} from "react-router-dom";
|
||||||
|
|
||||||
|
|
||||||
|
const SidebarItem = ({value, Icon}) => {
|
||||||
|
let navigate = useNavigate();
|
||||||
|
const handleClick = () => {
|
||||||
|
navigate(`/${value}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="sidebarItem" onClick={handleClick}>
|
||||||
|
<Stack direction="row">
|
||||||
|
<Icon className="sidebarIcon"/>
|
||||||
|
<div className="sidebarText"> {value} </div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SidebarItem;
|
||||||
Whitespace-only changes.
@@ -0,0 +1,32 @@
|
|||||||
|
import "./SuggestedUsers.css"
|
||||||
|
import React, {useEffect} from 'react';
|
||||||
|
import UserCard from "../User/UserCard";
|
||||||
|
import ShowMoreUsers from "../showMoreUsers/ShowMoreUsers";
|
||||||
|
import {Stack} from "@mui/material";
|
||||||
|
|
||||||
|
|
||||||
|
const SuggestedUsers = ({showMoreCallback}) => {
|
||||||
|
const usersIds = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
|
||||||
|
const users = usersIds.map(value => {
|
||||||
|
let callBack = () => console.log(`Clicked follow on user${value}`);
|
||||||
|
return <UserCard key={value} id={value} name={`user${value}`} followCallback={callBack}/>
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("SuggestedUsersConstructor called")
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack direction="column"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
alignItems="center"
|
||||||
|
spacing={1}>
|
||||||
|
{users}
|
||||||
|
<ShowMoreUsers showMoreCallback={showMoreCallback}/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default SuggestedUsers;
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
.userSection {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
height: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileAvatar {
|
||||||
|
height: 7rem !important;
|
||||||
|
width: 7rem !important;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profilePicBG {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: none no-repeat scroll 0 0 #fff;
|
||||||
|
position: relative;
|
||||||
|
height: 8rem !important;
|
||||||
|
width: 8rem !important;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileCard {
|
||||||
|
margin-top: -50px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileSection {
|
||||||
|
width: 100%;
|
||||||
|
overflow: initial !important; /* TODO check this is needed */
|
||||||
|
height: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.middleSection {
|
||||||
|
width: 39rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import "./UserProfile.css"
|
||||||
|
import React from 'react';
|
||||||
|
import UserProfileHeader from "../userProfileHeader/UserProfileHeader";
|
||||||
|
import {Stack} from "@mui/material";
|
||||||
|
import PostsFeed from "../postsFeed/PostsFeed";
|
||||||
|
|
||||||
|
|
||||||
|
const UserProfile = () => {
|
||||||
|
|
||||||
|
/*TODO finish this shit*/
|
||||||
|
|
||||||
|
let actualUser = 'Loui Molina';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack direction="column"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
alignItems="center"
|
||||||
|
spacing={1}
|
||||||
|
className="middleSection">
|
||||||
|
|
||||||
|
<UserProfileHeader actualUser={actualUser}/>
|
||||||
|
<PostsFeed/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default UserProfile;
|
||||||
Whitespace-only changes.
@@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Card, CardContent, CardMedia, Typography} from "@mui/material";
|
||||||
|
import banner from "../../images/banner.jpg";
|
||||||
|
import pfp from "../../images/superalgos.png";
|
||||||
|
|
||||||
|
const UserProfileHeader = ({actualUser}) => {
|
||||||
|
return (
|
||||||
|
<Card className="profileSection">
|
||||||
|
<CardMedia className="banner"
|
||||||
|
component="img"
|
||||||
|
image={banner}
|
||||||
|
alt="PP"
|
||||||
|
/>
|
||||||
|
<div className="profileCard">
|
||||||
|
<div className="profilePicBG">
|
||||||
|
<CardMedia className="profileAvatar"
|
||||||
|
component="img"
|
||||||
|
image={pfp}
|
||||||
|
alt="ProfilePic"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<CardContent className="userSection">
|
||||||
|
<Typography variant="h5">{actualUser}</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserProfileHeader;
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 6.3 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
body {
|
||||||
|
margin: 2.5vh 5vw;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
height: 95vh !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
height: inherit;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import './index.css';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import {Provider} from "react-redux";
|
||||||
|
import reducers from "./store";
|
||||||
|
import Root from "./components/Root";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<Provider store={reducers}>
|
||||||
|
<Root/>
|
||||||
|
</Provider>
|
||||||
|
</React.StrictMode>,
|
||||||
|
document.getElementById('root')
|
||||||
|
);
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Saira';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Saira Light'), local('Saira-Light'), url(Fonts/Saira.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Saira Condensed';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Saira Condensed Light'), local('SairaCondensed-Light'), url(Fonts/Saira-Condensed.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: segoeui;
|
||||||
|
src: url(Fonts/segoeui.woff) format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body{
|
||||||
|
overflow-y: hidden;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-div {
|
||||||
|
position:absolute;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
top:0px;
|
||||||
|
left:0px;
|
||||||
|
vertical-align: top;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
color: #000;
|
||||||
|
border-color: blue;
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.static-div {
|
||||||
|
position: fixed;
|
||||||
|
top:0px;
|
||||||
|
left:18%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
background:transparent;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-div {
|
||||||
|
position:relative;
|
||||||
|
vertical-align: top;
|
||||||
|
height: 100%;
|
||||||
|
width: 30%;
|
||||||
|
left: 31.2%;
|
||||||
|
color: #000;
|
||||||
|
border-color: blue;
|
||||||
|
background-color:transparent;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-placeholder {
|
||||||
|
vertical-align: top;
|
||||||
|
height: 50px;
|
||||||
|
width: 100%;
|
||||||
|
color: #000;
|
||||||
|
border-color: blue;
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-div {
|
||||||
|
vertical-align: top;
|
||||||
|
height: 300px;
|
||||||
|
width: 100%;
|
||||||
|
color: #000;
|
||||||
|
border-color: blue;
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-post-div {
|
||||||
|
vertical-align: top;
|
||||||
|
height: 300px;
|
||||||
|
width: 100%;
|
||||||
|
color: #000;
|
||||||
|
border-color: blue;
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-table {
|
||||||
|
top:0px;
|
||||||
|
left:18%;
|
||||||
|
width: 64%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
background:transparent;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-column {
|
||||||
|
position:relative;
|
||||||
|
top:0px;
|
||||||
|
width: 20%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.middle-column {
|
||||||
|
position:relative;
|
||||||
|
top:0px;
|
||||||
|
width: 50%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-column {
|
||||||
|
position:relative;
|
||||||
|
top:0px;
|
||||||
|
left:0px;
|
||||||
|
width: 30%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-table {
|
||||||
|
position:relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-cell {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
height: 70px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-cell {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-cell {
|
||||||
|
vertical-align: bottom;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.middle-table {
|
||||||
|
position:relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-title-cell {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-cell {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-table {
|
||||||
|
position:relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-cell {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-cell {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
background:transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-table {
|
||||||
|
position:relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 65%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item-cell {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.who-to-follow-table {
|
||||||
|
position:relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 30%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-to-follow-table {
|
||||||
|
position:relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 30%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #000;
|
||||||
|
border-width: 0px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-to-follow-span {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-to-follow-button {
|
||||||
|
float: right;
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-to-unfollow-span {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-to-unfollow-button {
|
||||||
|
float: right;
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
const reportWebVitals = onPerfEntry => {
|
||||||
|
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||||
|
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||||
|
getCLS(onPerfEntry);
|
||||||
|
getFID(onPerfEntry);
|
||||||
|
getFCP(onPerfEntry);
|
||||||
|
getLCP(onPerfEntry);
|
||||||
|
getTTFB(onPerfEntry);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default reportWebVitals;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
import ExampleReducer from './slices/Globals'
|
||||||
|
|
||||||
|
export default configureStore({
|
||||||
|
reducer:{
|
||||||
|
example: ExampleReducer
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import {createSlice} from '@reduxjs/toolkit'
|
||||||
|
|
||||||
|
export const Globals = createSlice({
|
||||||
|
name: 'globals',
|
||||||
|
initialState: {
|
||||||
|
UI: {
|
||||||
|
projects: {},
|
||||||
|
schemas: {projectSchema: undefined},
|
||||||
|
environment: undefined,
|
||||||
|
clientNode: undefined,
|
||||||
|
webApp: undefined
|
||||||
|
},
|
||||||
|
SA: {projects: {}}
|
||||||
|
},
|
||||||
|
reducers: {
|
||||||
|
exampleAction: (state, action) => {
|
||||||
|
state.userName = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Action creators are generated for each case reducer function
|
||||||
|
export const {exampleAction} = Globals.actions
|
||||||
|
|
||||||
|
export default Globals.reducer
|
||||||
|
|
||||||
|
|
||||||
+9
-1
@@ -58,13 +58,21 @@ exports.newDesktopRoot = function newDesktopRoot() {
|
|||||||
/*
|
/*
|
||||||
Setting up Secrets.
|
Setting up Secrets.
|
||||||
*/
|
*/
|
||||||
|
try {
|
||||||
SA.secrets = {
|
SA.secrets = {
|
||||||
array: require('./My-Secrets/Secrets.json').secrets,
|
array: require('./My-Secrets/Secrets.json').secrets,
|
||||||
map: new Map()
|
map: new Map()
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
SA.secrets = {
|
||||||
|
array: [],
|
||||||
|
map: new Map()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < SA.secrets.array.length; i++) {
|
for (let i = 0; i < SA.secrets.array.length; i++) {
|
||||||
let secret = SA.secrets.array[i]
|
let secret = SA.secrets.array[i]
|
||||||
SA.secrets.map.set (secret.signingAccountChildCodeName, secret)
|
SA.secrets.map.set(secret.nodeCodeName, secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
run()
|
run()
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
exports.newDesktopRoot = function newDesktopRoot() {
|
||||||
|
/*
|
||||||
|
This module represents the execution root of the Desktop App.
|
||||||
|
We use this module that is outside the Desktop folder to
|
||||||
|
load all node dependencies and get them ready to the actual App.
|
||||||
|
*/
|
||||||
|
let thisObject = {
|
||||||
|
run: run
|
||||||
|
}
|
||||||
|
|
||||||
|
return thisObject
|
||||||
|
|
||||||
|
async function run(debugSettings) {
|
||||||
|
/*
|
||||||
|
The DK object is accessible everywhere at the Superalgos Desktop App.
|
||||||
|
It provides access to all modules built for this App.
|
||||||
|
*/
|
||||||
|
global.DK = {}
|
||||||
|
/*
|
||||||
|
The SA object is accessible everywhere at the Superalgos Desktop App.
|
||||||
|
It provides access to all modules built for Superalgos in general.
|
||||||
|
*/
|
||||||
|
global.SA = {}
|
||||||
|
/* Load Environment Variables */
|
||||||
|
let ENVIRONMENT = require('./Environment.js');
|
||||||
|
let ENVIRONMENT_MODULE = ENVIRONMENT.newEnvironment()
|
||||||
|
global.env = ENVIRONMENT_MODULE
|
||||||
|
|
||||||
|
if (debugSettings !== undefined && debugSettings.DESKTOP_APP_SIGNING_ACCOUNT !== undefined) {
|
||||||
|
global.env.DESKTOP_APP_SIGNING_ACCOUNT = debugSettings.DESKTOP_APP_SIGNING_ACCOUNT
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
First thing is to load the project schema file.
|
||||||
|
*/
|
||||||
|
global.PROJECTS_SCHEMA = require(global.env.PATH_TO_PROJECT_SCHEMA)
|
||||||
|
/*
|
||||||
|
Setting up the modules that will be available, defined at the Project Schema file.
|
||||||
|
*/
|
||||||
|
let MULTI_PROJECT = require('./MultiProject.js');
|
||||||
|
let MULTI_PROJECT_MODULE = MULTI_PROJECT.newMultiProject()
|
||||||
|
MULTI_PROJECT_MODULE.initialize(DK, 'DK')
|
||||||
|
MULTI_PROJECT_MODULE.initialize(SA, 'SA')
|
||||||
|
/*
|
||||||
|
Setting up external dependencies.
|
||||||
|
*/
|
||||||
|
SA.nodeModules = {
|
||||||
|
fs: require('fs'),
|
||||||
|
util: require('util'),
|
||||||
|
path: require('path'),
|
||||||
|
web3: require('web3'),
|
||||||
|
ws: require('ws'),
|
||||||
|
open: require('open'),
|
||||||
|
http: require('http'),
|
||||||
|
octokit: require("@octokit/rest"),
|
||||||
|
simpleGit: require('simple-git'),
|
||||||
|
nodeFetch: require('node-fetch')
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Setting up Secrets.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
SA.secrets = {
|
||||||
|
array: require('./My-Secrets/Secrets.json').secrets,
|
||||||
|
map: new Map()
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
SA.secrets = {
|
||||||
|
array: [],
|
||||||
|
map: new Map()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < SA.secrets.array.length; i++) {
|
||||||
|
let secret = SA.secrets.array[i]
|
||||||
|
SA.secrets.map.set(secret.nodeCodeName, secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
run()
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
DK.app = require('./DesktopReact/DesktopApp.js').newDesktopApp()
|
||||||
|
await DK.app.run()
|
||||||
|
console.log('Superalgos Desktop App is Running!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -3,7 +3,7 @@ WORKDIR /app
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN apk add --no-cache --virtual .build-deps make g++ \
|
RUN apk add --no-cache --virtual .build-deps make g++ \
|
||||||
&& apk add --no-cache python3 \
|
&& apk add --no-cache python3 \
|
||||||
&& if [ "$(uname -m)" = "x86_64" ]; then node setup noShortcuts tensorflow; else node setup noShortcuts; fi \
|
&& npm ci \
|
||||||
&& mkdir -p ./Platform/My-Data-Storage ./Platform/My-Log-Files ./Platform/My-Workspaces \
|
&& mkdir -p ./Platform/My-Data-Storage ./Platform/My-Log-Files ./Platform/My-Workspaces \
|
||||||
&& addgroup superalgos \
|
&& addgroup superalgos \
|
||||||
&& adduser --disabled-password --no-create-home --ingroup superalgos superalgos \
|
&& adduser --disabled-password --no-create-home --ingroup superalgos superalgos \
|
||||||
|
|||||||
+6
-2
@@ -9,6 +9,7 @@ exports.newEnvironment = function () {
|
|||||||
|
|
||||||
let thisObject = {
|
let thisObject = {
|
||||||
DEMO_MODE: false,
|
DEMO_MODE: false,
|
||||||
|
DEMO_MODE_HOST: "super-super-uzzdd68dwm9w-22a320db4ede63aa.elb.us-east-2.amazonaws.com",
|
||||||
BASE_PATH: basePath,
|
BASE_PATH: basePath,
|
||||||
WEB_SERVER_URL: 'localhost',
|
WEB_SERVER_URL: 'localhost',
|
||||||
PLATFORM_WEB_SOCKETS_INTERFACE_PORT: 18041,
|
PLATFORM_WEB_SOCKETS_INTERFACE_PORT: 18041,
|
||||||
@@ -27,16 +28,19 @@ exports.newEnvironment = function () {
|
|||||||
PATH_TO_DESKTOP: './Desktop',
|
PATH_TO_DESKTOP: './Desktop',
|
||||||
PATH_TO_DEFAULT_WORKSPACE: path.join(basePath, './Projects/Foundations/Plugins/Workspaces'),
|
PATH_TO_DEFAULT_WORKSPACE: path.join(basePath, './Projects/Foundations/Plugins/Workspaces'),
|
||||||
PATH_TO_MY_WORKSPACES: path.join(basePath, './Platform/My-Workspaces'),
|
PATH_TO_MY_WORKSPACES: path.join(basePath, './Platform/My-Workspaces'),
|
||||||
|
PATH_TO_SECRETS: path.join(basePath, './My-Secrets'),
|
||||||
PATH_TO_FONTS: path.join(basePath, './Platform/WebServer/Fonts'),
|
PATH_TO_FONTS: path.join(basePath, './Platform/WebServer/Fonts'),
|
||||||
DESKTOP_APP_SIGNING_ACCOUNT: 'Social-Trading-Desktop-App-1',
|
DESKTOP_APP_SIGNING_ACCOUNT: 'Social-Trading-Desktop-App-1',
|
||||||
DESKTOP_APP_MAX_OUTGOING_PEERS: 1,
|
DESKTOP_APP_MAX_OUTGOING_PEERS: 1,
|
||||||
|
TASK_SERVER_APP_MAX_OUTGOING_PEERS: 1,
|
||||||
|
TASK_SERVER_APP_MAX_OUTGOING_HEADS: 1,
|
||||||
MOBILE_APP_SIGNING_ACCOUNT: 'Social-Trading-Mobile-App-1',
|
MOBILE_APP_SIGNING_ACCOUNT: 'Social-Trading-Mobile-App-1',
|
||||||
SERVER_APP_SIGNING_ACCOUNT: 'Social-Trading-Server-App-1',
|
SERVER_APP_SIGNING_ACCOUNT: 'Social-Trading-Server-App-1',
|
||||||
PLATFORM_APP_SIGNING_ACCOUNT: 'Algo-Traders-Platform-1',
|
PLATFORM_APP_SIGNING_ACCOUNT: 'Algo-Traders-Platform-1',
|
||||||
P2P_NETWORK_NODE_SIGNING_ACCOUNT: 'P2P-Network-Node-1',
|
P2P_NETWORK_NODE_SIGNING_ACCOUNT: 'P2P-Network-Node-1',
|
||||||
P2P_NETWORK_NODE_MAX_INCOMING_CLIENTS: 1,
|
P2P_NETWORK_NODE_MAX_INCOMING_CLIENTS: 1,
|
||||||
P2P_NETWORK_NODE_MAX_INCOMING_PEERS: 2,
|
P2P_NETWORK_NODE_MAX_INCOMING_PEERS: 0,
|
||||||
P2P_NETWORK_NODE_MAX_OUTGOING_PEERS: 2
|
P2P_NETWORK_NODE_MAX_OUTGOING_PEERS: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.DATA_PATH) {
|
if (process.env.DATA_PATH) {
|
||||||
|
|||||||
@@ -94,9 +94,9 @@ if (os.platform() == "win32") {
|
|||||||
} else if (os.platform() == "darwin") {
|
} else if (os.platform() == "darwin") {
|
||||||
const icon = path.join( __dirname,"/superalgos.ico");
|
const icon = path.join( __dirname,"/superalgos.ico");
|
||||||
const createShortcutCommand = `chmod +x ${name}.command & cp ${name}.command ~/Desktop/${name}.command`
|
const createShortcutCommand = `chmod +x ${name}.command & cp ${name}.command ~/Desktop/${name}.command`
|
||||||
const installFileIconcommand = `npm install fileicon`;
|
const installFileIconcommand = `npm install -g fileicon`;
|
||||||
const changeIconCommand = `./node_modules/fileicon/bin/fileicon set ~/Desktop/${name}.command ./Launch-Scripts/superalgos.ico`
|
const changeIconCommand = `./node_modules/fileicon/bin/fileicon set ~/Desktop/${name}.command ./Launch-Scripts/superalgos.ico`
|
||||||
const unInstallFileIconcommand = `npm uninstall fileicon`;
|
const unInstallFileIconcommand = `npm uninstall -g fileicon`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create .desktop shortcut file
|
// Create .desktop shortcut file
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
exports.newMultiProject = function () {
|
exports.newMultiProject = function () {
|
||||||
|
/* TODO add init method to DK*/
|
||||||
let thisObject = {
|
let thisObject = {
|
||||||
initialize: initialize
|
initialize: initialize
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ exports.newNetworkNode = function newNetworkNode() {
|
|||||||
thisObject.socialGraphService = NT.projects.socialTrading.modules.socialGraph.newNetworkModulesSocialGraph()
|
thisObject.socialGraphService = NT.projects.socialTrading.modules.socialGraph.newNetworkModulesSocialGraph()
|
||||||
await thisObject.socialGraphService.initialize()
|
await thisObject.socialGraphService.initialize()
|
||||||
/*
|
/*
|
||||||
The Sotrage deals with persisting the Social Graph.
|
The Storage deals with persisting the Social Graph.
|
||||||
*/
|
*/
|
||||||
thisObject.storage = NT.projects.socialTrading.modules.storage.newSocialTradingModulesStorage()
|
thisObject.storage = NT.projects.socialTrading.modules.storage.newSocialTradingModulesStorage()
|
||||||
thisObject.storage.initialize()
|
thisObject.storage.initialize()
|
||||||
|
|||||||
+9
-1
@@ -56,13 +56,21 @@ exports.newNetworkRoot = function newNetworkRoot() {
|
|||||||
/*
|
/*
|
||||||
Setting up Secrets.
|
Setting up Secrets.
|
||||||
*/
|
*/
|
||||||
|
try {
|
||||||
SA.secrets = {
|
SA.secrets = {
|
||||||
array: require('./My-Secrets/Secrets.json').secrets,
|
array: require('./My-Secrets/Secrets.json').secrets,
|
||||||
map: new Map()
|
map: new Map()
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
SA.secrets = {
|
||||||
|
array: [],
|
||||||
|
map: new Map()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < SA.secrets.array.length; i++) {
|
for (let i = 0; i < SA.secrets.array.length; i++) {
|
||||||
let secret = SA.secrets.array[i]
|
let secret = SA.secrets.array[i]
|
||||||
SA.secrets.map.set(secret.signingAccountChildCodeName, secret)
|
SA.secrets.map.set(secret.nodeCodeName, secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
NT.app = require('./Network/NetwokNode.js').newNetworkNode()
|
NT.app = require('./Network/NetwokNode.js').newNetworkNode()
|
||||||
|
|||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
----- Changes made outside of /Projects/Portfolio-Management/ -----
|
||||||
|
|
||||||
|
Projects/ProjectsSchema.json:
|
||||||
|
cp Algorithmic-Trading Portfolio-Management - Some stuff definitely unneded here
|
||||||
|
|
||||||
|
Projects/Community-Plugins/UI/Function-Libraries/
|
||||||
|
ActionSwitch.js:
|
||||||
|
cp case 'Add Missing Plugin Trading Mines' case 'Add Missing Plugin Portfolio Mines'
|
||||||
|
cp case 'Add Missing Plugin Trading Systems' case 'Add Missing Plugin Portfolio Systems'
|
||||||
|
cp case 'Add Missing Plugin Trading Engines' case 'Add Missing Plugin Portfolio Engines'
|
||||||
|
|
||||||
|
PluginsFunctions.js:
|
||||||
|
cp addMissingPluginTradingMines addMissingPluginPortfolioMines
|
||||||
|
cp addMissingPluginTradingSystems addMissingPluginPortfolioSystems
|
||||||
|
cp addMissingPluginTradingEngines addMissingPluginPortfolioEngines
|
||||||
|
|
||||||
|
../Utilities/Plugins.js:
|
||||||
|
function getPluginFolderNamesByNodeType(nodeType):
|
||||||
|
add case 'Portfolio Engine'
|
||||||
|
add case 'Portfolio Mine'
|
||||||
|
add case 'Portfolio System'
|
||||||
|
|
||||||
|
Projects/Data-Mining/UI/Function-Libraries/
|
||||||
|
MineFunctions.js:
|
||||||
|
cp scanBotArray(dataMine.tradingBots) scanBotArray(dataMine.portfolioBots)
|
||||||
|
|
||||||
|
Skipping:
|
||||||
|
Projects/Foundations/TS/Function-Libraries/OutputManagementFunctions.js:
|
||||||
|
tradingProcessDate, VARS...INDEX_MAP->TRADING_PROCESSING_DAILY_FILES, ...
|
||||||
|
|
||||||
|
|
||||||
|
Projects/Foundations/TS/Function-Libraries/
|
||||||
|
SingleMarketFunctions.js:
|
||||||
|
cp findNodeInNodeMesh(outputDatasetNode, 'Trading Bot') ...'Portfolio Bot')
|
||||||
|
Line 117 if...else add portfolioMineNode
|
||||||
|
|
||||||
|
Projects/Foundations/TS/Process-Modules/
|
||||||
|
Dataset.js:
|
||||||
|
cp startingNode.type === 'Market Trading Products'
|
||||||
|
ProcessOutput.js:
|
||||||
|
cp line 27-29, 124-126
|
||||||
|
StatusReport.js:
|
||||||
|
Lines 102, 116, cp 172-222 dealing with finding process definitions the report depends on has been cloned from Trading -> Portfolio
|
||||||
|
|
||||||
|
Projects/Foundations/UI/Function-Libraries/
|
||||||
|
ActionSwitch.js:
|
||||||
|
cp case statements run-all, stop-all, add-missing, references, products, etc.
|
||||||
|
Line 506 && 512 may not need to have been cloned but I did for now - regarding live and paper trading.
|
||||||
|
ChartingSpaceFunctions.js: Needs Completion to include Portfolio at Charting Space.
|
||||||
|
'Market Trading|Portfolio Tasks' -> 'nodeType' as param. <= If error arises note that it was not configured this way by Luis when adding the Learning Mine. This is a File that could be heavily re-factored && optimized.
|
||||||
|
ProductFunctions.js:
|
||||||
|
|
||||||
|
Skipping:
|
||||||
|
Projects/Foundations/UI/Function-Libraries/ChartingSpaceFunctions.js: Needs Completion
|
||||||
|
Projects/Foundations/UI/Function-Libraries/CryptoEcosystemFunctions.js
|
||||||
|
|
||||||
|
Projects/Foundations/UI/Function-Libraries/
|
||||||
|
DataStorageFunctions.js:
|
||||||
|
Many things cloned. But on line 156 only did 'addMissingSession(livePortfolioSessionArray) not back|forward|paper
|
||||||
|
TaskFunctions.js:
|
||||||
|
run/stop | addMissing - Portfolio Tasks. Project|Exchange|Market|Mine
|
||||||
|
Line 148 - Only cloned 'Live Portfolio Session->'
|
||||||
|
Line 198 - Only cloned 'Production Portfolio Tasks->'
|
||||||
|
|
||||||
|
Skipping:
|
||||||
|
Projects/Foundations/UI/Function-Libraries/DependenciesFilter.js:
|
||||||
|
Appears 'tradingSystem' var here is just a parameter so no need change.
|
||||||
|
|
||||||
|
Projects/Foundations/UI/Spaces/
|
||||||
|
/Charting-Space/PlottersManager.js:
|
||||||
|
/Plotting/RecordValues.js:
|
||||||
|
/Design-Space/Workspace.js:
|
||||||
|
/Floating-Space/FloatingSpace.js:
|
||||||
|
/Panel-Space/Layer.js: Line 173 Only 'Live Portfolio Session'
|
||||||
|
|
||||||
|
Projects/Visual-Scripting/UI/Function-Libraries/
|
||||||
|
<<<<<<< Updated upstream
|
||||||
|
ActionsSwitch.js: *** NOTE: Not sure how to handle line 14 at the current moment. ***
|
||||||
|
UiObjectsFromNodes.js: only if(uiObjectType === 'Live Portfolio Session')
|
||||||
|
=======
|
||||||
|
ActionsSwitch.js:
|
||||||
|
NodePath.js*** NOTE: Not sure how to handle line 14 at the current moment. ***
|
||||||
|
UIObjectsFromNodes.js: Line 977 'Live Portfolio Session' only.
|
||||||
|
>>>>>>> Stashed changes
|
||||||
|
|
||||||
|
Skipping:
|
||||||
|
Projects/Foundations/UI/Spaces/Floating-Space/ConditionEditor.js
|
||||||
|
|
||||||
|
Skipping:
|
||||||
|
Projects/Governance/UI/Function-Libraries/ActionSwitch.js:
|
||||||
|
Projects/Machine-Learning/TS/Bot-Modules/Learning-Bot/LearningSession.js:
|
||||||
|
Projects/Machine-Learning/TS/Bot-Modules/Learning-Bot/Low-Frequency-Learning/LearningOutput.js:
|
||||||
|
Projects/Machine-Learning/*
|
||||||
|
Projects/Network/*
|
||||||
|
node_modules, */My-Workspaces, */My-Log-Files, *.json, .gitignore, desktop.js, Environment.js, README.md, run.js, setup.js, Tested-Exchanges, CODEOWNERS, DesktopApp.js, WebApp.js, Projects/Social-Bots/*, Projects/Social-Trading/*, Projects/Governance/*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----- Changes made inside Portfolio-Management (Clone of Algorithmic-Trading) -----
|
||||||
|
References to trading changed to portfolio regardless of capitalization:
|
||||||
|
Examples:
|
||||||
|
find ./ -type f -exec sed -i 's/trading/portfolio/g' {} \;
|
||||||
|
find ./ -type f -exec sed -i 's/Trading/Portfolio/g' {} \;
|
||||||
|
find ./ -type f -exec sed -i 's/TRADING/PORTFOLIO/g' {} \;
|
||||||
|
|
||||||
Vendored
+17
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}\\..\\PlatformRoot.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"**/Data-Storage": true,
|
||||||
|
"**/Log-Files": true,
|
||||||
|
"**/node_modules": true,
|
||||||
|
"**/My-Social-Trading-Data": true,
|
||||||
|
"**/My-Network-Nodes-Data": true,
|
||||||
|
"**/My-Workspaces": true,
|
||||||
|
"**/My-Secrets": true,
|
||||||
|
"**/My-Data-Storage": true,
|
||||||
|
"**/My-Log-Files": true,
|
||||||
|
},
|
||||||
|
"search.exclude": {
|
||||||
|
"**/Data-Storage": true,
|
||||||
|
"**/Log-Files": true,
|
||||||
|
"**/node_modules": true,
|
||||||
|
"**/My-Social-Trading-Data": true,
|
||||||
|
"**/My-Network-Nodes-Data": true,
|
||||||
|
"**/My-Workspaces": true,
|
||||||
|
"**/My-Secrets": true,
|
||||||
|
"**/My-Data-Storage": true,
|
||||||
|
"**/My-Log-Files": true,
|
||||||
|
},
|
||||||
|
"search.maintainFileSearchCache": true,
|
||||||
|
"editor.mouseWheelZoom": true
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ exports.newGithubServer = function newGithubServer() {
|
|||||||
getGithubStars: getGithubStars,
|
getGithubStars: getGithubStars,
|
||||||
getGithubWatchers: getGithubWatchers,
|
getGithubWatchers: getGithubWatchers,
|
||||||
getGithubForks: getGithubForks,
|
getGithubForks: getGithubForks,
|
||||||
|
createGithubFork: createGithubFork,
|
||||||
mergePullRequests: mergePullRequests,
|
mergePullRequests: mergePullRequests,
|
||||||
initialize: initialize,
|
initialize: initialize,
|
||||||
finalize: finalize,
|
finalize: finalize,
|
||||||
@@ -162,6 +163,46 @@ exports.newGithubServer = function newGithubServer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createGithubFork(token) {
|
||||||
|
try {
|
||||||
|
token = unescape(token)
|
||||||
|
|
||||||
|
await doGithub()
|
||||||
|
|
||||||
|
async function doGithub() {
|
||||||
|
try {
|
||||||
|
const { Octokit } = SA.nodeModules.octokit
|
||||||
|
const octokit = new Octokit({
|
||||||
|
auth: token,
|
||||||
|
userAgent: 'Superalgos ' + SA.version
|
||||||
|
})
|
||||||
|
|
||||||
|
await octokit.repos.createFork({
|
||||||
|
owner: 'Superalgos',
|
||||||
|
repo: 'Superalgos'
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
if (err === undefined) { return }
|
||||||
|
console.log('[ERROR] Github Server -> createGithubFork -> doGithub -> err.stack = ' + err.stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[ERROR] Github Server -> createGithubFork -> Method call produced an error.')
|
||||||
|
console.log('[ERROR] Github Server -> createGithubFork -> err.stack = ' + err.stack)
|
||||||
|
console.log('[ERROR] Github Server -> createGithubFork -> repository = ' + repository)
|
||||||
|
console.log('[ERROR] Github Server -> createGithubFork -> username = ' + username)
|
||||||
|
console.log('[ERROR] Github Server -> createGithubFork -> token starts with = ' + token.substring(0, 10) + '...')
|
||||||
|
console.log('[ERROR] Github Server -> createGithubFork -> token ends with = ' + '...' + token.substring(token.length - 10))
|
||||||
|
|
||||||
|
let error = {
|
||||||
|
result: 'Fail Because',
|
||||||
|
message: err.message,
|
||||||
|
stack: err.stack
|
||||||
|
}
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function mergeGithubPullRequests(commitMessage, username, token) {
|
async function mergeGithubPullRequests(commitMessage, username, token) {
|
||||||
try {
|
try {
|
||||||
commitMessage = unescape(commitMessage)
|
commitMessage = unescape(commitMessage)
|
||||||
@@ -169,7 +210,7 @@ exports.newGithubServer = function newGithubServer() {
|
|||||||
token = unescape(token)
|
token = unescape(token)
|
||||||
const repository = 'Superalgos'
|
const repository = 'Superalgos'
|
||||||
|
|
||||||
/* Unsavping # */
|
/* Unsaving # */
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
commitMessage = commitMessage.replace('_SLASH_', '/')
|
commitMessage = commitMessage.replace('_SLASH_', '/')
|
||||||
commitMessage = commitMessage.replace('_HASHTAG_', '#')
|
commitMessage = commitMessage.replace('_HASHTAG_', '#')
|
||||||
@@ -284,13 +325,30 @@ exports.newGithubServer = function newGithubServer() {
|
|||||||
/*
|
/*
|
||||||
Lets get the files changed at this Pull Request.
|
Lets get the files changed at this Pull Request.
|
||||||
*/
|
*/
|
||||||
|
let filesChanged = []
|
||||||
|
const per_page = 100 // Max
|
||||||
|
let page = 0
|
||||||
|
let lastPage = false
|
||||||
|
|
||||||
|
while (lastPage === false) {
|
||||||
|
page++
|
||||||
await PL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
await PL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||||
let listResponse = await octokit.rest.pulls.listFiles({
|
let listResponse = await octokit.rest.pulls.listFiles({
|
||||||
owner: owner,
|
owner: owner,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
pull_number: pullRequest.number
|
pull_number: pullRequest.number,
|
||||||
|
per_page: per_page,
|
||||||
|
page: page
|
||||||
});
|
});
|
||||||
let filesChanged = listResponse.data
|
|
||||||
|
if (listResponse.data.length < 100) {
|
||||||
|
lastPage = true
|
||||||
|
}
|
||||||
|
for (let i = 0; i < listResponse.data.length; i++) {
|
||||||
|
let listItem = listResponse.data[i]
|
||||||
|
filesChanged.push(listItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
let fileContentUrl // URL to the only file at the PR
|
let fileContentUrl // URL to the only file at the PR
|
||||||
let fileContent // File content of the only file at the PR
|
let fileContent // File content of the only file at the PR
|
||||||
let userProfile // User Profile Object
|
let userProfile // User Profile Object
|
||||||
@@ -307,6 +365,11 @@ exports.newGithubServer = function newGithubServer() {
|
|||||||
if (await validateUserProfileBlockchainAccountDoesNotBelongtoAnotherUserProfile() === false) { continue }
|
if (await validateUserProfileBlockchainAccountDoesNotBelongtoAnotherUserProfile() === false) { continue }
|
||||||
if (await validateUserProfileSigningAccountsDoesNotBelongtoAnotherUserProfile() === false) { continue }
|
if (await validateUserProfileSigningAccountsDoesNotBelongtoAnotherUserProfile() === false) { continue }
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: We need to check before merging a User Profile that none of id of the node of the profile hierarchy exists at any other
|
||||||
|
User Profile already at the repository, to avoid attacks of users hijacking references of other user profiles.
|
||||||
|
*/
|
||||||
|
|
||||||
if (await mergePullRequest() === false) {
|
if (await mergePullRequest() === false) {
|
||||||
console.log('[WARN] Github Server -> mergeGithubPullRequests -> Merge Failed -> Pull Request "' + pullRequest.title + '" not merged because Github could not merge it. -> mergeResponse.message = ' + mergeResponse.data.message)
|
console.log('[WARN] Github Server -> mergeGithubPullRequests -> Merge Failed -> Pull Request "' + pullRequest.title + '" not merged because Github could not merge it. -> mergeResponse.message = ' + mergeResponse.data.message)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify({error: 'Method ' + params.method + ' is invalid.'}), httpResponse)
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify({ error: 'Method ' + params.method + ' is invalid.' }), httpResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -325,6 +325,42 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'Secrets': {
|
||||||
|
switch (requestPath[2]) { // switch by command
|
||||||
|
case 'Save-Secrets-File': {
|
||||||
|
SA.projects.foundations.utilities.httpRequests.getRequestBody(httpRequest, httpResponse, processRequest)
|
||||||
|
|
||||||
|
async function processRequest(body) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
let filePath = global.env.PATH_TO_SECRETS + '/'
|
||||||
|
let fileName = "Secrets.json"
|
||||||
|
|
||||||
|
createNewDir(filePath)
|
||||||
|
SA.nodeModules.fs.writeFileSync(filePath + '/' + fileName, body)
|
||||||
|
|
||||||
|
console.log('[SUCCESS] ' + filePath + '/' + fileName + ' created.')
|
||||||
|
|
||||||
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(global.DEFAULT_OK_RESPONSE), httpResponse)
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[ERROR] httpInterface -> Secrets -> Save-Secrets-File -> Method call produced an error.')
|
||||||
|
console.log('[ERROR] httpInterface -> Secrets -> Save-Secrets-File -> err.stack = ' + err.stack)
|
||||||
|
console.log('[ERROR] httpInterface -> Secrets -> Save-Secrets-File -> Params Received = ' + body)
|
||||||
|
|
||||||
|
let error = {
|
||||||
|
result: 'Fail Because',
|
||||||
|
message: err.message,
|
||||||
|
stack: err.stack
|
||||||
|
}
|
||||||
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(error), httpResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
case 'Docs': {
|
case 'Docs': {
|
||||||
switch (requestPath[2]) { // switch by command
|
switch (requestPath[2]) { // switch by command
|
||||||
case 'Save-Node-Schema': {
|
case 'Save-Node-Schema': {
|
||||||
@@ -633,16 +669,6 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewDir(path) {
|
|
||||||
try {
|
|
||||||
fs.mkdirSync(path, {recursive: true})
|
|
||||||
} catch (err) {
|
|
||||||
if (err.message.indexOf('file already exists') < 0) {
|
|
||||||
throw (err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return noErrorsDuringSaving
|
return noErrorsDuringSaving
|
||||||
@@ -697,7 +723,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
contribute()
|
contribute()
|
||||||
|
|
||||||
async function contribute() {
|
async function contribute() {
|
||||||
const {lookpath} = SA.nodeModules.lookpath
|
const { lookpath } = SA.nodeModules.lookpath
|
||||||
const gitpath = await lookpath('git')
|
const gitpath = await lookpath('git')
|
||||||
if (gitpath === undefined) {
|
if (gitpath === undefined) {
|
||||||
console.log('[ERROR] `git` not installed.')
|
console.log('[ERROR] `git` not installed.')
|
||||||
@@ -768,7 +794,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
|
|
||||||
async function doGithub() {
|
async function doGithub() {
|
||||||
|
|
||||||
const {Octokit} = SA.nodeModules.octokit
|
const { Octokit } = SA.nodeModules.octokit
|
||||||
|
|
||||||
const octokit = new Octokit({
|
const octokit = new Octokit({
|
||||||
auth: token,
|
auth: token,
|
||||||
@@ -832,7 +858,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
update()
|
update()
|
||||||
|
|
||||||
async function update() {
|
async function update() {
|
||||||
const {lookpath} = SA.nodeModules.lookpath
|
const { lookpath } = SA.nodeModules.lookpath
|
||||||
const gitpath = await lookpath('git');
|
const gitpath = await lookpath('git');
|
||||||
if (gitpath === undefined) {
|
if (gitpath === undefined) {
|
||||||
console.log('[ERROR] `git` not installed.')
|
console.log('[ERROR] `git` not installed.')
|
||||||
@@ -873,11 +899,11 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
let message
|
let message
|
||||||
try {
|
try {
|
||||||
message = await git.pull('https://github.com/Superalgos/Superalgos', currentBranch)
|
message = await git.pull('https://github.com/Superalgos/Superalgos', currentBranch)
|
||||||
return {message: message}
|
return { message: message }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('[ERROR] Error updating ' + currentBranch)
|
console.log('[ERROR] Error updating ' + currentBranch)
|
||||||
console.log(err.stack)
|
console.log(err.stack)
|
||||||
return {error: err}
|
return { error: err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -903,7 +929,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
checkout()
|
checkout()
|
||||||
|
|
||||||
async function checkout() {
|
async function checkout() {
|
||||||
const {lookpath} = SA.nodeModules.lookpath
|
const { lookpath } = SA.nodeModules.lookpath
|
||||||
const gitpath = await lookpath('git');
|
const gitpath = await lookpath('git');
|
||||||
if (gitpath === undefined) {
|
if (gitpath === undefined) {
|
||||||
console.log('[ERROR] `git` not installed.')
|
console.log('[ERROR] `git` not installed.')
|
||||||
@@ -1001,7 +1027,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
branch()
|
branch()
|
||||||
|
|
||||||
async function branch() {
|
async function branch() {
|
||||||
const {lookpath} = SA.nodeModules.lookpath
|
const { lookpath } = SA.nodeModules.lookpath
|
||||||
const gitpath = await lookpath('git');
|
const gitpath = await lookpath('git');
|
||||||
if (gitpath === undefined) {
|
if (gitpath === undefined) {
|
||||||
console.log('[ERROR] `git` not installed.')
|
console.log('[ERROR] `git` not installed.')
|
||||||
@@ -1135,7 +1161,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
try {
|
try {
|
||||||
console.log('fixSchemas...' + allAppSchemas.length)
|
console.log('fixSchemas...' + allAppSchemas.length)
|
||||||
let projects = SA.projects.foundations.utilities.filesAndDirectories.getDirectories(global.env.PATH_TO_PROJECTS)
|
let projects = SA.projects.foundations.utilities.filesAndDirectories.getDirectories(global.env.PATH_TO_PROJECTS)
|
||||||
const fs = SA.nodeModules.fs
|
//const fs = SA.nodeModules.fs
|
||||||
let needFixing = 0
|
let needFixing = 0
|
||||||
for (let i = 0; i < allAppSchemas.length; i++) {
|
for (let i = 0; i < allAppSchemas.length; i++) {
|
||||||
let schemaDocument = allAppSchemas[i]
|
let schemaDocument = allAppSchemas[i]
|
||||||
@@ -1183,13 +1209,13 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasUpdated === true) {
|
//if (wasUpdated === true) {
|
||||||
let fileContent = JSON.stringify(schemaDocument, undefined, 4)
|
//let fileContent = JSON.stringify(schemaDocument, undefined, 4)
|
||||||
let filePath = allAppSchemasFilePaths[i]
|
//let filePath = allAppSchemasFilePaths[i]
|
||||||
//console.log('Saving File at ' + filePath)
|
//console.log('Saving File at ' + filePath)
|
||||||
//console.log(fileContent)
|
//console.log(fileContent)
|
||||||
//fs.writeFileSync(filePath, fileContent)
|
//fs.writeFileSync(filePath, fileContent)
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err.stack)
|
console.log(err.stack)
|
||||||
@@ -1286,6 +1312,15 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case 'createGithubFork': {
|
||||||
|
|
||||||
|
let serverResponse = await PL.servers.GITHUB_SERVER.createGithubFork(
|
||||||
|
params.token
|
||||||
|
)
|
||||||
|
|
||||||
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||||
|
return
|
||||||
|
}
|
||||||
case 'mergePullRequests': {
|
case 'mergePullRequests': {
|
||||||
|
|
||||||
let serverResponse = await PL.servers.GITHUB_SERVER.mergePullRequests(
|
let serverResponse = await PL.servers.GITHUB_SERVER.mergePullRequests(
|
||||||
@@ -1318,8 +1353,21 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
|
|
||||||
let error
|
let error
|
||||||
|
|
||||||
|
await checkFork()
|
||||||
await updateUser()
|
await updateUser()
|
||||||
|
|
||||||
|
async function checkFork() {
|
||||||
|
let serverResponse = await PL.servers.GITHUB_SERVER.createGithubFork(
|
||||||
|
params.token
|
||||||
|
)
|
||||||
|
|
||||||
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||||
|
|
||||||
|
if(error != undefined) {
|
||||||
|
console.log('[ERROR] httpInterface -> Gov -> createFork -> You already have a fork. Good for you!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function updateUser() {
|
async function updateUser() {
|
||||||
|
|
||||||
await doGithubUser()
|
await doGithubUser()
|
||||||
@@ -1343,7 +1391,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
|
|
||||||
async function doGithubUser() {
|
async function doGithubUser() {
|
||||||
|
|
||||||
const {Octokit} = SA.nodeModules.octokit
|
const { Octokit } = SA.nodeModules.octokit
|
||||||
|
|
||||||
const octokit = new Octokit({
|
const octokit = new Octokit({
|
||||||
auth: token,
|
auth: token,
|
||||||
@@ -1353,8 +1401,14 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
const repo = 'Superalgos'
|
const repo = 'Superalgos'
|
||||||
const owner = 'Superalgos'
|
const owner = 'Superalgos'
|
||||||
const head = username + ':' + contributionsBranch
|
const head = username + ':' + contributionsBranch
|
||||||
const base = currentBranch
|
//const base = currentBranch
|
||||||
const title = 'Contribution: ' + mess
|
let base = undefined
|
||||||
|
if (process.env.SA_MODE === 'gitDisable') {
|
||||||
|
base = 'develop'
|
||||||
|
} else {
|
||||||
|
base = currentBranch
|
||||||
|
}
|
||||||
|
const title = 'Governance: ' + mess
|
||||||
const path = 'Projects/Governance/Plugins/User-Profiles/' + username + '.json';
|
const path = 'Projects/Governance/Plugins/User-Profiles/' + username + '.json';
|
||||||
|
|
||||||
const sha = await getSHA(path);
|
const sha = await getSHA(path);
|
||||||
@@ -1429,11 +1483,11 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
|
|
||||||
async function getSHA(path) {
|
async function getSHA(path) {
|
||||||
let sha = ''
|
let sha = ''
|
||||||
const {graphql} = SA.nodeModules.graphql
|
const { graphql } = SA.nodeModules.graphql
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const {repository} = await graphql(
|
const { repository } = await graphql(
|
||||||
'{ ' +
|
'{ ' +
|
||||||
' repository(name: "SuperAlgos", owner: "' + username + '") {' +
|
' repository(name: "SuperAlgos", owner: "' + username + '") {' +
|
||||||
' object(expression: "develop:' + path + '") {' +
|
' object(expression: "develop:' + path + '") {' +
|
||||||
@@ -1518,7 +1572,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify({error: 'Method ' + params.method + ' is invalid.'}), httpResponse)
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify({ error: 'Method ' + params.method + ' is invalid.' }), httpResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -1534,7 +1588,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
try {
|
try {
|
||||||
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(error), httpResponse)
|
SA.projects.foundations.utilities.httpResponses.respondWithContent(JSON.stringify(error), httpResponse)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// we just try to reponnd to the web app, but maybe the response has already been sent.
|
// we just try to respond to the web app, but maybe the response has already been sent.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2053,7 +2107,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
|
|
||||||
/* Create Dir if it does not exist */
|
/* Create Dir if it does not exist */
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
fs.mkdirSync(dir, {recursive: true});
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFile(filePath, fileContent, onFileWritten)
|
fs.writeFile(filePath, fileContent, onFileWritten)
|
||||||
@@ -2177,7 +2231,7 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
break
|
break
|
||||||
case 'Storage': {
|
case 'Storage': {
|
||||||
let pathToFile = httpRequest.url.substring(9)
|
let pathToFile = httpRequest.url.substring(9)
|
||||||
/* Unsavping # */
|
/* Unsaving # */
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
pathToFile = pathToFile.replace('_HASHTAG_', '#')
|
pathToFile = pathToFile.replace('_HASHTAG_', '#')
|
||||||
}
|
}
|
||||||
@@ -2197,4 +2251,14 @@ exports.newHttpInterface = function newHttpInterface() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createNewDir(path) {
|
||||||
|
try {
|
||||||
|
SA.nodeModules.fs.mkdirSync(path, { recursive: true })
|
||||||
|
} catch (err) {
|
||||||
|
if (err.message.indexOf('file already exists') < 0) {
|
||||||
|
throw (err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -225,6 +225,10 @@ function newEventsServerClient(lanNetworkNode) {
|
|||||||
port = config.webSocketsPort
|
port = config.webSocketsPort
|
||||||
extwsurl = config.webSocketsExternalURL
|
extwsurl = config.webSocketsExternalURL
|
||||||
|
|
||||||
|
if (UI.environment.DEMO_MODE === true) {
|
||||||
|
host = UI.environment.DEMO_MODE_HOST
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we really have to establish the connection. */
|
/* Check if we really have to establish the connection. */
|
||||||
if (config.autoConnect === false) { return }
|
if (config.autoConnect === false) { return }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ function newFrame() {
|
|||||||
|
|
||||||
function isThisPointHere(point, outsideViewPort, dontTransform, padding) {
|
function isThisPointHere(point, outsideViewPort, dontTransform, padding) {
|
||||||
// The second parameter is useful when you want to check a point that you already know is outside the viewport.
|
// The second parameter is useful when you want to check a point that you already know is outside the viewport.
|
||||||
// The padding is a distance to the borders of the container. Can be either negative (outside, to increase the container size) or positive (inside to decrease the cointainer size)
|
// The padding is a distance to the borders of the container. Can be either negative (outside, to increase the container size) or positive (inside to decrease the container size)
|
||||||
|
|
||||||
if (padding === undefined) { padding = 0 }
|
if (padding === undefined) { padding = 0 }
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
@@ -2,7 +2,7 @@
|
|||||||
* FlexSearch.js v0.7.2 (Bundle)
|
* FlexSearch.js v0.7.2 (Bundle)
|
||||||
* Copyright 2018-2021 Nextapps GmbH
|
* Copyright 2018-2021 Nextapps GmbH
|
||||||
* Author: Thomas Wilkerling
|
* Author: Thomas Wilkerling
|
||||||
* Licence: Apache-2.0
|
* License: Apache-2.0
|
||||||
* https://github.com/nextapps-de/flexsearch
|
* https://github.com/nextapps-de/flexsearch
|
||||||
*/
|
*/
|
||||||
(function _f(self){'use strict';try{if(module)self=module}catch(e){}self._factory=_f;var t;function u(a){return"undefined"!==typeof a?a:!0}function aa(a){const b=Array(a);for(let c=0;c<a;c++)b[c]=v();return b}function v(){return Object.create(null)}function ba(a,b){return b.length-a.length}function x(a){return"string"===typeof a}function C(a){return"object"===typeof a}function D(a){return"function"===typeof a};function ca(a,b){var c=da;if(a&&(b&&(a=E(a,b)),this.H&&(a=E(a,this.H)),this.J&&1<a.length&&(a=E(a,this.J)),c||""===c)){a=a.split(c);if(this.filter){b=this.filter;c=a.length;const d=[];for(let e=0,f=0;e<c;e++){const g=a[e];g&&!b[g]&&(d[f++]=g)}a=d}return a}return a}const da=/[\p{Z}\p{S}\p{P}\p{C}]+/u,ea=/[\u0300-\u036f]/g;
|
(function _f(self){'use strict';try{if(module)self=module}catch(e){}self._factory=_f;var t;function u(a){return"undefined"!==typeof a?a:!0}function aa(a){const b=Array(a);for(let c=0;c<a;c++)b[c]=v();return b}function v(){return Object.create(null)}function ba(a,b){return b.length-a.length}function x(a){return"string"===typeof a}function C(a){return"object"===typeof a}function D(a){return"function"===typeof a};function ca(a,b){var c=da;if(a&&(b&&(a=E(a,b)),this.H&&(a=E(a,this.H)),this.J&&1<a.length&&(a=E(a,this.J)),c||""===c)){a=a.split(c);if(this.filter){b=this.filter;c=a.length;const d=[];for(let e=0,f=0;e<c;e++){const g=a[e];g&&!b[g]&&(d[f++]=g)}a=d}return a}return a}const da=/[\p{Z}\p{S}\p{P}\p{C}]+/u,ea=/[\u0300-\u036f]/g;
|
||||||
|
|||||||
@@ -42,6 +42,15 @@
|
|||||||
try {
|
try {
|
||||||
drawSplashText()
|
drawSplashText()
|
||||||
loadSuperalgos()
|
loadSuperalgos()
|
||||||
|
window.api.receive('fromMaster', (data) => {
|
||||||
|
if(data.newUser){
|
||||||
|
UI.projects.foundations.spaces.designSpace.workspace.replaceWorkspaceByLoadingOne(data.newUser[0], data.newUser[1])
|
||||||
|
}else if(data.submit){
|
||||||
|
UI.projects.governance.spaces.reportsSpace.commandInterface.command = data.submit[0]
|
||||||
|
UI.projects.governance.spaces.reportsSpace.commandInterface.detectCommands()
|
||||||
|
//const element = document.getElementsByClassName("governance-filter-input")[0]
|
||||||
|
}
|
||||||
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("[ERROR] UI can not be started. Please check that WebServer is running.", err);
|
console.log("[ERROR] UI can not be started. Please check that WebServer is running.", err);
|
||||||
}
|
}
|
||||||
@@ -66,6 +75,13 @@
|
|||||||
|
|
||||||
function drawSplashText() {
|
function drawSplashText() {
|
||||||
const splashTextArray = [
|
const splashTextArray = [
|
||||||
|
{
|
||||||
|
"splashTextLine1Html": '<span class="credits-red">Every month, the project distributes 10M SA tokens with an approximate market value of $500,000 among contributors. </span>'
|
||||||
|
,
|
||||||
|
"splashTextLine2Html": 'The October 2021 distribution counted around 50 contributors, with an average mining reward of $10,000 each. Contributing to Superalgos today is like mining Bitcoin in 2010! Ask Community Mods how to join a team to participate in the next distribution!'
|
||||||
|
,
|
||||||
|
"splashTextLine3Html": ''
|
||||||
|
} /*,
|
||||||
{
|
{
|
||||||
"splashTextLine1Html": '<span class="credits-red">Superalgos is open source, forever free for everyone, and is constantly improving thanks to the involvement of contributors!</span>'
|
"splashTextLine1Html": '<span class="credits-red">Superalgos is open source, forever free for everyone, and is constantly improving thanks to the involvement of contributors!</span>'
|
||||||
,
|
,
|
||||||
@@ -107,7 +123,7 @@
|
|||||||
"splashTextLine2Html": 'Look around, find something that is missing and start coding! If you need help, ask in the chat groups to find a mentor!'
|
"splashTextLine2Html": 'Look around, find something that is missing and start coding! If you need help, ask in the chat groups to find a mentor!'
|
||||||
,
|
,
|
||||||
"splashTextLine3Html": 'Follow our motto: Just code it!'
|
"splashTextLine3Html": 'Follow our motto: Just code it!'
|
||||||
}
|
} */
|
||||||
]
|
]
|
||||||
|
|
||||||
let arrayIndex = Math.trunc(Math.random() * splashTextArray.length)
|
let arrayIndex = Math.trunc(Math.random() * splashTextArray.length)
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+93
-11
@@ -7,6 +7,11 @@
|
|||||||
"language": "ES",
|
"language": "ES",
|
||||||
"text": "La jerarquia trading engine es la estructura de datos utilizada por el robot comercial para mantener la información en tiempo de ejecución altamente accesible y expuesta a otros.",
|
"text": "La jerarquia trading engine es la estructura de datos utilizada por el robot comercial para mantener la información en tiempo de ejecución altamente accesible y expuesta a otros.",
|
||||||
"updated": 1624452474129
|
"updated": 1624452474129
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Trading Engine - это структура данных, используемая торговым ботом для обеспечения высокого доступа к информации во время выполнения и ее доступности для других торговых ботов.",
|
||||||
|
"updated": 1638338951505
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -17,50 +22,127 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "You will use this hierarchy for two main purposes:"
|
"text": "You will use this hierarchy for two main purposes:",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Вы будете использовать эту иерархию для двух основных целей:",
|
||||||
|
"updated": 1638338966721
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "List",
|
"style": "List",
|
||||||
"text": "To let your trading systems access the information processed by the trading bot. This allows strategies to keep track of and react to current and past events—including those involving the exchange, such as orders placed or filled—as the bot is running."
|
"text": "To let your trading systems access the information processed by the trading bot. This allows strategies to keep track of and react to current and past events—including those involving the exchange, such as orders placed or filled—as the bot is running.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Чтобы позволить вашим торговым системам получить доступ к информации, обрабатываемой торговым ботом. Это позволяет стратегиям отслеживать и реагировать на текущие и прошлые события, в том числе связанные с обменом, такие как размещенные или исполненные заявки, во время работы бота.",
|
||||||
|
"updated": 1638339042173
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "List",
|
"style": "List",
|
||||||
"text": "To keep track of the actions of the trading bot via the design space visual environment and panels over the charts. By analyzing runtime information, you may gain a detailed understanding of what happens, when, and why, throughout a trading session."
|
"text": "To keep track of the actions of the trading bot via the design space visual environment and panels over the charts. By analyzing runtime information, you may gain a detailed understanding of what happens, when, and why, throughout a trading session.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Для отслеживания действий торгового бота через визуальную среду Design Space и панели над графиками. Анализируя информацию о времени выполнения, вы можете получить подробное представление о том, что происходит, когда и почему в течение торговой сессии.",
|
||||||
|
"updated": 1638339093835
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Title",
|
"style": "Title",
|
||||||
"text": "Frequently Asked Questions"
|
"text": "Frequently Asked Questions",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Часто задаваемые вопросы",
|
||||||
|
"updated": 1638339158409
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Subtitle",
|
"style": "Subtitle",
|
||||||
"text": "Can a Trading Engine be shared between two Trading Bots?"
|
"text": "Can a Trading Engine be shared between two Trading Bots?",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Может ли Trading Engine использоваться совместно двумя торговыми ботами?",
|
||||||
|
"updated": 1638339236191
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "The same trading engine can be used from multiple trading sessions, because it is just a node-based representation of a data structure.",
|
"text": "The same trading engine can be used from multiple trading sessions, because it is just a node-based representation of a data structure.",
|
||||||
"updated": 1621987910896
|
"updated": 1621987910896,
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Один и тот же торговый движок можно использовать в нескольких торговых сессиях, потому что это просто представление структуры данных на основе узлов.",
|
||||||
|
"updated": 1638339266880
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "Every time a Task is ran, a snapshot of that data structure, together with a snapshot of the Network and the Bots definitions at their Data Mine is sent from the UI to the Task Server, and from there is consumed by the running Bot. That means that a second Bot can receive the same Trading Engine snapshot and it will never know if other bots were fed with the same information or not.",
|
"text": "Every time a Task is ran, a snapshot of that data structure, together with a snapshot of the Network and the Bots definitions at their Data Mine is sent from the UI to the Task Server, and from there is consumed by the running Bot. That means that a second Bot can receive the same Trading Engine snapshot and it will never know if other bots were fed with the same information or not.",
|
||||||
"updated": 1621987965915
|
"updated": 1621987965915,
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Каждый раз, когда запускается задача Task, снимок этой структуры данных вместе со снимком сети и определениями ботов в их Data Mine отправляется из UI на сервер задач Task Server, а оттуда используется запущенным ботом. Это означает, что второй бот может получить тот же снимок состояния Trading Engine, и он никогда не узнает, были ли другие боты загружены той же информацией или нет.",
|
||||||
|
"updated": 1638339437677
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Subtitle",
|
"style": "Subtitle",
|
||||||
"text": "Do I need to change something at the Trading Engine?"
|
"text": "Do I need to change something at the Trading Engine?",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Нужно ли мне что-то менять в Trading Engine?",
|
||||||
|
"updated": 1638339586902
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "You don't need to physically change anything inside trading engine via the UI. The trading engine is a visual representation of the data structure that the trading system uses to store its values, so to speak."
|
"text": "You don't need to physically change anything inside trading engine via the UI. The trading engine is a visual representation of the data structure that the trading system uses to store its values, so to speak.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Вам не нужно ничего физически менять внутри Trading Engine через UI. Trading Engine - это визуальное представление структуры данных, которую торговая система использует, так сказать, для хранения своих значений.",
|
||||||
|
"updated": 1638339666496
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Subtitle",
|
"style": "Subtitle",
|
||||||
"text": "Can I change the values inside the Trading Engine?"
|
"text": "Can I change the values inside the Trading Engine?",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Могу ли я изменить значения в Trading Engine?",
|
||||||
|
"updated": 1638339692515
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "You access the Trading Engine from within your trading system if there is something in there you would like to change. This is the whole purpose of the User Defined Code node.",
|
"text": "You access the Trading Engine from within your trading system if there is something in there you would like to change. This is the whole purpose of the User Defined Code node.",
|
||||||
"updated": 1621988418300
|
"updated": 1621988418300,
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Вы получаете доступ к Trading Engine из своей торговой системы, если в ней есть что-то, что вы хотели бы изменить. В этом вся цель узла User Defined Code.",
|
||||||
|
"updated": 1638339838848
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+37
-4
@@ -7,6 +7,11 @@
|
|||||||
"language": "ES",
|
"language": "ES",
|
||||||
"text": "Un trading mine es una jerarquía que contiene definiciones de trading bots y sus conspiradores. Estas definiciones constituyen los programas reales de dichos bots: el código fuente.",
|
"text": "Un trading mine es una jerarquía que contiene definiciones de trading bots y sus conspiradores. Estas definiciones constituyen los programas reales de dichos bots: el código fuente.",
|
||||||
"updated": 1628906153772
|
"updated": 1628906153772
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Trading Mine - это иерархия, которая содержит определения торговых ботов и их плоттеры. Эти определения составляют фактические программы таких ботов - исходный код.",
|
||||||
|
"updated": 1638338598326
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -17,16 +22,37 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "Altough Superalgos is starting out with a single trading bot, the system is prepared to feature as many trading bots as developers are willing to create. As such, a trading mine is a catalog of trading bots."
|
"text": "Altough Superalgos is starting out with a single trading bot, the system is prepared to feature as many trading bots as developers are willing to create. As such, a trading mine is a catalog of trading bots.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Хотя Superalgos начинает с одного торгового бота, система готова включать в себя столько торговых ботов, сколько разработчики готовы создать. Таким образом, Trading Mine представляет собой каталог торговых ботов.",
|
||||||
|
"updated": 1638338508685
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "Notice that, in the context of Superalgos, a trading bot has nothing to do with the trading logic. Think of trading logic as the business rules which—in Superalgos—are defined in trading systems. Anyone may build a Trading System, meaning that creating trading systems and the trading strategies within does not require coding.",
|
"text": "Notice that, in the context of Superalgos, a trading bot has nothing to do with the trading logic. Think of trading logic as the business rules which—in Superalgos—are defined in trading systems. Anyone may build a Trading System, meaning that creating trading systems and the trading strategies within does not require coding.",
|
||||||
"updated": 1609861342619
|
"updated": 1609861342619,
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Обратите внимание, что в контексте Superalgos торговый бот не имеет ничего общего с торговой логикой. Думайте о торговой логике как о бизнес-правилах, которые - в Superalgos - определены в торговых системах. Любой может создать торговую систему, а это означает, что создание торговых систем и торговых стратегий внутри нее не требует программирования.",
|
||||||
|
"updated": 1638338537661
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "Trading mines work similarly to data mines in the sense that they provide the same kind of tools to structure the definitions of bots, including process definitions, product definitions, and plotters."
|
"text": "Trading mines work similarly to data mines in the sense that they provide the same kind of tools to structure the definitions of bots, including process definitions, product definitions, and plotters.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Trading Mine работает аналогично Data Mine в том смысле, что они предоставляют те же инструменты для структурирования определений ботов, включая определения процессов, определения продуктов и плоттеры.",
|
||||||
|
"updated": 1638338689173
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Block",
|
"style": "Block",
|
||||||
@@ -35,7 +61,14 @@
|
|||||||
{
|
{
|
||||||
"style": "Title",
|
"style": "Title",
|
||||||
"text": "Trading Mine Configuration",
|
"text": "Trading Mine Configuration",
|
||||||
"updated": 1609861240385
|
"updated": 1609861240385,
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Настройка Trading Mine",
|
||||||
|
"updated": 1638338789550
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+67
-7
@@ -10,8 +10,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"language": "RU",
|
"language": "RU",
|
||||||
"text": "Торговая система - это структура, управляющая логикой низкого уровня, которая служит для структурирования процессов и методов, используемых для реализации и развертывания торговых стратегий.",
|
"text": "Trading System - это структура, управляющая логикой низкого уровня, которая служит для структурирования процессов и методов, используемых для реализации и развертывания торговых стратегий.",
|
||||||
"updated": 1636194401995
|
"updated": 1638338041020
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"language": "DE",
|
"language": "DE",
|
||||||
@@ -27,23 +27,83 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "In practical terms, a trading system is a hierarchical arrangement organizing the actionable aspects of your investment plan. The hierarchy contains definitions regarding any number of trading strategies, all operating on the same market and sharing the same initial capital allocation."
|
"text": "In practical terms, a trading system is a hierarchical arrangement organizing the actionable aspects of your investment plan. The hierarchy contains definitions regarding any number of trading strategies, all operating on the same market and sharing the same initial capital allocation.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "ES",
|
||||||
|
"text": "En términos prácticos, un Trading System es una disposición jerárquica que organiza los aspectos procesables de su plan de inversión. Esta jerarquía contiene definiciones respecto a un sinnúmero de estrategias de trading, todas operando en el mismo mercado y compartiendo la misma asignación de capital inicial.",
|
||||||
|
"updated": 1637880963165
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "С практической точки зрения торговая система - это иерархическая структура, организующая практические аспекты вашего инвестиционного плана. Иерархия содержит определения относительно любого количества торговых стратегий, работающих на одном рынке и имеющих одинаковое начальное распределение капитала.",
|
||||||
|
"updated": 1638338066276
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "You use a trading system to define strategies following the Superalgos Protocol, splitting strategies into four stages: trigger, open, manage, and close."
|
"text": "You use a trading system to define strategies following the Superalgos Protocol, splitting strategies into four stages: trigger, open, manage, and close.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "ES",
|
||||||
|
"text": "Se utiliza un Trading System para definir estrategias acorde al protocolo de Superalgos, dividiendo a éstas en cuatro etapas: activación, apertura, gestión y cierre.",
|
||||||
|
"updated": 1637880976135
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Вы используете торговую систему для определения стратегий в соответствии с протоколом Superalgos, разделяя стратегии на четыре этапа: запуск, открытие, управление и закрытие.",
|
||||||
|
"updated": 1638338085462
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "The concept of describing strategies in stages is fundamental to the methodical aspect of the trading system, as it provides a framework to run every strategy with the same framework, which contributes to developing scalable trading systems that may grow to any number of strategies."
|
"text": "The concept of describing strategies in stages is fundamental to the methodical aspect of the trading system, as it provides a framework to run every strategy with the same framework, which contributes to developing scalable trading systems that may grow to any number of strategies.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "ES",
|
||||||
|
"text": "El concepto de describir estrategias en etapas es fundamental para el aspecto metódico del Trading System, ya que provee la infraestructura necesaria para ejecutar cualquier estrategia con la misma infraestructura. Esto contribuye a desarrollar Trading Systems escalables, que pueden alcanzar innumerable cantidad de estrategias.",
|
||||||
|
"updated": 1637880986625
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Концепция поэтапного описания стратегий является фундаментальной для методического аспекта торговой системы, поскольку она обеспечивает основу для запуска каждой стратегии с одной и той же структурой, что способствует разработке масштабируемых торговых систем, которые могут расширяться до любого количества стратегий.",
|
||||||
|
"updated": 1638338107057
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "When a trading system features more than one strategy, the first strategy has precedence over the second, the second over the third, and so on. This means that strategies are evaluated in a sequence. When a given strategy is triggered-on, the remaining strategies in the queue are no longer evaluated until the strategy triggers off. In other words, when multiple strategies are deployed within a single trading system, only one strategy may trade at any given moment, and precedence is given by the order around the trading system node."
|
"text": "When a trading system features more than one strategy, the first strategy has precedence over the second, the second over the third, and so on. This means that strategies are evaluated in a sequence. When a given strategy is triggered-on, the remaining strategies in the queue are no longer evaluated until the strategy triggers off. In other words, when multiple strategies are deployed within a single trading system, only one strategy may trade at any given moment, and precedence is given by the order around the trading system node.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "ES",
|
||||||
|
"text": "Cuando un Trading System ofrece más de una estrategia, la primera estrategia tiene prioridad sobre la segunda, la segunda sobre la tercera, y así sucesivamente. Esto significa que las estrategias son analizadas de manera secuencial. Cuando una estrategia dada es activada, las estrategias restantes no serán analizadas hasta que ésta se desactive. En otras palabras, cuando se implementan múltiples estrategias bajo un único Trading System, solo una estrategia puede operar en un momento dado, y la prioridad está dada por el orden especificado en el Nodo del Trading System.",
|
||||||
|
"updated": 1637881003253
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Когда торговая система использует более одной стратегии, первая стратегия имеет приоритет над второй, вторая над третьей и так далее. Это означает, что стратегии оцениваются последовательно. Когда данная стратегия срабатывает, оставшиеся в очереди стратегии больше не оцениваются, пока стратегия не сработает. Другими словами, когда несколько стратегий развернуты в одной торговой системе, только одна стратегия может торговать в любой момент времени, а приоритет отдается порядку, установленному вокруг узла торговой системы.",
|
||||||
|
"updated": 1638338139127
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"style": "Text",
|
"style": "Text",
|
||||||
"text": "As a corollary to the above, if you wish strategies to operate in different markets, or you wish strategies to be able to take positions simultaneously, then you must set up those strategies in different trading systems."
|
"text": "As a corollary to the above, if you wish strategies to operate in different markets, or you wish strategies to be able to take positions simultaneously, then you must set up those strategies in different trading systems.",
|
||||||
|
"translations": [
|
||||||
|
{
|
||||||
|
"language": "ES",
|
||||||
|
"text": "Como complemento a lo anterior, si se desea configurar estrategias que operen sobre diferentes mercados, o estrategias que tengan la posibilidad de abrir posiciones de forma simultánea, entonces se las deberá configurar bajo Trading Systems distintos.",
|
||||||
|
"updated": 1637881023208
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "RU",
|
||||||
|
"text": "Как следствие вышесказанного, если вы хотите, чтобы стратегии работали на разных рынках, или вы хотите, чтобы стратегии могли открывать позиции одновременно, вы должны настроить эти стратегии в разных торговых системах.",
|
||||||
|
"updated": 1638338156830
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+17
-2
@@ -23,13 +23,17 @@
|
|||||||
function initialize() {
|
function initialize() {
|
||||||
tradingSystem = TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingSystem
|
tradingSystem = TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingSystem
|
||||||
|
|
||||||
exchangeId = TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName
|
let exchangeConfig = TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config
|
||||||
|
exchangeId = exchangeConfig.codeName
|
||||||
|
if (exchangeConfig.options !== undefined) {
|
||||||
|
options = exchangeConfig.options
|
||||||
|
}
|
||||||
|
|
||||||
let key
|
let key
|
||||||
let secret
|
let secret
|
||||||
let uid
|
let uid
|
||||||
let password
|
let password
|
||||||
let sandBox = TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.sandbox || false;
|
let sandBox = exchangeConfig.sandbox || false;
|
||||||
|
|
||||||
if (TS.projects.foundations.globals.taskConstants.TASK_NODE.keyReference !== undefined) {
|
if (TS.projects.foundations.globals.taskConstants.TASK_NODE.keyReference !== undefined) {
|
||||||
if (TS.projects.foundations.globals.taskConstants.TASK_NODE.keyReference.referenceParent !== undefined) {
|
if (TS.projects.foundations.globals.taskConstants.TASK_NODE.keyReference.referenceParent !== undefined) {
|
||||||
@@ -39,6 +43,17 @@
|
|||||||
password = TS.projects.foundations.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.password
|
password = TS.projects.foundations.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.password
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (exchangeId) {
|
||||||
|
case 'okex':
|
||||||
|
case 'okex3':
|
||||||
|
case 'okex5':
|
||||||
|
if (!('brokerId' in options)) {
|
||||||
|
options.brokerId = 'c77ccd60ec7b4cBC'
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const exchangeClass = ccxt[exchangeId]
|
const exchangeClass = ccxt[exchangeId]
|
||||||
const exchangeConstructorParams = {
|
const exchangeConstructorParams = {
|
||||||
'apiKey': key,
|
'apiKey': key,
|
||||||
|
|||||||
+1
-1
@@ -208,7 +208,7 @@ exports.newAlgorithmicTradingBotModulesOrdersSimulations = function (processInde
|
|||||||
case tradingSystemOrder.type === 'Market Buy Order' || tradingSystemOrder.type === 'Limit Buy Order': {
|
case tradingSystemOrder.type === 'Market Buy Order' || tradingSystemOrder.type === 'Limit Buy Order': {
|
||||||
if (tradingEngineOrder.orderStatistics.actualRate.value > tradingEngine.tradingCurrent.tradingEpisode.candle.max.value) {
|
if (tradingEngineOrder.orderStatistics.actualRate.value > tradingEngine.tradingCurrent.tradingEpisode.candle.max.value) {
|
||||||
|
|
||||||
const message = 'Simulating - Actual Rate Too Hight'
|
const message = 'Simulating - Actual Rate Too High'
|
||||||
let docs = {
|
let docs = {
|
||||||
project: 'Foundations',
|
project: 'Foundations',
|
||||||
category: 'Topic',
|
category: 'Topic',
|
||||||
|
|||||||
+1
-1
@@ -150,7 +150,7 @@ exports.newAlgorithmicTradingBotModulesSnapshots = function(processIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now we go down through all this node children */
|
/* Now we go down through all this node children */
|
||||||
let schemaDocument = TS.projects.foundations.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
let schemaDocument = SA.projects.foundations.globals.schemas.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
||||||
if (schemaDocument === undefined) { return }
|
if (schemaDocument === undefined) { return }
|
||||||
|
|
||||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||||
|
|||||||
+3
-3
@@ -112,7 +112,7 @@ exports.newAlgorithmicTradingBotModulesTradingEngine = function (processIndex) {
|
|||||||
destinationNode.value = originNode.value
|
destinationNode.value = originNode.value
|
||||||
|
|
||||||
/* Now we go down through all the children of the origin node, assuming the destination node has the same children structure*/
|
/* Now we go down through all the children of the origin node, assuming the destination node has the same children structure*/
|
||||||
let schemaDocument = TS.projects.foundations.globals.taskConstants.APP_SCHEMA_MAP.get(originNode.project + '-' + originNode.type)
|
let schemaDocument = SA.projects.foundations.globals.schemas.APP_SCHEMA_MAP.get(originNode.project + '-' + originNode.type)
|
||||||
if (schemaDocument === undefined) { return }
|
if (schemaDocument === undefined) { return }
|
||||||
|
|
||||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||||
@@ -151,7 +151,7 @@ exports.newAlgorithmicTradingBotModulesTradingEngine = function (processIndex) {
|
|||||||
nodesMap.set(node.id, node)
|
nodesMap.set(node.id, node)
|
||||||
|
|
||||||
/* Now we go down through all this node children */
|
/* Now we go down through all this node children */
|
||||||
let schemaDocument = TS.projects.foundations.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
let schemaDocument = SA.projects.foundations.globals.schemas.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
||||||
if (schemaDocument === undefined) { return }
|
if (schemaDocument === undefined) { return }
|
||||||
|
|
||||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||||
@@ -194,7 +194,7 @@ exports.newAlgorithmicTradingBotModulesTradingEngine = function (processIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now we go down through all this node children */
|
/* Now we go down through all this node children */
|
||||||
let schemaDocument = TS.projects.foundations.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
let schemaDocument = SA.projects.foundations.globals.schemas.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
||||||
if (schemaDocument === undefined) { return }
|
if (schemaDocument === undefined) { return }
|
||||||
|
|
||||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ exports.newAlgorithmicTradingBotModulesTradingOutput = function (processIndex) {
|
|||||||
/* Preparing everything for the Simulation */
|
/* Preparing everything for the Simulation */
|
||||||
let tradingSimulationModuleObject = TS.projects.algorithmicTrading.botModules.tradingSimulation.newAlgorithmicTradingBotModulesTradingSimulation(processIndex)
|
let tradingSimulationModuleObject = TS.projects.algorithmicTrading.botModules.tradingSimulation.newAlgorithmicTradingBotModulesTradingSimulation(processIndex)
|
||||||
|
|
||||||
let outputDatasets = TS.projects.visualScripting.utilities.nodeFunctions.nodeBranchToArray(TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
let outputDatasets = SA.projects.visualScripting.utilities.nodeFunctions.nodeBranchToArray(TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||||
let outputDatasetsMap = new Map()
|
let outputDatasetsMap = new Map()
|
||||||
|
|
||||||
await TS.projects.foundations.functionLibraries.outputManagementFunctions.readFiles(
|
await TS.projects.foundations.functionLibraries.outputManagementFunctions.readFiles(
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@ exports.newAlgorithmicTradingBotModulesTradingRecords = function (processIndex)
|
|||||||
we have a pointer to the node that have the information we need to extract.
|
we have a pointer to the node that have the information we need to extract.
|
||||||
Later, based on the product record definition we will extract each individual value.
|
Later, based on the product record definition we will extract each individual value.
|
||||||
*/
|
*/
|
||||||
let outputDatasets = TS.projects.visualScripting.utilities.nodeFunctions.nodeBranchToArray(TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
let outputDatasets = SA.projects.visualScripting.utilities.nodeFunctions.nodeBranchToArray(TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||||
|
|
||||||
for (let i = 0; i < outputDatasets.length; i++) {
|
for (let i = 0; i < outputDatasets.length; i++) {
|
||||||
let outputDatasetNode = outputDatasets[i]
|
let outputDatasetNode = outputDatasets[i]
|
||||||
|
|||||||
+2
-2
@@ -372,8 +372,8 @@ exports.newAlgorithmicTradingBotModulesTradingSimulation = function (processInde
|
|||||||
}
|
}
|
||||||
|
|
||||||
function positionChart(chart) {
|
function positionChart(chart) {
|
||||||
let dataDependencies = TS.projects.visualScripting.utilities.nodeFunctions.nodeBranchToArray(TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency')
|
let dataDependencies = SA.projects.visualScripting.utilities.nodeFunctions.nodeBranchToArray(TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency')
|
||||||
dataDependencies = TS.projects.visualScripting.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies)
|
dataDependencies = SA.projects.visualScripting.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies)
|
||||||
|
|
||||||
/* Finding the Current Element on Daily Files */
|
/* Finding the Current Element on Daily Files */
|
||||||
if (TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
if (TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||||
|
|||||||
+54
-34
@@ -25,6 +25,8 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
let tradingPositionModuleObject = TS.projects.algorithmicTrading.botModules.tradingPosition.newAlgorithmicTradingBotModulesTradingPosition(processIndex)
|
let tradingPositionModuleObject = TS.projects.algorithmicTrading.botModules.tradingPosition.newAlgorithmicTradingBotModulesTradingPosition(processIndex)
|
||||||
let tradingExecutionModuleObject = TS.projects.algorithmicTrading.botModules.tradingExecution.newAlgorithmicTradingBotModulesTradingExecution(processIndex)
|
let tradingExecutionModuleObject = TS.projects.algorithmicTrading.botModules.tradingExecution.newAlgorithmicTradingBotModulesTradingExecution(processIndex)
|
||||||
let announcementsModuleObject = TS.projects.socialBots.botModules.announcements.newSocialBotsBotModulesAnnouncements(processIndex)
|
let announcementsModuleObject = TS.projects.socialBots.botModules.announcements.newSocialBotsBotModulesAnnouncements(processIndex)
|
||||||
|
let outgoingTradingSignalsModuleObject = TS.projects.tradingSignals.modules.outgoingTradingSignals.newTradingSignalsModulesOutgoingTradingSignals(processIndex)
|
||||||
|
let portfolioManagerClient = TS.projects.portfolioManagement.modules.portfolioManagerClient.newPortfolioManagementModulesPortfolioManagerClient(processIndex)
|
||||||
let snapshotsModuleObject = TS.projects.algorithmicTrading.botModules.snapshots.newAlgorithmicTradingBotModulesSnapshots(processIndex)
|
let snapshotsModuleObject = TS.projects.algorithmicTrading.botModules.snapshots.newAlgorithmicTradingBotModulesSnapshots(processIndex)
|
||||||
let tradingEpisodeModuleObject = TS.projects.algorithmicTrading.botModules.tradingEpisode.newAlgorithmicTradingBotModulesTradingEpisode(processIndex)
|
let tradingEpisodeModuleObject = TS.projects.algorithmicTrading.botModules.tradingEpisode.newAlgorithmicTradingBotModulesTradingEpisode(processIndex)
|
||||||
|
|
||||||
@@ -97,15 +99,15 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
tradingPositionModuleObject.cycleBasedStatistics()
|
tradingPositionModuleObject.cycleBasedStatistics()
|
||||||
}
|
}
|
||||||
|
|
||||||
function runTriggerStage() {
|
async function runTriggerStage() {
|
||||||
/*
|
/*
|
||||||
We check if we will be triggering on, off or taking position.
|
We check if we will be triggering on, off or taking position.
|
||||||
*/
|
*/
|
||||||
checkTriggerOn()
|
await checkTriggerOn()
|
||||||
checkTriggerOff()
|
await checkTriggerOff()
|
||||||
checkTakePosition()
|
await checkTakePosition()
|
||||||
|
|
||||||
function checkTriggerOn() {
|
async function checkTriggerOn() {
|
||||||
if (
|
if (
|
||||||
tradingEngine.tradingCurrent.strategy.index.value === tradingEngine.tradingCurrent.strategy.index.config.initialValue
|
tradingEngine.tradingCurrent.strategy.index.value === tradingEngine.tradingCurrent.strategy.index.config.initialValue
|
||||||
) {
|
) {
|
||||||
@@ -137,7 +139,12 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
passed = tradingSystem.checkConditions(situation, passed)
|
passed = tradingSystem.checkConditions(situation, passed)
|
||||||
|
|
||||||
tradingSystem.values.push([situation.id, passed])
|
tradingSystem.values.push([situation.id, passed])
|
||||||
|
|
||||||
|
let response = await portfolioManagerClient.askPortfolioEventsManager(triggerStage.triggerOn, passed)
|
||||||
|
passed = response.raiseEvent
|
||||||
|
|
||||||
if (passed) {
|
if (passed) {
|
||||||
|
|
||||||
tradingSystem.highlights.push(situation.id)
|
tradingSystem.highlights.push(situation.id)
|
||||||
tradingSystem.highlights.push(triggerStage.triggerOn.id)
|
tradingSystem.highlights.push(triggerStage.triggerOn.id)
|
||||||
tradingSystem.highlights.push(triggerStage.id)
|
tradingSystem.highlights.push(triggerStage.id)
|
||||||
@@ -147,6 +154,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
/* Initialize this */
|
/* Initialize this */
|
||||||
tradingEngine.tradingCurrent.tradingEpisode.distanceToTradingEvent.triggerOn.value = 1
|
tradingEngine.tradingCurrent.tradingEpisode.distanceToTradingEvent.triggerOn.value = 1
|
||||||
|
|
||||||
|
await outgoingTradingSignalsModuleObject.broadcastSignal(triggerStage.triggerOn)
|
||||||
announcementsModuleObject.makeAnnouncements(triggerStage.triggerOn)
|
announcementsModuleObject.makeAnnouncements(triggerStage.triggerOn)
|
||||||
|
|
||||||
if (TS.projects.foundations.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
if (TS.projects.foundations.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
||||||
@@ -156,9 +164,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeStageStatus('Trigger Stage', 'Open')
|
changeStageStatus('Trigger Stage', 'Open')
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,7 +173,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTriggerOff() {
|
async function checkTriggerOff() {
|
||||||
if (tradingEngine.tradingCurrent.strategyTriggerStage.status.value === 'Open') {
|
if (tradingEngine.tradingCurrent.strategyTriggerStage.status.value === 'Open') {
|
||||||
checkUserDefinedCode('Trigger Stage', 'Running', 'first');
|
checkUserDefinedCode('Trigger Stage', 'Running', 'first');
|
||||||
|
|
||||||
@@ -188,12 +194,18 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
passed = tradingSystem.checkConditions(situation, passed)
|
passed = tradingSystem.checkConditions(situation, passed)
|
||||||
|
|
||||||
tradingSystem.values.push([situation.id, passed])
|
tradingSystem.values.push([situation.id, passed])
|
||||||
|
|
||||||
|
let response = await portfolioManagerClient.askPortfolioEventsManager(triggerStage.triggerOff, passed)
|
||||||
|
passed = response.raiseEvent
|
||||||
|
|
||||||
if (passed) {
|
if (passed) {
|
||||||
tradingSystem.highlights.push(situation.id)
|
tradingSystem.highlights.push(situation.id)
|
||||||
tradingSystem.highlights.push(triggerStage.triggerOff.id)
|
tradingSystem.highlights.push(triggerStage.triggerOff.id)
|
||||||
tradingSystem.highlights.push(triggerStage.id)
|
tradingSystem.highlights.push(triggerStage.id)
|
||||||
|
|
||||||
tradingEngine.tradingCurrent.tradingEpisode.distanceToTradingEvent.triggerOff.value = 1
|
tradingEngine.tradingCurrent.tradingEpisode.distanceToTradingEvent.triggerOff.value = 1
|
||||||
|
|
||||||
|
outgoingTradingSignalsModuleObject.broadcastSignal(triggerStage.triggerOff)
|
||||||
announcementsModuleObject.makeAnnouncements(triggerStage.triggerOff)
|
announcementsModuleObject.makeAnnouncements(triggerStage.triggerOff)
|
||||||
changeStageStatus('Trigger Stage', 'Closed', 'Trigger Off Event')
|
changeStageStatus('Trigger Stage', 'Closed', 'Trigger Off Event')
|
||||||
tradingStrategyModuleObject.closeStrategy('Trigger Off')
|
tradingStrategyModuleObject.closeStrategy('Trigger Off')
|
||||||
@@ -204,7 +216,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTakePosition() {
|
async function checkTakePosition() {
|
||||||
if (
|
if (
|
||||||
tradingEngine.tradingCurrent.strategyTriggerStage.status.value === 'Open'
|
tradingEngine.tradingCurrent.strategyTriggerStage.status.value === 'Open'
|
||||||
) {
|
) {
|
||||||
@@ -212,7 +224,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
let triggerStage = strategy.triggerStage
|
let triggerStage = strategy.triggerStage
|
||||||
|
|
||||||
tradingSystem.evalConditions(strategy, 'Take Position Event')
|
tradingSystem.evalConditions(strategy, 'Take Position Event')
|
||||||
tradingSystem.evalFormulas(strategy, 'Take Position Event')
|
await tradingSystem.evalFormulas(strategy, 'Take Position Event')
|
||||||
|
|
||||||
if (triggerStage !== undefined) {
|
if (triggerStage !== undefined) {
|
||||||
if (triggerStage.takePosition !== undefined) {
|
if (triggerStage.takePosition !== undefined) {
|
||||||
@@ -226,6 +238,10 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
passed = tradingSystem.checkConditions(situation, passed)
|
passed = tradingSystem.checkConditions(situation, passed)
|
||||||
|
|
||||||
tradingSystem.values.push([situation.id, passed])
|
tradingSystem.values.push([situation.id, passed])
|
||||||
|
|
||||||
|
let response = await portfolioManagerClient.askPortfolioEventsManager(triggerStage.takePosition, passed)
|
||||||
|
passed = response.raiseEvent
|
||||||
|
|
||||||
if (passed) {
|
if (passed) {
|
||||||
tradingSystem.highlights.push(situation.id)
|
tradingSystem.highlights.push(situation.id)
|
||||||
tradingSystem.highlights.push(triggerStage.takePosition.id)
|
tradingSystem.highlights.push(triggerStage.takePosition.id)
|
||||||
@@ -233,6 +249,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
|
|
||||||
tradingPositionModuleObject.openPosition(situation.name)
|
tradingPositionModuleObject.openPosition(situation.name)
|
||||||
|
|
||||||
|
outgoingTradingSignalsModuleObject.broadcastSignal(triggerStage.takePosition)
|
||||||
announcementsModuleObject.makeAnnouncements(triggerStage.takePosition)
|
announcementsModuleObject.makeAnnouncements(triggerStage.takePosition)
|
||||||
|
|
||||||
if (TS.projects.foundations.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
if (TS.projects.foundations.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
||||||
@@ -259,14 +276,14 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
async function runOpenStage() {
|
async function runOpenStage() {
|
||||||
|
|
||||||
checkIfWeNeedToAbortTheStage()
|
checkIfWeNeedToAbortTheStage()
|
||||||
runWhenStatusIsOpening()
|
await runWhenStatusIsOpening()
|
||||||
await runWhenStatusIsOpen()
|
await runWhenStatusIsOpen()
|
||||||
await runWhenStatusIsClosing()
|
await runWhenStatusIsClosing()
|
||||||
|
|
||||||
function checkIfWeNeedToAbortTheStage() {
|
function checkIfWeNeedToAbortTheStage() {
|
||||||
/* Abort Open Stage Check */
|
/* Abort Open Stage Check */
|
||||||
if (tradingEngine.tradingCurrent.strategyOpenStage.status.value === 'Open' &&
|
if (tradingEngine.tradingCurrent.strategyOpenStage.status.value === 'Open' &&
|
||||||
(tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Opening' || tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Open') ){
|
(tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Opening' || tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Open')) {
|
||||||
/*
|
/*
|
||||||
if the Close stage is opened while the open stage is still open that means that
|
if the Close stage is opened while the open stage is still open that means that
|
||||||
we need to stop placing orders, check what happened to the orders already placed,
|
we need to stop placing orders, check what happened to the orders already placed,
|
||||||
@@ -276,7 +293,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runWhenStatusIsOpening() {
|
async function runWhenStatusIsOpening() {
|
||||||
/* Opening Status Procedure */
|
/* Opening Status Procedure */
|
||||||
if (tradingEngine.tradingCurrent.strategyOpenStage.status.value === 'Opening') {
|
if (tradingEngine.tradingCurrent.strategyOpenStage.status.value === 'Opening') {
|
||||||
/*
|
/*
|
||||||
@@ -298,7 +315,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
TS.projects.foundations.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.initializeNode(tradingEngine.exchangeOrders)
|
TS.projects.foundations.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.initializeNode(tradingEngine.exchangeOrders)
|
||||||
|
|
||||||
/* Entry Position size and rate */
|
/* Entry Position size and rate */
|
||||||
tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets')
|
await tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets')
|
||||||
tradingPositionModuleObject.initialTargets(tradingSystemStage, tradingEngineStage)
|
tradingPositionModuleObject.initialTargets(tradingSystemStage, tradingEngineStage)
|
||||||
initializeStageTargetSize()
|
initializeStageTargetSize()
|
||||||
|
|
||||||
@@ -321,7 +338,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
|
|
||||||
/* Evaluate conditions and formulas so they are ready during the execution run */
|
/* Evaluate conditions and formulas so they are ready during the execution run */
|
||||||
tradingSystem.evalConditions(executionNode, 'Open Execution')
|
tradingSystem.evalConditions(executionNode, 'Open Execution')
|
||||||
tradingSystem.evalFormulas(executionNode, 'Open Execution')
|
await tradingSystem.evalFormulas(executionNode, 'Open Execution')
|
||||||
|
|
||||||
await tradingExecutionModuleObject.runExecution(
|
await tradingExecutionModuleObject.runExecution(
|
||||||
executionNode,
|
executionNode,
|
||||||
@@ -351,7 +368,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
and cancel the ones that were not.
|
and cancel the ones that were not.
|
||||||
*/
|
*/
|
||||||
tradingSystem.evalConditions(tradingSystemStage, 'Open Execution')
|
tradingSystem.evalConditions(tradingSystemStage, 'Open Execution')
|
||||||
tradingSystem.evalFormulas(tradingSystemStage, 'Open Execution')
|
await tradingSystem.evalFormulas(tradingSystemStage, 'Open Execution')
|
||||||
|
|
||||||
await tradingExecutionModuleObject.runExecution(
|
await tradingExecutionModuleObject.runExecution(
|
||||||
executionNode,
|
executionNode,
|
||||||
@@ -407,12 +424,12 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runManageStage() {
|
async function runManageStage() {
|
||||||
|
|
||||||
if (tradingEngine.tradingCurrent.tradingEpisode.cycle.value !== 'First') { return }
|
if (tradingEngine.tradingCurrent.tradingEpisode.cycle.value !== 'First') { return }
|
||||||
|
|
||||||
runWhenStatusIsOpening()
|
runWhenStatusIsOpening()
|
||||||
runWhenStatusIsOpen()
|
await runWhenStatusIsOpen()
|
||||||
|
|
||||||
function runWhenStatusIsOpening() {
|
function runWhenStatusIsOpening() {
|
||||||
/* Opening Status Procedure */
|
/* Opening Status Procedure */
|
||||||
@@ -438,7 +455,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runWhenStatusIsOpen() {
|
async function runWhenStatusIsOpen() {
|
||||||
/* Open Status Procedure */
|
/* Open Status Procedure */
|
||||||
if (tradingEngine.tradingCurrent.strategyManageStage.status.value === 'Open') {
|
if (tradingEngine.tradingCurrent.strategyManageStage.status.value === 'Open') {
|
||||||
checkUserDefinedCode('Manage Stage', 'Running', 'first');
|
checkUserDefinedCode('Manage Stage', 'Running', 'first');
|
||||||
@@ -447,7 +464,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
|
|
||||||
/* Evaluate all the stage conditions and formulas to have them ready */
|
/* Evaluate all the stage conditions and formulas to have them ready */
|
||||||
tradingSystem.evalConditions(manageStage, 'Manage Stage')
|
tradingSystem.evalConditions(manageStage, 'Manage Stage')
|
||||||
tradingSystem.evalFormulas(manageStage, 'Manage Stage')
|
await tradingSystem.evalFormulas(manageStage, 'Manage Stage')
|
||||||
|
|
||||||
/* Stop Loss Management */
|
/* Stop Loss Management */
|
||||||
checkStopPhasesEvents()
|
checkStopPhasesEvents()
|
||||||
@@ -696,6 +713,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
|
|
||||||
tradingPositionModuleObject.updateTakeProfit(tradingEngine.tradingCurrent.position.takeProfit.takeProfitPhase.value + 1)
|
tradingPositionModuleObject.updateTakeProfit(tradingEngine.tradingCurrent.position.takeProfit.takeProfitPhase.value + 1)
|
||||||
|
|
||||||
|
outgoingTradingSignalsModuleObject.broadcastSignal(nextPhaseEvent)
|
||||||
announcementsModuleObject.makeAnnouncements(nextPhaseEvent)
|
announcementsModuleObject.makeAnnouncements(nextPhaseEvent)
|
||||||
|
|
||||||
/* Reset this counter */
|
/* Reset this counter */
|
||||||
@@ -747,6 +765,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outgoingTradingSignalsModuleObject.broadcastSignal(moveToPhaseEvent)
|
||||||
announcementsModuleObject.makeAnnouncements(moveToPhaseEvent)
|
announcementsModuleObject.makeAnnouncements(moveToPhaseEvent)
|
||||||
|
|
||||||
/* Reset this counter */
|
/* Reset this counter */
|
||||||
@@ -810,11 +829,11 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
|
|
||||||
async function runCloseStage() {
|
async function runCloseStage() {
|
||||||
|
|
||||||
runWhenStatusIsOpening()
|
await runWhenStatusIsOpening()
|
||||||
await runWhenStatusIsOpen()
|
await runWhenStatusIsOpen()
|
||||||
await runWhenStatusIsClosing()
|
await runWhenStatusIsClosing()
|
||||||
|
|
||||||
function runWhenStatusIsOpening() {
|
async function runWhenStatusIsOpening() {
|
||||||
|
|
||||||
/* Opening Status Procedure */
|
/* Opening Status Procedure */
|
||||||
if (tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Opening') {
|
if (tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Opening') {
|
||||||
@@ -834,7 +853,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage
|
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage
|
||||||
|
|
||||||
/* Exit Position size and rate */
|
/* Exit Position size and rate */
|
||||||
tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets')
|
await tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets')
|
||||||
if (tradingPositionModuleObject.initialTargets(tradingSystemStage, tradingEngine.tradingCurrent.strategyCloseStage, 'Close Stage') === false) {
|
if (tradingPositionModuleObject.initialTargets(tradingSystemStage, tradingEngine.tradingCurrent.strategyCloseStage, 'Close Stage') === false) {
|
||||||
//console.log("No Close-Stage Target Asset to Trade: Strategy Closing.");
|
//console.log("No Close-Stage Target Asset to Trade: Strategy Closing.");
|
||||||
}
|
}
|
||||||
@@ -866,7 +885,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
let executionNode = tradingSystemStage.closeExecution
|
let executionNode = tradingSystemStage.closeExecution
|
||||||
|
|
||||||
tradingSystem.evalConditions(tradingSystemStage, 'Close Execution')
|
tradingSystem.evalConditions(tradingSystemStage, 'Close Execution')
|
||||||
tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution')
|
await tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution')
|
||||||
|
|
||||||
await tradingExecutionModuleObject.runExecution(
|
await tradingExecutionModuleObject.runExecution(
|
||||||
executionNode,
|
executionNode,
|
||||||
@@ -896,7 +915,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
and cancel the ones that were not.
|
and cancel the ones that were not.
|
||||||
*/
|
*/
|
||||||
tradingSystem.evalConditions(tradingSystemStage, 'Close Execution')
|
tradingSystem.evalConditions(tradingSystemStage, 'Close Execution')
|
||||||
tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution')
|
await tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution')
|
||||||
|
|
||||||
await tradingExecutionModuleObject.runExecution(
|
await tradingExecutionModuleObject.runExecution(
|
||||||
executionNode,
|
executionNode,
|
||||||
@@ -1108,6 +1127,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
tradingSystem.highlights.push(closeStageEvent.id)
|
tradingSystem.highlights.push(closeStageEvent.id)
|
||||||
tradingSystem.highlights.push(stage.id)
|
tradingSystem.highlights.push(stage.id)
|
||||||
|
|
||||||
|
outgoingTradingSignalsModuleObject.broadcastSignal(closeStageEvent)
|
||||||
announcementsModuleObject.makeAnnouncements(closeStageEvent)
|
announcementsModuleObject.makeAnnouncements(closeStageEvent)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -1272,20 +1292,20 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
tradingSystemStage.userDefinedCode !== undefined) {
|
tradingSystemStage.userDefinedCode !== undefined) {
|
||||||
if (status === 'Running' && when !== tradingSystemStage.userDefinedCode.config.whileAtStageWhenToRun) { return; }
|
if (status === 'Running' && when !== tradingSystemStage.userDefinedCode.config.whileAtStageWhenToRun) { return; }
|
||||||
|
|
||||||
switch(status) {
|
switch (status) {
|
||||||
case 'Open' : {
|
case 'Open': {
|
||||||
if (tradingSystemStage.userDefinedCode.config.runWhenEnteringStage) {
|
if (tradingSystemStage.userDefinedCode.config.runWhenEnteringStage) {
|
||||||
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
|
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'Running' : {
|
case 'Running': {
|
||||||
if (tradingSystemStage.userDefinedCode.config.runWhileAtStage) {
|
if (tradingSystemStage.userDefinedCode.config.runWhileAtStage) {
|
||||||
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
|
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'Closed' : {
|
case 'Closed': {
|
||||||
if (tradingSystemStage.userDefinedCode.config.runWhenExitingStage) {
|
if (tradingSystemStage.userDefinedCode.config.runWhenExitingStage) {
|
||||||
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
|
tradingSystem.evalUserCode(tradingSystemStage, 'User Defined Code');
|
||||||
}
|
}
|
||||||
@@ -1305,20 +1325,20 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) {
|
|||||||
|
|
||||||
/* getTradingSystemStage(): takes stage name returns stage object. */
|
/* getTradingSystemStage(): takes stage name returns stage object. */
|
||||||
function getTradingSystemStage(stage) {
|
function getTradingSystemStage(stage) {
|
||||||
switch(stage) {
|
switch (stage) {
|
||||||
case 'Trigger Stage' : {
|
case 'Trigger Stage': {
|
||||||
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].triggerStage;
|
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].triggerStage;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'Open Stage' : {
|
case 'Open Stage': {
|
||||||
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].openStage;
|
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].openStage;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'Manage Stage' : {
|
case 'Manage Stage': {
|
||||||
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].manageStage;
|
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].manageStage;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'Close Stage' : {
|
case 'Close Stage': {
|
||||||
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage;
|
return tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-10
@@ -27,6 +27,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
let dynamicIndicators
|
let dynamicIndicators
|
||||||
|
|
||||||
let tradingStagesModuleObject = TS.projects.algorithmicTrading.botModules.tradingStages.newAlgorithmicTradingBotModulesTradingStages(processIndex)
|
let tradingStagesModuleObject = TS.projects.algorithmicTrading.botModules.tradingStages.newAlgorithmicTradingBotModulesTradingStages(processIndex)
|
||||||
|
let portfolioManagerClient = TS.projects.portfolioManagement.modules.portfolioManagerClient.newPortfolioManagementModulesPortfolioManagerClient(processIndex)
|
||||||
|
|
||||||
let taskParameters = {
|
let taskParameters = {
|
||||||
market: TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName +
|
market: TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName +
|
||||||
@@ -70,8 +71,8 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
evalNode(startingNode, 'Conditions', descendentOfNodeType)
|
evalNode(startingNode, 'Conditions', descendentOfNodeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
tradingSystem.evalFormulas = function (startingNode, descendentOfNodeType) {
|
tradingSystem.evalFormulas = async function (startingNode, descendentOfNodeType) {
|
||||||
evalNode(startingNode, 'Formulas', descendentOfNodeType)
|
await evalNode(startingNode, 'Formulas', descendentOfNodeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
tradingSystem.evalUserCode = function (startingNode, descendentOfNodeType) {
|
tradingSystem.evalUserCode = function (startingNode, descendentOfNodeType) {
|
||||||
@@ -203,13 +204,13 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
buildDynamicIndicators()
|
buildDynamicIndicators()
|
||||||
|
|
||||||
/* Run the Trigger Stage */
|
/* Run the Trigger Stage */
|
||||||
tradingStagesModuleObject.runTriggerStage()
|
await tradingStagesModuleObject.runTriggerStage()
|
||||||
|
|
||||||
/* Run the Open Stage */
|
/* Run the Open Stage */
|
||||||
await tradingStagesModuleObject.runOpenStage()
|
await tradingStagesModuleObject.runOpenStage()
|
||||||
|
|
||||||
/* Run the Manage Stage */
|
/* Run the Manage Stage */
|
||||||
tradingStagesModuleObject.runManageStage()
|
await tradingStagesModuleObject.runManageStage()
|
||||||
|
|
||||||
/* Run the Close Stage */
|
/* Run the Close Stage */
|
||||||
await tradingStagesModuleObject.runCloseStage()
|
await tradingStagesModuleObject.runCloseStage()
|
||||||
@@ -234,7 +235,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function evalNode(node, evaluating, descendentOfNodeType, isDescendent) {
|
async function evalNode(node, evaluating, descendentOfNodeType, isDescendent, parentNode) {
|
||||||
if (node === undefined) { return }
|
if (node === undefined) { return }
|
||||||
|
|
||||||
/* Verify if this node is descendent of the specified node type */
|
/* Verify if this node is descendent of the specified node type */
|
||||||
@@ -257,7 +258,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
if (node.code !== undefined) {
|
if (node.code !== undefined) {
|
||||||
/* We will eval this formula */
|
/* We will eval this formula */
|
||||||
if (isDescendent === true) {
|
if (isDescendent === true) {
|
||||||
evalFormula(node)
|
await evalFormula(node, parentNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,7 +273,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now we go down through all this node children */
|
/* Now we go down through all this node children */
|
||||||
let schemaDocument = TS.projects.foundations.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
let schemaDocument = SA.projects.foundations.globals.schemas.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
||||||
if (schemaDocument === undefined) { return }
|
if (schemaDocument === undefined) { return }
|
||||||
|
|
||||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||||
@@ -284,7 +285,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
case 'node': {
|
case 'node': {
|
||||||
if (property.name !== previousPropertyName) {
|
if (property.name !== previousPropertyName) {
|
||||||
if (node[property.name] !== undefined) {
|
if (node[property.name] !== undefined) {
|
||||||
evalNode(node[property.name], evaluating, descendentOfNodeType, isDescendent)
|
await evalNode(node[property.name], evaluating, descendentOfNodeType, isDescendent, node)
|
||||||
}
|
}
|
||||||
previousPropertyName = property.name
|
previousPropertyName = property.name
|
||||||
}
|
}
|
||||||
@@ -294,7 +295,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
if (node[property.name] !== undefined) {
|
if (node[property.name] !== undefined) {
|
||||||
let nodePropertyArray = node[property.name]
|
let nodePropertyArray = node[property.name]
|
||||||
for (let m = 0; m < nodePropertyArray.length; m++) {
|
for (let m = 0; m < nodePropertyArray.length; m++) {
|
||||||
evalNode(nodePropertyArray[m], evaluating, descendentOfNodeType, isDescendent)
|
await evalNode(nodePropertyArray[m], evaluating, descendentOfNodeType, isDescendent, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@@ -357,7 +358,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalCondition -> value = ' + value)
|
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalCondition -> value = ' + value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function evalFormula(node) {
|
async function evalFormula(node, parentNode) {
|
||||||
let value
|
let value
|
||||||
let errorMessage
|
let errorMessage
|
||||||
let docs
|
let docs
|
||||||
@@ -365,6 +366,10 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) {
|
|||||||
try {
|
try {
|
||||||
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> ' + node.name + ' -> code = ' + node.code)
|
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> ' + node.name + ' -> code = ' + node.code)
|
||||||
value = eval(node.code)
|
value = eval(node.code)
|
||||||
|
|
||||||
|
let response = await portfolioManagerClient.askPortfolioFormulaManager(parentNode, value)
|
||||||
|
value = response.value
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
/*
|
/*
|
||||||
One possible error is that the formula references a .previous that is undefined. This
|
One possible error is that the formula references a .previous that is undefined. This
|
||||||
|
|||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/* PMCommunicationModule - Trading Bot's Version.
|
||||||
|
* Fascilitates communications between the Portfolio Manager and its managed sessions.
|
||||||
|
* Session Key naming convention: name + type + id
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.newPMCommunicationModule_Trading = function (callerId) {
|
||||||
|
const MODULE_NAME = 'PM Communication Module - Trading';
|
||||||
|
|
||||||
|
moduleObj = {
|
||||||
|
beginListening: beginListening,
|
||||||
|
getQuoteAssetBalance: getQuoteAssetBalance
|
||||||
|
}
|
||||||
|
|
||||||
|
const SESSION_ID = callerId;
|
||||||
|
|
||||||
|
return moduleObj;
|
||||||
|
|
||||||
|
|
||||||
|
/* Listeners Section: */
|
||||||
|
function beginListening() {
|
||||||
|
TS.projects.foundations.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.listenToEvent(
|
||||||
|
SESSION_ID,
|
||||||
|
'Quote Asset Balance Reply',
|
||||||
|
undefined,
|
||||||
|
SESSION_ID,
|
||||||
|
undefined,
|
||||||
|
gotQuoteAssetBalance)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* eventsCallBack Section: */
|
||||||
|
function getQuoteAssetBalance() {
|
||||||
|
TS.projects.foundations.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(
|
||||||
|
SESSION_ID,
|
||||||
|
'Quote Asset Balance',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotQuoteAssetBalance() {
|
||||||
|
let ret = arguments[0].event;
|
||||||
|
console.log("Quote Asset Balance=>" + ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,6 +48,9 @@
|
|||||||
TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||||
TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY)
|
TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY)
|
||||||
|
|
||||||
|
/* We will store the PMCommunicationModule Object: */
|
||||||
|
TS.projects.foundations.globals.processVariables.PM_COMMUNICATION_MODULE = TS.projects.algorithmicTrading.botModules.PMCommunicationModule_Trading.newPMCommunicationModule_Trading(VARIABLES_BY_PROCESS_INDEX.SESSION_KEY);
|
||||||
|
|
||||||
/* Listen to event to start or stop the session. */
|
/* Listen to event to start or stop the session. */
|
||||||
TS.projects.foundations.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.listenToEvent(
|
TS.projects.foundations.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.listenToEvent(
|
||||||
TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||||
@@ -512,6 +515,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startBackTesting(message) {
|
function startBackTesting(message) {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,6 +584,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startLiveTrading() {
|
function startLiveTrading() {
|
||||||
|
/* Testing to be removed @PLUV: */
|
||||||
|
/*TS.projects.foundations.globals.processVariables.PM_COMMUNICATION_MODULE.beginListening();
|
||||||
|
TS.projects.foundations.globals.processVariables.PM_COMMUNICATION_MODULE.getQuoteAssetBalance();*/
|
||||||
|
/* End Testing */
|
||||||
return checkKey()
|
return checkKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ function newAlgorithmicTradingActionSwitch() {
|
|||||||
UI.projects.algorithmicTrading.functionLibraries.tradingSessionFunctions.stopSession(action.node, action.callBackFunction)
|
UI.projects.algorithmicTrading.functionLibraries.tradingSessionFunctions.stopSession(action.node, action.callBackFunction)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
console.log("[WARN] Action sent to Algorithmic-Trading Action Switch does not belong here. Verify at the App Schema file of the node that triggered this action that the actionProject is pointing to the right project. -> Action = " + action.name + " -> Action Node Name = " + action.node.name)
|
console.log("[WARN] Action sent to Algorithmic-Trading Action Switch does not belong here. Verify at the App Schema file of the node that triggered this action that the actionProject is pointing to the right project. -> Action = " + action.name + " -> Action Node Name = " + action.node.name)
|
||||||
}
|
}
|
||||||
|
|||||||
Loaded 100 of 855 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user