Compare commits
762 Commits
0.17.0
...
0.21.0.rc3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea3a0814fc | ||
|
|
680e1cbb42 | ||
|
|
2d37dec5ff | ||
|
|
3f4c306bd6 | ||
|
|
ac432495d7 | ||
|
|
12fb7c1a62 | ||
|
|
feb15a30a2 | ||
|
|
eb0f3970cf | ||
|
|
b82d15af76 | ||
|
|
32b38ee2d6 | ||
|
|
1d702f2142 | ||
|
|
4ae77ba8af | ||
|
|
3c72e1f8fb | ||
|
|
4bfe08d7c3 | ||
|
|
3a7ed8d194 | ||
|
|
4d204b3b36 | ||
|
|
39ee33aeff | ||
|
|
831cd21737 | ||
|
|
f92a172c7f | ||
|
|
a82bb588f4 | ||
|
|
a84bd5225c | ||
|
|
f2b9f3d5c8 | ||
|
|
7faf38c976 | ||
|
|
357b25e5ae | ||
|
|
8e307a3e4d | ||
|
|
f0acc11249 | ||
|
|
fa35d7d2f4 | ||
|
|
e65aba3c46 | ||
|
|
fab7b1083b | ||
|
|
d9161fb76a | ||
|
|
85b18ff5e7 | ||
|
|
3a8af5d0b0 | ||
|
|
1c545d3a2d | ||
|
|
120a5d08f9 | ||
|
|
b586cb0ba7 | ||
|
|
ae2205aeb5 | ||
|
|
2e25fc4161 | ||
|
|
ba89b2d091 | ||
|
|
aee8438924 | ||
|
|
a6ba841e57 | ||
|
|
8643228b51 | ||
|
|
de869973c7 | ||
|
|
ac57780607 | ||
|
|
630604bc6b | ||
|
|
eb5d220b5e | ||
|
|
3f076b00cd | ||
|
|
514f9452f3 | ||
|
|
068c343be0 | ||
|
|
500455fc72 | ||
|
|
1b4f128f55 | ||
|
|
1a3a8daf49 | ||
|
|
7fce8eab3a | ||
|
|
b4c9402737 | ||
|
|
8459347bdc | ||
|
|
f7bf17290c | ||
|
|
d908e48d61 | ||
|
|
a3a4687ebf | ||
|
|
4d48d5d854 | ||
|
|
83e6807fa0 | ||
|
|
ba96984048 | ||
|
|
591e5ec32e | ||
|
|
690de862e8 | ||
|
|
35810ce2bf | ||
|
|
6c52f2ff72 | ||
|
|
d663bea5e6 | ||
|
|
1ea4521d0c | ||
|
|
c4153c0bbe | ||
|
|
ae8b249dc2 | ||
|
|
9500f0aae3 | ||
|
|
be3da6396f | ||
|
|
330926c167 | ||
|
|
cbcc00c929 | ||
|
|
d03b74f754 | ||
|
|
ec21d5af21 | ||
|
|
70c7315ae0 | ||
|
|
4fa1f0ab17 | ||
|
|
39e502faae | ||
|
|
0280bc52e0 | ||
|
|
dee47864c4 | ||
|
|
17623f71d4 | ||
|
|
7453131858 | ||
|
|
e822fb50d8 | ||
|
|
e2bca47421 | ||
|
|
7987cb794b | ||
|
|
7483e2c942 | ||
|
|
e6129eb492 | ||
|
|
b10aca2de1 | ||
|
|
02cbad59de | ||
|
|
ccb87d337c | ||
|
|
63a49983eb | ||
|
|
81dd622fdb | ||
|
|
9a49b1c41d | ||
|
|
b059506afa | ||
|
|
13c17e1526 | ||
|
|
8e3217a921 | ||
|
|
aed7c7436a | ||
|
|
7f3edad119 | ||
|
|
7fd9c82ae8 | ||
|
|
f3c7052f30 | ||
|
|
326d90a5e4 | ||
|
|
cccc47311b | ||
|
|
5c03167948 | ||
|
|
87b6d76c32 | ||
|
|
abfa03474c | ||
|
|
5bc734b2e5 | ||
|
|
814b70ffd8 | ||
|
|
1e18bfdea4 | ||
|
|
200b66d088 | ||
|
|
cbd01074ba | ||
|
|
1582fa1964 | ||
|
|
a9b6d11ade | ||
|
|
c4b6324e74 | ||
|
|
9432ea80be | ||
|
|
f412b4c158 | ||
|
|
547a3bf4e7 | ||
|
|
e97dc9d3cb | ||
|
|
efae14592e | ||
|
|
1d06495629 | ||
|
|
ffdfdb94ab | ||
|
|
8d7e97a26e | ||
|
|
f8b8f6a343 | ||
|
|
4967342362 | ||
|
|
9893847991 | ||
|
|
18e9640d99 | ||
|
|
58ea736ed6 | ||
|
|
b4bdc45a6b | ||
|
|
fa07b8d51b | ||
|
|
e121a8585e | ||
|
|
adef519583 | ||
|
|
08f09b4761 | ||
|
|
2a89c90e0b | ||
|
|
ce5fa379ec | ||
|
|
d4d4a9b1f1 | ||
|
|
d0b5b449b2 | ||
|
|
bad6938d1a | ||
|
|
48e28eff9b | ||
|
|
f87163413b | ||
|
|
52a9f2742b | ||
|
|
7f07fbefbc | ||
|
|
93660c6838 | ||
|
|
3ebadbcda9 | ||
|
|
3df3e0d681 | ||
|
|
4a3c09187a | ||
|
|
76f8d33d81 | ||
|
|
6cc6637454 | ||
|
|
d7f8a7fde3 | ||
|
|
80eb9c2c64 | ||
|
|
bd45e3b19a | ||
|
|
b866b33dee | ||
|
|
8994bdacbd | ||
|
|
f3b403d346 | ||
|
|
5ad4167512 | ||
|
|
ca67a7a4e9 | ||
|
|
64ef8b14b4 | ||
|
|
912c6f6231 | ||
|
|
6f1351fbbb | ||
|
|
f75dc0271d | ||
|
|
1fb8716231 | ||
|
|
ed212440b5 | ||
|
|
1528288b59 | ||
|
|
7c936e7f60 | ||
|
|
ff268a7526 | ||
|
|
e9804aedff | ||
|
|
e95132ddc3 | ||
|
|
bb0f69d074 | ||
|
|
645de384e3 | ||
|
|
15ecdeb3ba | ||
|
|
04ea3addc4 | ||
|
|
7e64f2e988 | ||
|
|
40fbf1c761 | ||
|
|
a85968eadb | ||
|
|
efc63669a6 | ||
|
|
076f9cd095 | ||
|
|
fdbc936dc9 | ||
|
|
18e459e19e | ||
|
|
064363df78 | ||
|
|
f8cc05b54e | ||
|
|
9baca6758d | ||
|
|
b39d165913 | ||
|
|
bc3ad64619 | ||
|
|
0bd2ac5353 | ||
|
|
03e2af8bd9 | ||
|
|
82b85d1d6c | ||
|
|
17c7ca239a | ||
|
|
ef59b6b650 | ||
|
|
d1a7a7b85c | ||
|
|
3d72eb475a | ||
|
|
b50489eb96 | ||
|
|
8773e32cd6 | ||
|
|
f438ccbcb1 | ||
|
|
f829b486d1 | ||
|
|
06e52e600e | ||
|
|
f0636b8748 | ||
|
|
c629282ec4 | ||
|
|
7d934e7246 | ||
|
|
8efcaeb768 | ||
|
|
cf0b670932 | ||
|
|
3949d39478 | ||
|
|
5718d6bbaf | ||
|
|
f3146ef6f9 | ||
|
|
255ea69977 | ||
|
|
9af34ba51c | ||
|
|
1cf634afa2 | ||
|
|
d7fc364ff4 | ||
|
|
aebd089ca5 | ||
|
|
ae7f163372 | ||
|
|
ed9f56448f | ||
|
|
ccd5fd44cf | ||
|
|
c5252d0f43 | ||
|
|
ede1432936 | ||
|
|
c3c9ceb1cc | ||
|
|
6fe93e18c7 | ||
|
|
c988080990 | ||
|
|
a26e65f418 | ||
|
|
e66f68d36c | ||
|
|
cb4d934ba5 | ||
|
|
6962c76412 | ||
|
|
b0d25a154a | ||
|
|
e22aecb0d1 | ||
|
|
32bd827b25 | ||
|
|
e399a8c613 | ||
|
|
b90d8e32f1 | ||
|
|
c81026ddb1 | ||
|
|
dd72048320 | ||
|
|
ad604aed09 | ||
|
|
31b7b9a6a0 | ||
|
|
745784fc97 | ||
|
|
fdee06bbf2 | ||
|
|
816c517f0f | ||
|
|
49f24d128b | ||
|
|
8223729e1e | ||
|
|
2d6b9422c6 | ||
|
|
3c0e85e2c0 | ||
|
|
490c707eb6 | ||
|
|
7c1b56f3a9 | ||
|
|
3e9f797949 | ||
|
|
f3de758363 | ||
|
|
90e46cb39c | ||
|
|
fe77534c03 | ||
|
|
1f135e41cd | ||
|
|
147c12dddf | ||
|
|
3dfdde130a | ||
|
|
255a36c280 | ||
|
|
66f646ac66 | ||
|
|
e53f3032bb | ||
|
|
3b4cd812ae | ||
|
|
ac5da46fb2 | ||
|
|
497a6f1df9 | ||
|
|
1fd08a5912 | ||
|
|
9676f02497 | ||
|
|
42dd64e413 | ||
|
|
c3ab796734 | ||
|
|
a782d623f0 | ||
|
|
48b88e5241 | ||
|
|
a47a512808 | ||
|
|
aff7a82664 | ||
|
|
2d237fe2ef | ||
|
|
c944c61747 | ||
|
|
0c8b24378d | ||
|
|
90ba6ee6a0 | ||
|
|
8d877e8a35 | ||
|
|
c5b1eb7f5b | ||
|
|
46d60880eb | ||
|
|
0c36827368 | ||
|
|
2b1bb35c5c | ||
|
|
d3824bbb38 | ||
|
|
670ba5d32e | ||
|
|
64c91ec9e3 | ||
|
|
1fda6f0745 | ||
|
|
f8e596b9d8 | ||
|
|
254645773c | ||
|
|
e79adbbc5f | ||
|
|
75e69f02e8 | ||
|
|
6fc837db51 | ||
|
|
2923a125db | ||
|
|
527572c3eb | ||
|
|
a7ba6e4a5d | ||
|
|
e31ad22f50 | ||
|
|
813ed6018d | ||
|
|
0454ef3726 | ||
|
|
afedcdf0d8 | ||
|
|
9f3aeb22d9 | ||
|
|
59268e978a | ||
|
|
b9a2fa4015 | ||
|
|
3c8577b853 | ||
|
|
0aa3d2a818 | ||
|
|
fbd0d46e8a | ||
|
|
c4e056929d | ||
|
|
84e59a11f1 | ||
|
|
9fcd5d67e4 | ||
|
|
ccf505a480 | ||
|
|
d1d1c49009 | ||
|
|
232a5c392e | ||
|
|
9c6248f3ba | ||
|
|
6841697917 | ||
|
|
81817309d3 | ||
|
|
025ef5a0f1 | ||
|
|
9a4e4d0443 | ||
|
|
c9c6bcaabe | ||
|
|
144f516700 | ||
|
|
c17ffc1e9c | ||
|
|
0d4137d21e | ||
|
|
0c5db55d55 | ||
|
|
bd4a4c2753 | ||
|
|
f399fcd624 | ||
|
|
08e40e2d78 | ||
|
|
2898f9d379 | ||
|
|
dfea8df7c9 | ||
|
|
a5320a0f37 | ||
|
|
b68084b9ac | ||
|
|
3b24d7df83 | ||
|
|
b3107bb603 | ||
|
|
08b7e891a7 | ||
|
|
57421d14d0 | ||
|
|
0cf0860a3d | ||
|
|
327c052456 | ||
|
|
033ba2cb66 | ||
|
|
cc36428260 | ||
|
|
6da68ab271 | ||
|
|
be01851ef7 | ||
|
|
20915457ff | ||
|
|
2385cd445b | ||
|
|
0429e842b5 | ||
|
|
f68189b54e | ||
|
|
dcf83031d1 | ||
|
|
ef7e9dd336 | ||
|
|
ae0655028f | ||
|
|
166c576c94 | ||
|
|
7190cf8e77 | ||
|
|
2ef9bfed20 | ||
|
|
0191fa58c8 | ||
|
|
4c3313b01c | ||
|
|
5278b53218 | ||
|
|
4ea770068b | ||
|
|
91bd38a851 | ||
|
|
163f4e359c | ||
|
|
90592d3e3d | ||
|
|
62fcdf2a92 | ||
|
|
48821b5101 | ||
|
|
3b129253a3 | ||
|
|
48760849ec | ||
|
|
9c1ca07c40 | ||
|
|
774ad45efb | ||
|
|
299e9ce6b8 | ||
|
|
219f33f0d1 | ||
|
|
58a704b84c | ||
|
|
b58cfbcb91 | ||
|
|
1e325d9645 | ||
|
|
ad5a4389a2 | ||
|
|
e4fba0ffb7 | ||
|
|
e584a9673f | ||
|
|
b888802e05 | ||
|
|
25c599d040 | ||
|
|
fb866a937b | ||
|
|
aa95e03eb9 | ||
|
|
cf1d0f38ad | ||
|
|
fca982c609 | ||
|
|
747bf80474 | ||
|
|
4f7fd65c8b | ||
|
|
6045063e78 | ||
|
|
0ec9cd4ad2 | ||
|
|
4268513653 | ||
|
|
7654eef110 | ||
|
|
b301ba1f57 | ||
|
|
95509f2000 | ||
|
|
49ab09101b | ||
|
|
40d9e15126 | ||
|
|
a141695b2b | ||
|
|
d01e67a159 | ||
|
|
c34df3eea4 | ||
|
|
56bcbb0f8e | ||
|
|
51f1aa3106 | ||
|
|
d7e419127c | ||
|
|
27fab0d54f | ||
|
|
091e93c831 | ||
|
|
bb6b2da267 | ||
|
|
7abe2d5eee | ||
|
|
7b015faae9 | ||
|
|
e834154030 | ||
|
|
256a521bf1 | ||
|
|
a626f994bf | ||
|
|
76dda688b1 | ||
|
|
163a6a20e5 | ||
|
|
3d136aa0a4 | ||
|
|
ff3057de5d | ||
|
|
7045018d86 | ||
|
|
a55f963e52 | ||
|
|
8dfe2b70b2 | ||
|
|
fdbb569c3e | ||
|
|
cc3e63f1de | ||
|
|
a48e246aa0 | ||
|
|
6eba6cac0b | ||
|
|
bd706ebbd1 | ||
|
|
abbf138cfb | ||
|
|
de346a3eba | ||
|
|
99e1de58bc | ||
|
|
5344a80535 | ||
|
|
0b09a74d37 | ||
|
|
e21745ac9d | ||
|
|
593861eac6 | ||
|
|
53dead9c29 | ||
|
|
f64e2ba7d5 | ||
|
|
80515d2a92 | ||
|
|
4d72afb54b | ||
|
|
06fcaa3095 | ||
|
|
de88764e93 | ||
|
|
9051e1f3e2 | ||
|
|
ba93e6a2d1 | ||
|
|
7e5e229f48 | ||
|
|
b9915e7ecf | ||
|
|
3e51c61dbf | ||
|
|
591e512327 | ||
|
|
fc5db474b7 | ||
|
|
c083aec8e8 | ||
|
|
1ce3b81d01 | ||
|
|
89cd10b3ce | ||
|
|
712297480c | ||
|
|
6ddccaaa9b | ||
|
|
1dcf2c4326 | ||
|
|
f0a8ea644b | ||
|
|
fb6ef26a24 | ||
|
|
00b34d7fbd | ||
|
|
8329ea2b9b | ||
|
|
da0a87a735 | ||
|
|
7aeca39c46 | ||
|
|
e1751c065c | ||
|
|
e5151cb915 | ||
|
|
24e3c7f89a | ||
|
|
987cb9978d | ||
|
|
274d21795f | ||
|
|
0d2c2b0681 | ||
|
|
1eff48facb | ||
|
|
17bd7512ff | ||
|
|
16141ecb94 | ||
|
|
34f381bc25 | ||
|
|
24292dbc11 | ||
|
|
24a2f5b8f0 | ||
|
|
0e6f754af9 | ||
|
|
fb85f008fa | ||
|
|
85fb4a933d | ||
|
|
d3ace6d63f | ||
|
|
205eed8350 | ||
|
|
5bf40e2256 | ||
|
|
7c28e4eace | ||
|
|
a882f7a55f | ||
|
|
9aba77db74 | ||
|
|
c9e5fbb09b | ||
|
|
65f25a1e5a | ||
|
|
e0dd5d9d1d | ||
|
|
737db25b6e | ||
|
|
bea702269c | ||
|
|
d78da8a9bf | ||
|
|
ed8153ff8b | ||
|
|
f7ce100180 | ||
|
|
72291d65c9 | ||
|
|
0d3f57a78d | ||
|
|
04fb0e2c2d | ||
|
|
155fec0a6b | ||
|
|
d90044cd52 | ||
|
|
62bd4eb211 | ||
|
|
677c427b16 | ||
|
|
52b0716571 | ||
|
|
04b662ea11 | ||
|
|
db052b17ea | ||
|
|
e300273e71 | ||
|
|
c5f2eafc90 | ||
|
|
90e4d6469d | ||
|
|
1e7773eb16 | ||
|
|
3c89c8cc46 | ||
|
|
74086dae2b | ||
|
|
66403f1876 | ||
|
|
3a4cd3ae24 | ||
|
|
4ffc1f613e | ||
|
|
dfbba84400 | ||
|
|
77864e6cf4 | ||
|
|
4d12251806 | ||
|
|
0c9f9b695b | ||
|
|
a4a2bf7ae9 | ||
|
|
d0a04cde49 | ||
|
|
69685b9dcc | ||
|
|
b308a3eb4e | ||
|
|
bfa40bd360 | ||
|
|
b0e2904c24 | ||
|
|
ce506bdf65 | ||
|
|
922cc037bf | ||
|
|
8252ada1f9 | ||
|
|
a2d2f8bb8c | ||
|
|
7c5f61d6a6 | ||
|
|
841e18a08c | ||
|
|
dbc7fef7f5 | ||
|
|
cbfe3cb2dc | ||
|
|
5fcd25def1 | ||
|
|
fe3f5f69ae | ||
|
|
2395fbbdaa | ||
|
|
960b26c7a2 | ||
|
|
28ac3504d6 | ||
|
|
ecc00bdd26 | ||
|
|
e7946451d6 | ||
|
|
9b34600c8e | ||
|
|
884610861b | ||
|
|
d9bd3d6460 | ||
|
|
38375be5c3 | ||
|
|
91d951ac42 | ||
|
|
d79a45ff32 | ||
|
|
818251fc85 | ||
|
|
75abd1f44a | ||
|
|
f55df3b18b | ||
|
|
5dbfdefae8 | ||
|
|
e5584440ce | ||
|
|
d5e9d5d045 | ||
|
|
3208a014ff | ||
|
|
874c12ad2d | ||
|
|
22d8075c53 | ||
|
|
baebba1159 | ||
|
|
04748b4cda | ||
|
|
a471afe206 | ||
|
|
5d0a01d0d0 | ||
|
|
9e1272e97c | ||
|
|
aeebd8840d | ||
|
|
55d3b012e5 | ||
|
|
a6e1e18244 | ||
|
|
46d7a925bb | ||
|
|
5929ab7689 | ||
|
|
fffb7b500a | ||
|
|
cb14640a82 | ||
|
|
d65054e015 | ||
|
|
5d5060eca6 | ||
|
|
9ff351532a | ||
|
|
59a6f447ec | ||
|
|
1887b5e934 | ||
|
|
33758bfff5 | ||
|
|
2d5beb1f91 | ||
|
|
5fd0e7d028 | ||
|
|
ef0c4be067 | ||
|
|
ac3aba7c7d | ||
|
|
0fdb57a181 | ||
|
|
3e7b5df287 | ||
|
|
3cd16cf368 | ||
|
|
a58adc862e | ||
|
|
7d88f80a9b | ||
|
|
09be02f70a | ||
|
|
50fcdd3a34 | ||
|
|
dee36491c5 | ||
|
|
903612ac6c | ||
|
|
ce705054fa | ||
|
|
c589616883 | ||
|
|
58309f275f | ||
|
|
edf4e4f24e | ||
|
|
b3e0b5b586 | ||
|
|
68802989bc | ||
|
|
70887d72e2 | ||
|
|
1922225042 | ||
|
|
0bdc3010d8 | ||
|
|
1df37e6e4d | ||
|
|
e9ed416654 | ||
|
|
03c42b5b87 | ||
|
|
e055e6d2c2 | ||
|
|
29780821e8 | ||
|
|
f10ee13901 | ||
|
|
cdfc4a35b2 | ||
|
|
eb762c8bfe | ||
|
|
83abfef830 | ||
|
|
54137ad023 | ||
|
|
4be6bfafaa | ||
|
|
9ba6d489f3 | ||
|
|
af4bd40853 | ||
|
|
84fa0d1940 | ||
|
|
938e13a429 | ||
|
|
dc364daffd | ||
|
|
1cadfecd4b | ||
|
|
5b26667fd5 | ||
|
|
899caf9449 | ||
|
|
e6063f2ddf | ||
|
|
46486f82d9 | ||
|
|
0089762955 | ||
|
|
2bd60c0747 | ||
|
|
db6cd21504 | ||
|
|
f40499e550 | ||
|
|
67a85b9831 | ||
|
|
cb3384b3b2 | ||
|
|
ac51a30f98 | ||
|
|
91fe02cdc8 | ||
|
|
76042be7c3 | ||
|
|
d3f55a0905 | ||
|
|
efaef8fe09 | ||
|
|
8757a24d89 | ||
|
|
63785f039c | ||
|
|
d6689ee700 | ||
|
|
787daf6005 | ||
|
|
23aeee5a9c | ||
|
|
70c6cad0e3 | ||
|
|
6b1bf3b395 | ||
|
|
f5216f6047 | ||
|
|
15654a3082 | ||
|
|
baff0cba38 | ||
|
|
c4ee098bb7 | ||
|
|
612b8ca3d7 | ||
|
|
c43a9fd554 | ||
|
|
6c68a21e4f | ||
|
|
db02b33e09 | ||
|
|
2df6baa7a7 | ||
|
|
fc7bd63039 | ||
|
|
959a09cc92 | ||
|
|
366ecefbaa | ||
|
|
a2b30f35fc | ||
|
|
8bceda8134 | ||
|
|
bae1067015 | ||
|
|
116dca3e6f | ||
|
|
b448394077 | ||
|
|
09f407f553 | ||
|
|
0479118efc | ||
|
|
c93411b1e7 | ||
|
|
31283f1424 | ||
|
|
93c6597cf4 | ||
|
|
4446c745a8 | ||
|
|
38e90fe309 | ||
|
|
f5489467e5 | ||
|
|
ab0bc5a3fa | ||
|
|
412634cb57 | ||
|
|
a0ddbb9ec9 | ||
|
|
a803705ddc | ||
|
|
75a358c616 | ||
|
|
493ba18362 | ||
|
|
5e4fca4ea4 | ||
|
|
d289783b67 | ||
|
|
ac84fc2b65 | ||
|
|
40b3d3b3ef | ||
|
|
50a9e13f9b | ||
|
|
66bff01b45 | ||
|
|
9691234b7e | ||
|
|
ddeabdd048 | ||
|
|
3ed45ab98c | ||
|
|
ca08e7051e | ||
|
|
1fb21b8b45 | ||
|
|
c581ea8661 | ||
|
|
f19d1958c5 | ||
|
|
9c99be510b | ||
|
|
7a08cdcb1c | ||
|
|
f24ddfd467 | ||
|
|
23a8ea5636 | ||
|
|
2c04d3c250 | ||
|
|
337454b646 | ||
|
|
b7f46ebe75 | ||
|
|
10773f96a7 | ||
|
|
b97a8275d4 | ||
|
|
081bdca71e | ||
|
|
62959ca38b | ||
|
|
fe68bc31c3 | ||
|
|
3d2c791ff1 | ||
|
|
d40ce52139 | ||
|
|
122891c29b | ||
|
|
c1d9918abe | ||
|
|
d93b1fc686 | ||
|
|
02c5cac26f | ||
|
|
6566377740 | ||
|
|
db6b2f3ae1 | ||
|
|
c31210b96d | ||
|
|
dcc6f2a18f | ||
|
|
0c0666caa0 | ||
|
|
243eeadfd6 | ||
|
|
9ba5b49d8a | ||
|
|
c870bd414e | ||
|
|
4b01e92509 | ||
|
|
513a090cdc | ||
|
|
abe79d1427 | ||
|
|
b81968dc20 | ||
|
|
66cc546a30 | ||
|
|
6e899ac55f | ||
|
|
6b52384024 | ||
|
|
0a1d8db357 | ||
|
|
6f68ddb505 | ||
|
|
4f59abf189 | ||
|
|
5c441f4ddb | ||
|
|
be023aba8d | ||
|
|
53990201bc | ||
|
|
37783d685f | ||
|
|
25fdcaca8b | ||
|
|
ce6e7c1359 | ||
|
|
91167665b1 | ||
|
|
f374345860 | ||
|
|
d3b50cb92e | ||
|
|
a58194bdb0 | ||
|
|
5f3484ac59 | ||
|
|
e14b74fdbf | ||
|
|
56f28859b7 | ||
|
|
f3cdb3b787 | ||
|
|
b35f6b0a94 | ||
|
|
5574cfef59 | ||
|
|
c3015583ce | ||
|
|
7cc2c930ed | ||
|
|
2662bf19df | ||
|
|
62e3fe2345 | ||
|
|
7d25d171e2 | ||
|
|
c5859c7254 | ||
|
|
dd7b4b8310 | ||
|
|
93551a65b8 | ||
|
|
7eafbabe65 | ||
|
|
43dd948476 | ||
|
|
75e7f2d22c | ||
|
|
26662eed9e | ||
|
|
121b1d0951 | ||
|
|
398036d77e | ||
|
|
59d5fcf88c | ||
|
|
1f8e48b374 | ||
|
|
7bf19b1232 | ||
|
|
1590b8c7e5 | ||
|
|
22522fc05f | ||
|
|
c9b59fab1f | ||
|
|
69152e087a | ||
|
|
652e572b56 | ||
|
|
65c89f54dc | ||
|
|
edf5c0e83b | ||
|
|
a4abbfe126 | ||
|
|
7b28bcef15 | ||
|
|
8042ac876e | ||
|
|
82bc907088 | ||
|
|
e2b572d9e2 | ||
|
|
e71596dc45 | ||
|
|
c3be58db43 | ||
|
|
3d77a12aa9 | ||
|
|
36deb8da71 | ||
|
|
05ee8c0e36 | ||
|
|
5ca55a5585 | ||
|
|
1b330a8c55 | ||
|
|
696678c981 | ||
|
|
20aec3cfca | ||
|
|
4ded37e71e | ||
|
|
0674ed846c | ||
|
|
3107152f5b | ||
|
|
5b19528662 | ||
|
|
357773c631 | ||
|
|
5e43d074c3 | ||
|
|
08bdcd52b8 | ||
|
|
0b8522be50 | ||
|
|
c02a7fe763 | ||
|
|
dcd5bdeb00 | ||
|
|
562b4f0415 | ||
|
|
6160a3fdff | ||
|
|
0779da6d24 | ||
|
|
740624ba01 | ||
|
|
2969cc9993 | ||
|
|
9a8c3a0447 | ||
|
|
e817382efd | ||
|
|
422d1feb3e | ||
|
|
2b0cb2b0a5 | ||
|
|
705d09d3d0 | ||
|
|
9114d86ecd | ||
|
|
ad4a950b56 | ||
|
|
bd480e0c6b | ||
|
|
af3415b040 | ||
|
|
b4a96bd840 | ||
|
|
9d8d421384 | ||
|
|
f6ffc00748 | ||
|
|
e35016f07d | ||
|
|
af8e2523a8 | ||
|
|
492df94b2a | ||
|
|
b62f7e2820 | ||
|
|
5cc2fc157c | ||
|
|
266c049f2d | ||
|
|
4e848c8cb5 | ||
|
|
efff1ac4a1 | ||
|
|
fc64a75fbd |
@@ -5,6 +5,11 @@ engines:
|
||||
enabled: false
|
||||
eslint:
|
||||
enabled: true
|
||||
checks:
|
||||
import/extensions:
|
||||
enabled: false
|
||||
import/no-extraneous-dependencies:
|
||||
enabled: false
|
||||
config:
|
||||
config: superset/assets/.eslintrc
|
||||
pep8:
|
||||
|
||||
@@ -1 +1 @@
|
||||
repo_token: eESbYiv4An6KEvjpmguDs4L7YkubXbqn1
|
||||
repo_token: 4P9MpvLrZfJKzHdGZsdV3MzO43OZJgYFn
|
||||
|
||||
5
.gitignore
vendored
@@ -24,6 +24,8 @@ app.db
|
||||
*.bak
|
||||
.idea
|
||||
*.sqllite
|
||||
.vscode
|
||||
.python-version
|
||||
|
||||
# Node.js, webpack artifacts
|
||||
*.entry.js
|
||||
@@ -32,3 +34,6 @@ node_modules
|
||||
npm-debug.log
|
||||
yarn.lock
|
||||
superset/assets/version_info.json
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[pycodestyle]
|
||||
max-line-length = 90
|
||||
407
.pylintrc
Normal file
@@ -0,0 +1,407 @@
|
||||
[MASTER]
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not
|
||||
# paths.
|
||||
ignore=CVS
|
||||
|
||||
# Add files or directories matching the regex patterns to the blacklist. The
|
||||
# regex matches against base names, not paths.
|
||||
ignore-patterns=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Use multiple processes to speed up Pylint.
|
||||
jobs=1
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code
|
||||
extension-pkg-whitelist=
|
||||
|
||||
# Allow optimization of some AST trees. This will activate a peephole AST
|
||||
# optimizer, which will apply various small optimizations. For instance, it can
|
||||
# be used to obtain the result of joining multiple strings with the addition
|
||||
# operator. Joining a lot of strings can lead to a maximum recursion error in
|
||||
# Pylint and this flag can prevent that. It has one side effect, the resulting
|
||||
# AST will be different than the one from reality. This option is deprecated
|
||||
# and it will be removed in Pylint 2.0.
|
||||
optimize-ast=no
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
|
||||
confidence=
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
#enable=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once).You can also use "--disable=all" to
|
||||
# disable everything first and then reenable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
disable=standarderror-builtin,long-builtin,dict-view-method,intern-builtin,suppressed-message,no-absolute-import,unpacking-in-except,apply-builtin,delslice-method,indexing-exception,old-raise-syntax,print-statement,cmp-builtin,reduce-builtin,useless-suppression,coerce-method,input-builtin,cmp-method,raw_input-builtin,nonzero-method,backtick,basestring-builtin,setslice-method,reload-builtin,oct-method,map-builtin-not-iterating,execfile-builtin,old-octal-literal,zip-builtin-not-iterating,buffer-builtin,getslice-method,metaclass-assignment,xrange-builtin,long-suffix,round-builtin,range-builtin-not-iterating,next-method-called,dict-iter-method,parameter-unpacking,unicode-builtin,unichr-builtin,import-star-module-level,raising-string,filter-builtin-not-iterating,old-ne-operator,using-cmp-argument,coerce-builtin,file-builtin,old-division,hex-method,invalid-unary-operand-type
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html. You can also give a reporter class, eg
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
output-format=text
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]". This option is deprecated
|
||||
# and it will be removed in Pylint 2.0.
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=yes
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details
|
||||
#msg-template=
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,j,k,ex,Run,_,d,e,v,o,l,x,ts
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata,d,fd
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name
|
||||
include-naming-hint=no
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Regular expression matching correct argument names
|
||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for argument names
|
||||
argument-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct method names
|
||||
method-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for method names
|
||||
method-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct variable names
|
||||
variable-rgx=[a-z_][a-z0-9_]{1,30}$
|
||||
|
||||
# Naming hint for variable names
|
||||
variable-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct inline iteration names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Naming hint for inline iteration names
|
||||
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Regular expression matching correct constant names
|
||||
const-rgx=(([A-Za-z_][A-Za-z0-9_]*)|(__.*__))$
|
||||
|
||||
# Naming hint for constant names
|
||||
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression matching correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Naming hint for class names
|
||||
class-name-hint=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression matching correct class attribute names
|
||||
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
|
||||
|
||||
# Naming hint for class attribute names
|
||||
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
|
||||
|
||||
# Regular expression matching correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Naming hint for module names
|
||||
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression matching correct attribute names
|
||||
attr-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for attribute names
|
||||
attr-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct function names
|
||||
function-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for function names
|
||||
function-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=10
|
||||
|
||||
|
||||
[ELIF]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=90
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
# List of optional constructs for which whitespace checking is disabled. `dict-
|
||||
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
|
||||
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
|
||||
# `empty-line` allows space-only lines.
|
||||
no-space-check=trailing-comma,dict-separator
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Ignore imports when computing similarities.
|
||||
ignore-imports=no
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it working
|
||||
# install python-enchant package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to indicated private dictionary in
|
||||
# --spelling-private-dict-file option instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis. It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=numpy,pandas,alembic.op,sqlalchemy,alembic.context,flask_appbuilder.security.sqla.PermissionView.role,flask_appbuilder.Model.metadata,flask_appbuilder.Base.metadata
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expectedly
|
||||
# not used).
|
||||
dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,_cb
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,future.builtins
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=mcs
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,_fields,_replace,_source,_make
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of boolean expressions in a if statement
|
||||
max-bool-expr=5
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=optparse
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=Exception
|
||||
15
.travis.yml
@@ -1,28 +1,26 @@
|
||||
|
||||
language: python
|
||||
services:
|
||||
- redis-server
|
||||
addons:
|
||||
code_climate:
|
||||
repo_token: 5f3a06c425eef7be4b43627d7d07a3e46c45bdc07155217825ff7c49cb6a470c
|
||||
apt:
|
||||
sources:
|
||||
- deadsnakes
|
||||
packages:
|
||||
- python3.5
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.wheelhouse/
|
||||
env:
|
||||
global:
|
||||
- TRAVIS_CACHE=$HOME/.travis_cache/
|
||||
- TRAVIS_NODE_VERSION="5.11"
|
||||
- TRAVIS_NODE_VERSION="7.10.0"
|
||||
matrix:
|
||||
- TOX_ENV=flake8
|
||||
- TOX_ENV=javascript
|
||||
- TOX_ENV=pylint
|
||||
- TOX_ENV=py34-postgres
|
||||
- TOX_ENV=py34-sqlite
|
||||
- TOX_ENV=py27-mysql
|
||||
- TOX_ENV=py27-sqlite
|
||||
before_install:
|
||||
- npm install -g npm@'>=3.9.5'
|
||||
- npm install -g npm@'>=5.4.1'
|
||||
before_script:
|
||||
- mysql -e 'drop database if exists superset; create database superset DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci' -u root
|
||||
- mysql -u root -e "CREATE USER 'mysqluser'@'localhost' IDENTIFIED BY 'mysqluserpassword';"
|
||||
@@ -33,5 +31,6 @@ before_script:
|
||||
install:
|
||||
- pip install --upgrade pip
|
||||
- pip install tox tox-travis
|
||||
- pip install --upgrade flake8
|
||||
- rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION
|
||||
script: tox -e $TOX_ENV
|
||||
|
||||
930
CHANGELOG.md
@@ -1,5 +1,927 @@
|
||||
## Change Log
|
||||
|
||||
### 0.20.5 (2017/11/06 07:18 +00:00)
|
||||
- [#3776](https://github.com/apache/incubator-superset/pull/3776) [flake8] Enabling flake8 linting (#3776) (@john-bodley)
|
||||
- [#3774](https://github.com/apache/incubator-superset/pull/3774) [sql-lab] Fixing Run Query tooltip (#3774) (@john-bodley)
|
||||
- [#3773](https://github.com/apache/incubator-superset/pull/3773) Fix dashboard export download (#3773) (@michellethomas)
|
||||
- [#3767](https://github.com/apache/incubator-superset/pull/3767) [time table] add tooltip to sparkline (#3767) (@williaster)
|
||||
- [#3748](https://github.com/apache/incubator-superset/pull/3748) Update to reflect new version of cryptography (#3748) (@SpyderRivera)
|
||||
- [#3763](https://github.com/apache/incubator-superset/pull/3763) docs: reword the FAQ regarding table changes (#3763) (@xrmx)
|
||||
- [#3764](https://github.com/apache/incubator-superset/pull/3764) add stackoverflow tag (#3764) (@dmigo)
|
||||
- [#3759](https://github.com/apache/incubator-superset/pull/3759) Add dummy file to fix symlink (#3759) (@mistercrunch)
|
||||
- [#3751](https://github.com/apache/incubator-superset/pull/3751) fix https://github.com/apache/incubator-superset/pull/3726 (#3751) (@graceguo-supercat)
|
||||
- [#3750](https://github.com/apache/incubator-superset/pull/3750) Consolidate all translation config (#3750) (@alanmcruickshank)
|
||||
- [#3726](https://github.com/apache/incubator-superset/pull/3726) Bumping react-select to rc10 (#3726) (@mistercrunch)
|
||||
- [#3741](https://github.com/apache/incubator-superset/pull/3741) Fix has_table method (#3741) (@mxmzdlv)
|
||||
- [#3736](https://github.com/apache/incubator-superset/pull/3736) Escape columns names for time grains - postgres (#3736) (@Ryanthegiantlion)
|
||||
- [#3739](https://github.com/apache/incubator-superset/pull/3739) Fix 3657 (#3739) (@baldoalessandro)
|
||||
- [#3733](https://github.com/apache/incubator-superset/pull/3733) Using indexOf instead of includes for isXAxisString (#3733) (@michellethomas)
|
||||
- [#3723](https://github.com/apache/incubator-superset/pull/3723) bump react-bootstrap version (#3723) (@graceguo-supercat)
|
||||
- [#3721](https://github.com/apache/incubator-superset/pull/3721) Add CRUD action to refresh table metadata (#3721) (@mistercrunch)
|
||||
- [#3720](https://github.com/apache/incubator-superset/pull/3720) Validate JSON in slice's params on save (#3720) (@mistercrunch)
|
||||
- [#3722](https://github.com/apache/incubator-superset/pull/3722) Fix box_plot NaN issue (#3722) (@mistercrunch)
|
||||
- [#3715](https://github.com/apache/incubator-superset/pull/3715) Update messages.po (#3715) (@magicansk)
|
||||
- [#3686](https://github.com/apache/incubator-superset/pull/3686) Missing the data of one province and two regions of China (#3686) (@roganw)
|
||||
- [#3685](https://github.com/apache/incubator-superset/pull/3685) Fix the ISO code description of region/province/department (#3685) (@roganw)
|
||||
- [#3662](https://github.com/apache/incubator-superset/pull/3662) Set logging level to debug for DummyStatsLogger (#3662) (@mistercrunch)
|
||||
- [#3692](https://github.com/apache/incubator-superset/pull/3692) fixes for bugs in #3689 (#3692) (@Mogball)
|
||||
- [#3703](https://github.com/apache/incubator-superset/pull/3703) add VIPKID to the orgs. (#3703) (@killpanda)
|
||||
- [#3696](https://github.com/apache/incubator-superset/pull/3696) changed metric heading from h1 to h3 (#3696) (@Mogball)
|
||||
- [#3713](https://github.com/apache/incubator-superset/pull/3713) [translation] added japanese support (#3713) (@xiaoyugit)
|
||||
- [#3663](https://github.com/apache/incubator-superset/pull/3663) [minor] fix label showing description in time_table's URL (#3663) (@mistercrunch)
|
||||
- [#3711](https://github.com/apache/incubator-superset/pull/3711) fix the slice permission issue after user click-edit new slice title (#3711) (@graceguo-supercat)
|
||||
- [#3701](https://github.com/apache/incubator-superset/pull/3701) [form-data] Quoting form data (#3701) (@john-bodley)
|
||||
- [#3698](https://github.com/apache/incubator-superset/pull/3698) fixing the datasource inconsistence but in visualize flow (#3698) (@graceguo-supercat)
|
||||
- [#3683](https://github.com/apache/incubator-superset/pull/3683) [cleanup] removing print() artefacts (#3683) (@mistercrunch)
|
||||
- [#3702](https://github.com/apache/incubator-superset/pull/3702) Add support for IE 11 for markup slices (#3702) (@jaylindquist)
|
||||
- [#3693](https://github.com/apache/incubator-superset/pull/3693) defaultSort should be false when no sort is necessary (#3693) (@michellethomas)
|
||||
- [#3586](https://github.com/apache/incubator-superset/pull/3586) [Feature] Percentage columns in Table Viz (#3586) (@Mogball)
|
||||
- [#3652](https://github.com/apache/incubator-superset/pull/3652) DI-1113. Authentication: Enable user impersonation for Superset to HiveServer2 using hive.server2.proxy.user (a.fernandez) (#3652) (@afernandez)
|
||||
- [#3664](https://github.com/apache/incubator-superset/pull/3664) [minor] fix padding in Time Table (#3664) (@mistercrunch)
|
||||
- [#3678](https://github.com/apache/incubator-superset/pull/3678) unit tests for OptionDescription component (#3678) (@Mogball)
|
||||
- [#3679](https://github.com/apache/incubator-superset/pull/3679) Avoid dividing by zero for sparkline in time table viz (#3679) (@michellethomas)
|
||||
- [#3680](https://github.com/apache/incubator-superset/pull/3680) Sqllab error troubleshooting (#3680) (@timifasubaa)
|
||||
- [#3653](https://github.com/apache/incubator-superset/pull/3653) Add a ColorPickerControl (#3653) (@mistercrunch)
|
||||
- [#3642](https://github.com/apache/incubator-superset/pull/3642) [New Viz] Partition Diagram (#3642) (@Mogball)
|
||||
- [#3665](https://github.com/apache/incubator-superset/pull/3665) Add description for running specific test (#3665) (@timifasubaa)
|
||||
- [#3661](https://github.com/apache/incubator-superset/pull/3661) Making the sort order for metrics pull from fd for time table viz (#3661) (@michellethomas)
|
||||
- [#3417](https://github.com/apache/incubator-superset/pull/3417) Make columns that return an exception on click unsortable. (#3417) (@aliavni)
|
||||
- [#3651](https://github.com/apache/incubator-superset/pull/3651) Adding sort time table (#3651) (@michellethomas)
|
||||
- [#3647](https://github.com/apache/incubator-superset/pull/3647) added aihello as superset user. (#3647) (@ganeshkrishnan1)
|
||||
- [#3646](https://github.com/apache/incubator-superset/pull/3646) Fix #3612 - reverse sign in difference calculation (#3646) (@mistercrunch)
|
||||
- [#3648](https://github.com/apache/incubator-superset/pull/3648) Fixing some warnings during tests (#3648) (@dennybiasiolli)
|
||||
|
||||
### 0.20.4 (2017/10/12 04:04 +00:00)
|
||||
- [#3645](https://github.com/apache/incubator-superset/pull/3645) [Translations] Restored lost French translations (#3645) (@Mogball)
|
||||
- [#3644](https://github.com/apache/incubator-superset/pull/3644) [sql lab] fix impersonation + template issue (#3644) (@mistercrunch)
|
||||
- [#3641](https://github.com/apache/incubator-superset/pull/3641) Pin moment.js library since 2.19.0 creates problem (#3641) (@mistercrunch)
|
||||
- [#3600](https://github.com/apache/incubator-superset/pull/3600) [time_table] adding support for URLs / links (#3600) (@mistercrunch)
|
||||
- [#3626](https://github.com/apache/incubator-superset/pull/3626) Set tooltip to show extent of sparkData (#3626) (@michellethomas)
|
||||
- [#3631](https://github.com/apache/incubator-superset/pull/3631) add explicit message display for 'Fetching Annotation Layer' error (#3631) (@graceguo-supercat)
|
||||
- [#3637](https://github.com/apache/incubator-superset/pull/3637) [bugfix] Template rendering failed: '_AppCtxGlobals' object has no attribute 'user' (#3637) (@mistercrunch)
|
||||
- [#3638](https://github.com/apache/incubator-superset/pull/3638) fix long title text wrapping in editable-title component (#3638) (@graceguo-supercat)
|
||||
- [#3625](https://github.com/apache/incubator-superset/pull/3625) [minor] proper tooltip on ControlHeader's instant re-render trigger (#3625) (@mistercrunch)
|
||||
- [#3634](https://github.com/apache/incubator-superset/pull/3634) add annotation option and a linear color map for heatmap viz. (#3634) (@xiaoyugit)
|
||||
- [#3633](https://github.com/apache/incubator-superset/pull/3633) [bugfix] empty From date filter NoneType error (#3633) (@mistercrunch)
|
||||
- [#3621](https://github.com/apache/incubator-superset/pull/3621) remove unused imports (#3621) (@xrmx)
|
||||
- [#3611](https://github.com/apache/incubator-superset/pull/3611) fixing date/time filter keys (#3611) (@Mogball)
|
||||
|
||||
### 0.20.2 (2017/10/06 07:46 +00:00)
|
||||
- [#3606](https://github.com/apache/incubator-superset/pull/3606) [bugfix] #3593 'Chart Options' panel is missing (#3606) (@mistercrunch)
|
||||
- [#3601](https://github.com/apache/incubator-superset/pull/3601) Removing git artifact (#3601) (@mistercrunch)
|
||||
- [#3599](https://github.com/apache/incubator-superset/pull/3599) [hotfix] fixing issues around new time_table viz (#3599) (@mistercrunch)
|
||||
- [#3598](https://github.com/apache/incubator-superset/pull/3598) [hofix] work around circular deps (#3598) (@mistercrunch)
|
||||
- [#3597](https://github.com/apache/incubator-superset/pull/3597) [time table] fix reversed ratio (#3597) (@mistercrunch)
|
||||
- [#3508](https://github.com/apache/incubator-superset/pull/3508) [Feature/Bugfix] Datepicker and time granularity options to dashboard filters (#3508) (@Mogball)
|
||||
- [#3596](https://github.com/apache/incubator-superset/pull/3596) updating react-alert dependency to v2.3.0 (#3596) (@dennybiasiolli)
|
||||
- [#3577](https://github.com/apache/incubator-superset/pull/3577) [translations] generating missing strings (#3577) (@mistercrunch)
|
||||
- [#3478](https://github.com/apache/incubator-superset/pull/3478) [Bugfix/Feature] Fixed slice render staggering on dashboard first load (#3478) (@Mogball)
|
||||
- [#3543](https://github.com/apache/incubator-superset/pull/3543) New "Time Series - Table" visualization (#3543) (@mistercrunch)
|
||||
- [#3587](https://github.com/apache/incubator-superset/pull/3587) [sql lab] fix numeric sort in data table (#3587) (@mistercrunch)
|
||||
- [#3594](https://github.com/apache/incubator-superset/pull/3594) Fxing bug in label generation for multiple groupbys (#3594) (@fabianmenges)
|
||||
- [#3591](https://github.com/apache/incubator-superset/pull/3591) update immutable.js to v3.8.2 (MIT license) (#3591) (@naoyak)
|
||||
- [#3571](https://github.com/apache/incubator-superset/pull/3571) [Feature] Copy-to-clipboard button in View Query (#3571) (@Mogball)
|
||||
- [#3585](https://github.com/apache/incubator-superset/pull/3585) Allow users to see query string when query returns no data (#3585) (@Mogball)
|
||||
- [#3582](https://github.com/apache/incubator-superset/pull/3582) [Bugfix]: Explore view does not respect custom timeout. (#3582) (@fabianmenges)
|
||||
- [#3584](https://github.com/apache/incubator-superset/pull/3584) Fixed creating new filter options in FilterBox (#3584) (@Mogball)
|
||||
- [#3562](https://github.com/apache/incubator-superset/pull/3562) Added custom pasteSelect to handle paste events (#3562) (@Mogball)
|
||||
- [#3569](https://github.com/apache/incubator-superset/pull/3569) Bumping React to 15.6.2 (MIT license) (#3569) (@mistercrunch)
|
||||
|
||||
### 0.20.1 (2017/10/03 07:04 +00:00)
|
||||
- [#3576](https://github.com/apache/incubator-superset/pull/3576) v0.20.1 (#3576) (@mistercrunch)
|
||||
- [#3572](https://github.com/apache/incubator-superset/pull/3572) After saving slice fixing redirect (#3572) (@michellethomas)
|
||||
- [#3565](https://github.com/apache/incubator-superset/pull/3565) Added label+percent and label+value display options to pie chart (#3565) (@Mogball)
|
||||
- [#3567](https://github.com/apache/incubator-superset/pull/3567) Removing yarn warnings during install (#3567) (@dennybiasiolli)
|
||||
- [#3563](https://github.com/apache/incubator-superset/pull/3563) [nvd3] fix single metric showing up in legend (#3563) (@mistercrunch)
|
||||
- [#3558](https://github.com/apache/incubator-superset/pull/3558) Add Pronto Tools to user list (#3558) (@zkan)
|
||||
- [#3553](https://github.com/apache/incubator-superset/pull/3553) Minor documentation fix (#3553) (@gaborhermann)
|
||||
- [#3545](https://github.com/apache/incubator-superset/pull/3545) CHANGELOG for 0.20.0 (#3545) (@mistercrunch)
|
||||
- [#3534](https://github.com/apache/incubator-superset/pull/3534) Explore update button labels (#3534) (@timifasubaa)
|
||||
- [#3547](https://github.com/apache/incubator-superset/pull/3547) Fixing missing messages.json file (#3547) (@mistercrunch)
|
||||
|
||||
### 0.20.0 (2017/09/28 04:26 +00:00)
|
||||
- [#3528](https://github.com/apache/incubator-superset/pull/3528) try to fix problem that chrome window not opening after ajax requrest (#3528) (@graceguo-supercat)
|
||||
- [#3521](https://github.com/apache/incubator-superset/pull/3521) Time Series Annotation Layers (#3521) (@graceguo-supercat)
|
||||
- [#3526](https://github.com/apache/incubator-superset/pull/3526) [explore] fix cached tooltip (#3526) (@mistercrunch)
|
||||
- [#3544](https://github.com/apache/incubator-superset/pull/3544) v0.20.0 (#3544) (@mistercrunch)
|
||||
- [#3506](https://github.com/apache/incubator-superset/pull/3506) setup: bump pandas to 0.20.3 (#3506) (@xrmx)
|
||||
- [#3066](https://github.com/apache/incubator-superset/pull/3066) Add support for column specific fillna to viz (#3066) (@xrmx)
|
||||
- [#3537](https://github.com/apache/incubator-superset/pull/3537) docs: QUERY_TIMEOUT_THRESHOLD is gone (#3537) (@xrmx)
|
||||
- [#3531](https://github.com/apache/incubator-superset/pull/3531) [style] no bold on dashboard widget headers (#3531) (@mistercrunch)
|
||||
- [#3532](https://github.com/apache/incubator-superset/pull/3532) Break word on InfoTooltip (#3532) (@michellethomas)
|
||||
- [#3473](https://github.com/apache/incubator-superset/pull/3473) Feature: Paired t-test table visualization (#3473) (@Mogball)
|
||||
- [#3513](https://github.com/apache/incubator-superset/pull/3513) Feature: query string API endpoint (#3513) (@Mogball)
|
||||
- [#3504](https://github.com/apache/incubator-superset/pull/3504) Feature: Display the verbose name for metrics within Charts and legend. (#3504) (@fabianmenges)
|
||||
- [#3527](https://github.com/apache/incubator-superset/pull/3527) Druid refresh metadata performance improvements (#3527) (@Mogball)
|
||||
- [#3466](https://github.com/apache/incubator-superset/pull/3466) Allow user update slice title in visualize flow (#3466) (@graceguo-supercat)
|
||||
- [#3467](https://github.com/apache/incubator-superset/pull/3467) allow user update slice name in dashboard view (#3467) (@graceguo-supercat)
|
||||
- [#3509](https://github.com/apache/incubator-superset/pull/3509) Add Table performance improvements (#3509) (@Mogball)
|
||||
- [#3499](https://github.com/apache/incubator-superset/pull/3499) Add metric warning (#3499) (@michellethomas)
|
||||
- [#3390](https://github.com/apache/incubator-superset/pull/3390) js translation -- performance improvment (#3390) (@graceguo-supercat)
|
||||
- [#3491](https://github.com/apache/incubator-superset/pull/3491) Remove repeated line (#3491) (@timifasubaa)
|
||||
- [#3497](https://github.com/apache/incubator-superset/pull/3497) Fix idna requirement (#3497) (@timifasubaa)
|
||||
- [#3495](https://github.com/apache/incubator-superset/pull/3495) update contributing.md (#3495) (@timifasubaa)
|
||||
- [#3500](https://github.com/apache/incubator-superset/pull/3500) Removing super() call from refactor (#3500) (@mistercrunch)
|
||||
- [#3493](https://github.com/apache/incubator-superset/pull/3493) Adding missing future imports (#3493) (@mistercrunch)
|
||||
- [#3494](https://github.com/apache/incubator-superset/pull/3494) Removing dependency on pythrifthiveapi (#3494) (@mistercrunch)
|
||||
- [#3474](https://github.com/apache/incubator-superset/pull/3474) [heatmap] account for bounds = 0 (#3474) (@mistercrunch)
|
||||
- [#3480](https://github.com/apache/incubator-superset/pull/3480) Improve code quality (#3480) (@timifasubaa)
|
||||
- [#3434](https://github.com/apache/incubator-superset/pull/3434) Feature/Fix: Get a full times_series for your filter instead of Topn for each point in time (#3434) (@fabianmenges)
|
||||
- [#3486](https://github.com/apache/incubator-superset/pull/3486) Getting datatype with its dialect (#3486) (@datinho)
|
||||
- [#3404](https://github.com/apache/incubator-superset/pull/3404) Feature: "Impersonate user" setting on Datasource (#3404) (@dmigo)
|
||||
- [#3484](https://github.com/apache/incubator-superset/pull/3484) Create CsvResponse to manage csv exports encoding (#3484) (@JulieRossi)
|
||||
- [#3469](https://github.com/apache/incubator-superset/pull/3469) Better installation docs (#3469) (@mistercrunch)
|
||||
- [#3475](https://github.com/apache/incubator-superset/pull/3475) viz: fix reversed stats_logger label (#3475) (@xrmx)
|
||||
- [#3477](https://github.com/apache/incubator-superset/pull/3477) docs: athena can be installed from pypi (#3477) (@xrmx)
|
||||
- [#3476](https://github.com/apache/incubator-superset/pull/3476) Miscvizcleanups (#3476) (@xrmx)
|
||||
- [#3435](https://github.com/apache/incubator-superset/pull/3435) Adding hook for CSRF exempting flask views. (#3435) (@fabianmenges)
|
||||
- [#3409](https://github.com/apache/incubator-superset/pull/3409) bugfix/3321 Ensure text appears on buttons inside tables (#3409) (@jeffcarey)
|
||||
- [#3415](https://github.com/apache/incubator-superset/pull/3415) Simple grammar and update to link (#3415) (@SpyderRivera)
|
||||
- [#3441](https://github.com/apache/incubator-superset/pull/3441) config: allow changing default options for writting csv (#3441) (@JulieRossi)
|
||||
- [#3425](https://github.com/apache/incubator-superset/pull/3425) Add shopee to user list. (#3425) (@xiaohanyu)
|
||||
- [#3458](https://github.com/apache/incubator-superset/pull/3458) Fixed filter removal bug (#3458) (@Mogball)
|
||||
- [#3424](https://github.com/apache/incubator-superset/pull/3424) fix encoding error in sql lab logging (#3424) (@graceguo-supercat)
|
||||
- [#3459](https://github.com/apache/incubator-superset/pull/3459) Sqllab dont send empty queries to db (#3459) (@timifasubaa)
|
||||
- [#3461](https://github.com/apache/incubator-superset/pull/3461) Fixed dashboard filters carrying over to explore slice (#3461) (@Mogball)
|
||||
- [#3436](https://github.com/apache/incubator-superset/pull/3436) Adding hook for external password store for databases (#3436) (@fabianmenges)
|
||||
- [#3460](https://github.com/apache/incubator-superset/pull/3460) Allow specifying sort criteria on Table viz (#3460) (@mistercrunch)
|
||||
- [#3456](https://github.com/apache/incubator-superset/pull/3456) [heatmap] numerous improvements (#3456) (@mistercrunch)
|
||||
- [#3431](https://github.com/apache/incubator-superset/pull/3431) fix https://github.com/apache/incubator-superset/issues/3430 (#3431) (@graceguo-supercat)
|
||||
- [#3440](https://github.com/apache/incubator-superset/pull/3440) fix https://github.com/apache/incubator-superset/issues/3422 (#3440) (@graceguo-supercat)
|
||||
- [#3439](https://github.com/apache/incubator-superset/pull/3439) Adding order_desc flag to explore endpoint (#3439) (@fabianmenges)
|
||||
- [#2937](https://github.com/apache/incubator-superset/pull/2937) Handling pandas ExtensionDtypes (#2937) (@fabianmenges)
|
||||
- [#3444](https://github.com/apache/incubator-superset/pull/3444) [postgres] adding support to serialized timedelta (#3444) (@mistercrunch)
|
||||
- [#3453](https://github.com/apache/incubator-superset/pull/3453) [explore] show validation error on control panel header (#3453) (@mistercrunch)
|
||||
- [#3450](https://github.com/apache/incubator-superset/pull/3450) [heatmap] fix default sorting (#3450) (@mistercrunch)
|
||||
- [#3452](https://github.com/apache/incubator-superset/pull/3452) Fix off-by-one error with linear color scales (#3452) (@mistercrunch)
|
||||
- [#3454](https://github.com/apache/incubator-superset/pull/3454) [explore] checkbox control won't uncheck (#3454) (@mistercrunch)
|
||||
- [#3446](https://github.com/apache/incubator-superset/pull/3446) Ignore intellij files (#3446) (@fabianmenges)
|
||||
- [#3445](https://github.com/apache/incubator-superset/pull/3445) Fixing the build (#3445) (@mistercrunch)
|
||||
- [#3405](https://github.com/apache/incubator-superset/pull/3405) setup: Bump sqlalchemy-utils to 0.32.16 (#3405) (@xrmx)
|
||||
- [#3403](https://github.com/apache/incubator-superset/pull/3403) [hotfix] user dashboard says '150 weeks' (#3403) (@mistercrunch)
|
||||
- [#3401](https://github.com/apache/incubator-superset/pull/3401) [hotfix] fix slices where since/until = None (#3401) (@mistercrunch)
|
||||
- [#3391](https://github.com/apache/incubator-superset/pull/3391) [dashboard] adding an option to duplicate slices when "Saving AS" (#3391) (@mistercrunch)
|
||||
- [#3399](https://github.com/apache/incubator-superset/pull/3399) Fix copypasta control label error 'Until' -> 'Since' (#3399) (@mistercrunch)
|
||||
- [#3397](https://github.com/apache/incubator-superset/pull/3397) [line chart] add 'min_periods' control related to rolling windows (#3397) (@mistercrunch)
|
||||
- [#3394](https://github.com/apache/incubator-superset/pull/3394) [hive] fix date casting in explore view (#3394) (@mistercrunch)
|
||||
- [#3396](https://github.com/apache/incubator-superset/pull/3396) [hotfix] backward compatibility on date expressions (#3396) (@mistercrunch)
|
||||
- [#3395](https://github.com/apache/incubator-superset/pull/3395) Add Capital Service to organizations list (#3395) (@pkonarzewski)
|
||||
- [#3377](https://github.com/apache/incubator-superset/pull/3377) Fix datatable scroll height when using filter or pagination (#3377) (@mxmzdlv)
|
||||
- [#3392](https://github.com/apache/incubator-superset/pull/3392) fix date picker Select alignment (#3392) (@graceguo-supercat)
|
||||
- [#3378](https://github.com/apache/incubator-superset/pull/3378) Build optimizations (#3378) (@mistercrunch)
|
||||
- [#3379](https://github.com/apache/incubator-superset/pull/3379) [dashboard] load list of slices at modal enter time (#3379) (@mistercrunch)
|
||||
- [#3371](https://github.com/apache/incubator-superset/pull/3371) [explore] Improved time filters controls (#3371) (@mistercrunch)
|
||||
- [#3363](https://github.com/apache/incubator-superset/pull/3363) [sql lab] using react-split-pane (#3363) (@mistercrunch)
|
||||
|
||||
### 0.19.1 (2017/08/26 22:07 +00:00)
|
||||
- [#3376](https://github.com/apache/incubator-superset/pull/3376) v1.9.1 (#3376) (@mistercrunch)
|
||||
- [#3373](https://github.com/apache/incubator-superset/pull/3373) Apply advanced analytics processing to comparison time series (#3373) (@mxmzdlv)
|
||||
- [#3362](https://github.com/apache/incubator-superset/pull/3362) [webpack] add a 'npm run dev-fast' command that is much faster (#3362) (@mistercrunch)
|
||||
- [#3366](https://github.com/apache/incubator-superset/pull/3366) bugfix for addTotalValues with negative values (#3366) (@hajdbo)
|
||||
- [#3339](https://github.com/apache/incubator-superset/pull/3339) [explore] Fix and test slice id logging issue (#3339) (@timifasubaa)
|
||||
- [#3364](https://github.com/apache/incubator-superset/pull/3364) Bump fab to 1.9.4 (#3364) (@mistercrunch)
|
||||
- [#3242](https://github.com/apache/incubator-superset/pull/3242) Revert "[sql lab] Make sql editor resizable (#3242)" (#3360) (@mistercrunch)
|
||||
- [#3357](https://github.com/apache/incubator-superset/pull/3357) [dist_bar] break down control groups (#3357) (@mistercrunch)
|
||||
- [#3356](https://github.com/apache/incubator-superset/pull/3356) delete unused csv file (#3356) (@timifasubaa)
|
||||
- [#3358](https://github.com/apache/incubator-superset/pull/3358) [hotfix] react-select dropdown autocomplete are invisible (#3358) (@mistercrunch)
|
||||
- [#3354](https://github.com/apache/incubator-superset/pull/3354) Collapsible Control sections (#3354) (@mistercrunch)
|
||||
- [#3353](https://github.com/apache/incubator-superset/pull/3353) [bugfix] `Y bounds` in line chart (#3353) (@mistercrunch)
|
||||
- [#3351](https://github.com/apache/incubator-superset/pull/3351) [css] react-select only in theme (#3351) (@mistercrunch)
|
||||
- [#3352](https://github.com/apache/incubator-superset/pull/3352) fix multi-value react select style (#3352) (@graceguo-supercat)
|
||||
- [#3345](https://github.com/apache/incubator-superset/pull/3345) Better looking checkboxes (#3345) (@mistercrunch)
|
||||
- [#3338](https://github.com/apache/incubator-superset/pull/3338) [hotfix] self-immune filter_box fix (#3338) (@mistercrunch)
|
||||
- [#3242](https://github.com/apache/incubator-superset/pull/3242) [sql lab] Make sql editor resizable (#3242) (@dmigo)
|
||||
- [#3308](https://github.com/apache/incubator-superset/pull/3308) [sql lab] improve error messages (#3308) (@mistercrunch)
|
||||
- [#3329](https://github.com/apache/incubator-superset/pull/3329) Syncing the timeout param from backend (#3329) (@mistercrunch)
|
||||
- [#3335](https://github.com/apache/incubator-superset/pull/3335) [dashboard] re-enabling cascading filters (#3335) (@mistercrunch)
|
||||
- [#3332](https://github.com/apache/incubator-superset/pull/3332) [nvd3] fix bubble axis (#3332) (@mistercrunch)
|
||||
- [#3333](https://github.com/apache/incubator-superset/pull/3333) [hotfix] hotfixing the hotfix (#3333) (@mistercrunch)
|
||||
- [#3331](https://github.com/apache/incubator-superset/pull/3331) Unnecessary to specify order_columns for DatasourceModelView (#3331) (@RoganW)
|
||||
- [#3328](https://github.com/apache/incubator-superset/pull/3328) disable immediately re-render for color scheme change (#3328) (@graceguo-supercat)
|
||||
- [#3330](https://github.com/apache/incubator-superset/pull/3330) [hotfix] dashboard widget resize is broken (#3330) (@mistercrunch)
|
||||
- [#3322](https://github.com/apache/incubator-superset/pull/3322) docs: add references to Flask-Appbuilder Security documentation (#3322) (@xrmx)
|
||||
- [#3315](https://github.com/apache/incubator-superset/pull/3315) Use react-alert for backend message flashing (#3315) (@mistercrunch)
|
||||
- [#3295](https://github.com/apache/incubator-superset/pull/3295) Allow for multiple color schemes (#3295) (@graceguo-supercat)
|
||||
- [#3313](https://github.com/apache/incubator-superset/pull/3313) French translation (#3313) (@invenis-paris)
|
||||
- [#3305](https://github.com/apache/incubator-superset/pull/3305) [hive] improve error messages (#3305) (@mistercrunch)
|
||||
- [#3309](https://github.com/apache/incubator-superset/pull/3309) Fix styles in Separator widget (#3309) (@mistercrunch)
|
||||
- [#3310](https://github.com/apache/incubator-superset/pull/3310) [sql lab] run button shortcut tooltip (#3310) (@mistercrunch)
|
||||
- [#3291](https://github.com/apache/incubator-superset/pull/3291) [bugfix] Presto KeyError 'errorLocation' (#3291) (@mistercrunch)
|
||||
- [#3292](https://github.com/apache/incubator-superset/pull/3292) [sql lab] add pending to the list of searchable statuses (#3292) (@mistercrunch)
|
||||
- [#3293](https://github.com/apache/incubator-superset/pull/3293) [mapbox] fix viewport alterations (#3293) (@mistercrunch)
|
||||
- [#3298](https://github.com/apache/incubator-superset/pull/3298) Fix raise error when query datasource (#3298) (@RoganW)
|
||||
- [#3296](https://github.com/apache/incubator-superset/pull/3296) [docs] document how to compile/publish docs (#3296) (@mistercrunch)
|
||||
- [#3280](https://github.com/apache/incubator-superset/pull/3280) [dashboard] add link to export CSV from dashboard (#3280) (@mistercrunch)
|
||||
- [#3282](https://github.com/apache/incubator-superset/pull/3282) FAQ entry for backend support (#3282) (@mistercrunch)
|
||||
- [#3286](https://github.com/apache/incubator-superset/pull/3286) [sql lab] fix sluggish backspace in editor (#3286) (@mistercrunch)
|
||||
- [#3287](https://github.com/apache/incubator-superset/pull/3287) Fix Chart Error Message Display (#3287) (@graceguo-supercat)
|
||||
- [#3284](https://github.com/apache/incubator-superset/pull/3284) [dashboard] fix standalone mode that hides the navbar (#3284) (@mistercrunch)
|
||||
- [#3031](https://github.com/apache/incubator-superset/pull/3031) Improve superset list view content layout (#3031) (@graceguo-supercat)
|
||||
- [#3281](https://github.com/apache/incubator-superset/pull/3281) [markup] fix CSS, remove scrollbar (#3281) (@mistercrunch)
|
||||
- [#2033](https://github.com/apache/incubator-superset/pull/2033) Fix returned time parse_human_datetime (#2033) (@0x0ece)
|
||||
- [#3032](https://github.com/apache/incubator-superset/pull/3032) Add translatable columns in label_columns of the view (#3032) (@RoganW)
|
||||
- [#3211](https://github.com/apache/incubator-superset/pull/3211) [security] prevent XSS markup viz (#3211) (@mistercrunch)
|
||||
- [#3034](https://github.com/apache/incubator-superset/pull/3034) add `_()` to Exception messages (#3034) (@RoganW)
|
||||
- [#3275](https://github.com/apache/incubator-superset/pull/3275) display the verbose_name of columns in list view, just like in the metrics list (#3275) (@RoganW)
|
||||
- [#3274](https://github.com/apache/incubator-superset/pull/3274) add placeholder to Select components (#3274) (@RoganW)
|
||||
- [#3277](https://github.com/apache/incubator-superset/pull/3277) Added Konfio to 'Who uses Superset' list. (#3277) (@luis-rodriguez)
|
||||
- [#3278](https://github.com/apache/incubator-superset/pull/3278) Fix celery worker (#3278) (@saguziel)
|
||||
- [#3183](https://github.com/apache/incubator-superset/pull/3183) [add] Save filters to dashboard (#3183) (@RoganW)
|
||||
- [#3110](https://github.com/apache/incubator-superset/pull/3110) Explore view save modal spec (#3110) (@graceguo-supercat)
|
||||
- [#3279](https://github.com/apache/incubator-superset/pull/3279) [explore] fixed padding bug on filter section (#3279) (@timifasubaa)
|
||||
- [#3088](https://github.com/apache/incubator-superset/pull/3088) [explore] Split large reducer logic in ExploreViewContainer (#3088) (@graceguo-supercat)
|
||||
- [#3267](https://github.com/apache/incubator-superset/pull/3267) Use sane Celery defaults to prevent tasks from being delayed (#3267) (@saguziel)
|
||||
- [#3268](https://github.com/apache/incubator-superset/pull/3268) [bugfix] preserve order in groupby (#3268) (@mistercrunch)
|
||||
- [#3266](https://github.com/apache/incubator-superset/pull/3266) Set default ports Druid (#3266) (@Fokko)
|
||||
- [#3262](https://github.com/apache/incubator-superset/pull/3262) [webpack] break CSS and JS files while webpackin' (#3262) (@mistercrunch)
|
||||
- [#3241](https://github.com/apache/incubator-superset/pull/3241) Improve the chart type of Visualize in sqllab (#3241) (@eeve)
|
||||
- [#3256](https://github.com/apache/incubator-superset/pull/3256) Modernize SQLA pessimistic handling (#3256) (@mistercrunch)
|
||||
- [#3252](https://github.com/apache/incubator-superset/pull/3252) Explicitly add Flask as dependancy (#3252) (@Fokko)
|
||||
- [#3261](https://github.com/apache/incubator-superset/pull/3261) Relying on FAB for font-awesome.min.css (#3261) (@mistercrunch)
|
||||
- [#3264](https://github.com/apache/incubator-superset/pull/3264) import logging (#3264) (@cclauss)
|
||||
- [#3244](https://github.com/apache/incubator-superset/pull/3244) [explore] make edit datasource a basic link (#3244) (@mistercrunch)
|
||||
- [#3254](https://github.com/apache/incubator-superset/pull/3254) [bugfix] wrong 'Cant have overlap between Series and Breakdowns' (#3254) (@mistercrunch)
|
||||
- [#3249](https://github.com/apache/incubator-superset/pull/3249) Fix Yahoo's website link (#3249) (@pedro-valentim)
|
||||
- [#3246](https://github.com/apache/incubator-superset/pull/3246) Fix typo (#3246) (@zeeshanu)
|
||||
- [#3235](https://github.com/apache/incubator-superset/pull/3235) docs: use yarn in making your own build (#3235) (@xrmx)
|
||||
- [#3067](https://github.com/apache/incubator-superset/pull/3067) explore: redraw chart on width change too (#3067) (@xrmx)
|
||||
- [#3225](https://github.com/apache/incubator-superset/pull/3225) Add basic Impala engine spec (#3225) (@mistercrunch)
|
||||
- [#3237](https://github.com/apache/incubator-superset/pull/3237) Treemap vis verbose metric name (#3237) (@RichRadics)
|
||||
- [#3240](https://github.com/apache/incubator-superset/pull/3240) [bug fix] Fix to #3137 and #3239 (#3240) (@FrederichCheng)
|
||||
- [#3238](https://github.com/apache/incubator-superset/pull/3238) SUPERSET_HOME enviroment variable (#3238) (@RichRadics)
|
||||
- [#3236](https://github.com/apache/incubator-superset/pull/3236) Handle Time at query_obj generation time (#3236) (@mistercrunch)
|
||||
- [#3230](https://github.com/apache/incubator-superset/pull/3230) [pivot] add support for in Pivot on Druid (#3230) (@mistercrunch)
|
||||
- [#3229](https://github.com/apache/incubator-superset/pull/3229) Allowing to integrate time as a groupby value (#3229) (@mistercrunch)
|
||||
- [#3227](https://github.com/apache/incubator-superset/pull/3227) 0.19.0 (#3227) (@mistercrunch)
|
||||
- [#2974](https://github.com/apache/incubator-superset/pull/2974) Allow 'refresh_immune_slices' (#2974) (@RichRadics)
|
||||
- [#3111](https://github.com/apache/incubator-superset/pull/3111) sql_lab: re-raise exception in get_sql_results (#3111) (@xrmx)
|
||||
|
||||
### 0.19.0 (2017/08/02 05:16 +00:00)
|
||||
- [#3210](https://github.com/apache/incubator-superset/pull/3210) [explore] DatasourceControl to pick datasource in modal (#3210) (@mistercrunch)
|
||||
- [#3214](https://github.com/apache/incubator-superset/pull/3214) [sqllab] fix UI shows 'The query returned no results' momentarily (#3214) (@mistercrunch)
|
||||
- [#3197](https://github.com/apache/incubator-superset/pull/3197) [explore] nvd3 sort values in rich tooltip (#3197) (@mistercrunch)
|
||||
- [#3222](https://github.com/apache/incubator-superset/pull/3222) [sqllab/cosmetics] add margin-top for labels in query history (#3222) (@mistercrunch)
|
||||
- [#3212](https://github.com/apache/incubator-superset/pull/3212) [docs] update url in CONTRIBUTING.md (#3212) (@diggzhang)
|
||||
- [#3213](https://github.com/apache/incubator-superset/pull/3213) [bugfix] capture Hive job_id pre-url transformation (#3213) (@mistercrunch)
|
||||
- [#3205](https://github.com/apache/incubator-superset/pull/3205) fix issue 3204 (#3205) (@diggzhang)
|
||||
- [#3203](https://github.com/apache/incubator-superset/pull/3203) Speed up JS build time (#3203) (@mistercrunch)
|
||||
- [#2929](https://github.com/apache/incubator-superset/pull/2929) Autofocus search input in VizTypeControl modal onEnter (#2929) (@pariser)
|
||||
- [#3086](https://github.com/apache/incubator-superset/pull/3086) add combine config for metrics in pivot table (#3086) (@RoganW)
|
||||
- [#3146](https://github.com/apache/incubator-superset/pull/3146) [druid] Allow custom druid postaggregators (#3146) (@brianwolfe)
|
||||
- [#3194](https://github.com/apache/incubator-superset/pull/3194) Adding 'apache' to docs (#3194) (@mistercrunch)
|
||||
- [#3196](https://github.com/apache/incubator-superset/pull/3196) [bugfix] fix merge conflict that broke Hive support (#3196) (@mistercrunch)
|
||||
- [#3193](https://github.com/apache/incubator-superset/pull/3193) Add BigQuery engine specifications (#3193) (@mistercrunch)
|
||||
- [#3187](https://github.com/apache/incubator-superset/pull/3187) [sqllab] improve Hive support (#3187) (@mistercrunch)
|
||||
- [#3186](https://github.com/apache/incubator-superset/pull/3186) Escaping the user's SQL in the explore view (#3186) (@mistercrunch)
|
||||
- [#3065](https://github.com/apache/incubator-superset/pull/3065) Bump cryptography to 1.9 (#3065) (@xrmx)
|
||||
- [#3174](https://github.com/apache/incubator-superset/pull/3174) Fix the segment interval for pulling metadata (#3174) (@Fokko)
|
||||
- [#3181](https://github.com/apache/incubator-superset/pull/3181) [bugfix] visualize flow error: 'Metric x is not valid' (#3181) (@mistercrunch)
|
||||
- [#3180](https://github.com/apache/incubator-superset/pull/3180) [bugfix] fix bar order (#3180) (@mistercrunch)
|
||||
- [#3169](https://github.com/apache/incubator-superset/pull/3169) docs: fixup installation examples code indentation (#3169) (@xrmx)
|
||||
- [#3171](https://github.com/apache/incubator-superset/pull/3171) add Zalando to the list of organizations (#3171) (@dmigo)
|
||||
- [#2968](https://github.com/apache/incubator-superset/pull/2968) fix hive.fetch_logs (#2968) (@timfeirg)
|
||||
- [#3036](https://github.com/apache/incubator-superset/pull/3036) [bugfix] numeric value for date fields in table viz (#3036) (@mistercrunch)
|
||||
- [#3101](https://github.com/apache/incubator-superset/pull/3101) Add 'show/hide totals' option to pivot table vis (#3101) (@RichRadics)
|
||||
- [#3045](https://github.com/apache/incubator-superset/pull/3045) add title description to model view (#3045) (@RoganW)
|
||||
- [#3035](https://github.com/apache/incubator-superset/pull/3035) Datasource cannot be empty (#3035) (@RoganW)
|
||||
- [#3105](https://github.com/apache/incubator-superset/pull/3105) [bugfix] only filterable columns should show up in FilterBox list (#3105) (@mistercrunch)
|
||||
- [#3179](https://github.com/apache/incubator-superset/pull/3179) Fixing the damn build (#3179) (@mistercrunch)
|
||||
- [#3102](https://github.com/apache/incubator-superset/pull/3102) Add event-flow visualization (#3102) (@williaster)
|
||||
- [#3163](https://github.com/apache/incubator-superset/pull/3163) Prevent people from deleting datasources that have associate slices (#3163) (@mistercrunch)
|
||||
- [#3164](https://github.com/apache/incubator-superset/pull/3164) More logging to csv endpoint (#3164) (@mistercrunch)
|
||||
- [#3159](https://github.com/apache/incubator-superset/pull/3159) [bugfix] SQLA instance has been deleted (#3159) (@mistercrunch)
|
||||
- [#3157](https://github.com/apache/incubator-superset/pull/3157) add douban to the orgs. (#3157) (@luchuan)
|
||||
- [#3150](https://github.com/apache/incubator-superset/pull/3150) [docs] use yarn in CONTRIBUTING.md (#3150) (@mistercrunch)
|
||||
- [#3155](https://github.com/apache/incubator-superset/pull/3155) [bugfix] fails on None view_menu (#3155) (@mistercrunch)
|
||||
- [#3112](https://github.com/apache/incubator-superset/pull/3112) allow user press Enter key to end editing title (#3112) (@graceguo-supercat)
|
||||
- [#3116](https://github.com/apache/incubator-superset/pull/3116) [minor] change tooltip on 'Edit slice properties' (#3116) (@mistercrunch)
|
||||
- [#3133](https://github.com/apache/incubator-superset/pull/3133) Prevent SQLA warning related to SQLALCHEMY_TRACK_MODIFICATION (#3133) (@mistercrunch)
|
||||
- [#3138](https://github.com/apache/incubator-superset/pull/3138) [#3137] Use state.datasource.type instead of state.datasource_type when rendering ControlPanelsContainer (#3138) (@FrederichCheng)
|
||||
- [#3119](https://github.com/apache/incubator-superset/pull/3119) [heatmap] basic non empty validation (#3119) (@mistercrunch)
|
||||
- [#3135](https://github.com/apache/incubator-superset/pull/3135) Fixes #3134 by correct response content-type of /testconn (#3135) (@shawnzhu)
|
||||
- [#3126](https://github.com/apache/incubator-superset/pull/3126) [Celery] fix the celery worker concurrency settings (#3126) (@dingguitao)
|
||||
- [#3118](https://github.com/apache/incubator-superset/pull/3118) [CLI] Improve the missing perm creation logic (#3118) (@mistercrunch)
|
||||
- [#3120](https://github.com/apache/incubator-superset/pull/3120) Using yarn instead of npm install (#3120) (@mistercrunch)
|
||||
- [#3044](https://github.com/apache/incubator-superset/pull/3044) clarify Superset different timeout config (#3044) (@graceguo-supercat)
|
||||
- [3d136aa](https://github.com/apache/incubator-superset/commit/3d136aa0a4d3c6ebb26821e1b308b6eff4c2fd8f) Update docs links on README (@mistercrunch)
|
||||
- [#3042](https://github.com/apache/incubator-superset/pull/3042) fix default checkbox alignment (#3042) (@graceguo-supercat)
|
||||
- [#3013](https://github.com/apache/incubator-superset/pull/3013) New chart type : Chord Diagrams (#3013) (@mistercrunch)
|
||||
- [#3041](https://github.com/apache/incubator-superset/pull/3041) [bugfix] issue creating separators & markup slices (#3041) (@mistercrunch)
|
||||
- [#3011](https://github.com/apache/incubator-superset/pull/3011) Bug fix: Datasource -> Slice relationship (#3011) (@fabianmenges)
|
||||
|
||||
### 0.18.5 (2017/06/22 22:46 +00:00)
|
||||
- [fdbb569](https://github.com/apache/incubator-superset/commit/fdbb569c3e2842fdfc80e0418f5817593e5c64fb) 0.18.5 (@mistercrunch)
|
||||
- [cc3e63f](https://github.com/apache/incubator-superset/commit/cc3e63f1de0a6e5c2fd68464297620ac878fe2a0) [docs] adding info on how to create new viz (@mistercrunch)
|
||||
- [#3022](https://github.com/apache/incubator-superset/pull/3022) add test coverage for sql lab components (#3022) (@graceguo-supercat)
|
||||
- [6eba6ca](https://github.com/apache/incubator-superset/commit/6eba6cac0b49a06172ba3dc817eb7aeef7cd310c) [hotfix] xAxis broken on time series viz (@mistercrunch)
|
||||
- [bd706eb](https://github.com/apache/incubator-superset/commit/bd706ebbd17e6d147962df5f20dabdf3af3a6730) Fixing image sizes for horizon and country_map (@mistercrunch)
|
||||
- [abbf138](https://github.com/apache/incubator-superset/commit/abbf138cfb6149277cbbfd1b38aa65a1e0170f3c) Bumping SQLLAB_ASYNC_TIME_LIMIT_SEC default config to 6 hours (@mistercrunch)
|
||||
- [#3021](https://github.com/apache/incubator-superset/pull/3021) CONTRIBUTING: add python unittes setup (#3021) (@graceguo-supercat)
|
||||
- [#3014](https://github.com/apache/incubator-superset/pull/3014) A set of minor fixes (#3014) (@mistercrunch)
|
||||
- [5344a80](https://github.com/apache/incubator-superset/commit/5344a805359fe6b72bcc7a4298b22f0dfb0cccfa) Bumping flask-appbuilder to 1.9.1 (@mistercrunch)
|
||||
- [0b09a74](https://github.com/apache/incubator-superset/commit/0b09a74d37874f9c6aa101c9566257873a6e41a0) Downgrading celery to 3.1.25 (@mistercrunch)
|
||||
- [#3017](https://github.com/apache/incubator-superset/pull/3017) CONTRIBUTING: ask to quote python stacktraces (#3017) (@xrmx)
|
||||
- [#3009](https://github.com/apache/incubator-superset/pull/3009) [bugfix] fix metrics/metric control default (#3009) (@mistercrunch)
|
||||
- [53dead9](https://github.com/apache/incubator-superset/commit/53dead9c2983ca9e3f940354e1fecb3d85f62b2b) Revert "Bumping FAB to 1.9.1" (@mistercrunch)
|
||||
- [f64e2ba](https://github.com/apache/incubator-superset/commit/f64e2ba7d52c442461b59ee1230476eae6b9ff22) Bumping FAB to 1.9.1 (@mistercrunch)
|
||||
- [#3012](https://github.com/apache/incubator-superset/pull/3012) Revert change in npm run build command (#3012) (@yolken)
|
||||
- [#3008](https://github.com/apache/incubator-superset/pull/3008) Adding missing dependency and linting webpack.js (#3008) (@mistercrunch)
|
||||
- [#2981](https://github.com/apache/incubator-superset/pull/2981) Stabilizing Celery / SQL Lab (#2981) (@mistercrunch)
|
||||
- [#2994](https://github.com/apache/incubator-superset/pull/2994) Misc. tweaks to improve webpack performance (#2994) (@yolken)
|
||||
- [#2990](https://github.com/apache/incubator-superset/pull/2990) translations extracted by pybabel (#2990) (@RoganW)
|
||||
- [#2983](https://github.com/apache/incubator-superset/pull/2983) Fix importing config from env var (#2983) (@andrewmchen)
|
||||
- [#2988](https://github.com/apache/incubator-superset/pull/2988) Improving TextAreaControl to support code and modal (#2988) (@mistercrunch)
|
||||
- [#2957](https://github.com/apache/incubator-superset/pull/2957) [pivot viz] fix formatting and verbose names (#2957) (@mistercrunch)
|
||||
- [#2927](https://github.com/apache/incubator-superset/pull/2927) [explore] improve bubble viz (#2927) (@mistercrunch)
|
||||
- [#2984](https://github.com/apache/incubator-superset/pull/2984) add test coverage for SqlEditorLeftBar (#2984) (@graceguo-supercat)
|
||||
- [#2985](https://github.com/apache/incubator-superset/pull/2985) fix is_owner check (#2985) (@graceguo-supercat)
|
||||
- [#2970](https://github.com/apache/incubator-superset/pull/2970) [FilterBox] use column verbose names (#2970) (@mistercrunch)
|
||||
- [1ce3b81](https://github.com/apache/incubator-superset/commit/1ce3b81d01e1453fb34469fa6ba66f9b7d09bcb2) Imporving the README (@mistercrunch)
|
||||
- [#2978](https://github.com/apache/incubator-superset/pull/2978) [bufix] superset views not getting from_dttm-to_dttm in template context (#2978) (@mistercrunch)
|
||||
- [#2963](https://github.com/apache/incubator-superset/pull/2963) [CLI] adding 'superset flower' command (flower is a UI for Celery) (#2963) (@mistercrunch)
|
||||
- [#2979](https://github.com/apache/incubator-superset/pull/2979) tests for saveQuery, fetchQueryResults, runQuery, postStopQuery (#2979) (@ascott)
|
||||
- [#2896](https://github.com/apache/incubator-superset/pull/2896) fix local state 'columns' (#2896) (@graceguo-supercat)
|
||||
- [#2977](https://github.com/apache/incubator-superset/pull/2977) test props on alert wrapper (#2977) (@ascott)
|
||||
- [#2972](https://github.com/apache/incubator-superset/pull/2972) add test coverage for ResultSet component (#2972) (@graceguo-supercat)
|
||||
- [#2976](https://github.com/apache/incubator-superset/pull/2976) [js-testing] add tests for explore actions (#2976) (@ascott)
|
||||
- [#2940](https://github.com/apache/incubator-superset/pull/2940) Edit Dashboard title and Slice title in place (#2940) (@graceguo-supercat)
|
||||
- [#2961](https://github.com/apache/incubator-superset/pull/2961) add test for ControlPanelSection (#2961) (@ascott)
|
||||
- [#2952](https://github.com/apache/incubator-superset/pull/2952) [js] remove unused npm dependencies (#2952) (@mistercrunch)
|
||||
- [#2939](https://github.com/apache/incubator-superset/pull/2939) add new slice test (#2939) (@ascott)
|
||||
- [#2951](https://github.com/apache/incubator-superset/pull/2951) [js] version js file names using webpack chunkhash (#2951) (@ascott)
|
||||
- [#2941](https://github.com/apache/incubator-superset/pull/2941) [dashboard] notify instead of modal onSave (#2941) (@mistercrunch)
|
||||
- [987cb99](https://github.com/apache/incubator-superset/commit/987cb9978dcd053ebac550c790a9d87d8d25aee6) [hotfix] bumping pandas version to 0.20.2 (@mistercrunch)
|
||||
- [#1742](https://github.com/apache/incubator-superset/pull/1742) Fix handling of Chunked requests (#1742) (@nishantmonu51)
|
||||
- [#2943](https://github.com/apache/incubator-superset/pull/2943) [table viz] get metrics to right-align (#2943) (@mistercrunch)
|
||||
- [#2945](https://github.com/apache/incubator-superset/pull/2945) Bumping some dependencies (#2945) (@mistercrunch)
|
||||
- [#2946](https://github.com/apache/incubator-superset/pull/2946) remove reference for CSRF_ENABLED, and use WTF_CSRF_ENABLED instead (#2946) (@timfeirg)
|
||||
- [#2921](https://github.com/apache/incubator-superset/pull/2921) [explore] improve metric(s) and groupby(s) controls (#2921) (@mistercrunch)
|
||||
- [34f381b](https://github.com/apache/incubator-superset/commit/34f381bc250cf7c74669b52d5cc5f9061c7184c5) v 0.18.5-alpha.3 (@ascott)
|
||||
- [#2928](https://github.com/apache/incubator-superset/pull/2928) add new slice form improvements (#2928) (@ascott)
|
||||
- [#2912](https://github.com/apache/incubator-superset/pull/2912) [big number] various improvements (#2912) (@mistercrunch)
|
||||
- [#2924](https://github.com/apache/incubator-superset/pull/2924) Fix #2814 - json serialization edge case (#2924) (@mistercrunch)
|
||||
- [fb85f00](https://github.com/apache/incubator-superset/commit/fb85f008fac2694bea7f6705cf21dc666490bcd0) v 0.18.5-alpha.2 (@ascott)
|
||||
- [85fb4a9](https://github.com/apache/incubator-superset/commit/85fb4a933d8ab7348082a6849ff96f199b8c02fa) [hotfix] only apply SQLAlchemy limit where needed (@mistercrunch)
|
||||
- [#2893](https://github.com/apache/incubator-superset/pull/2893) [js-testing] type checking for dates.js (#2893) (@ascott)
|
||||
- [#2889](https://github.com/apache/incubator-superset/pull/2889) add more tests for Timer (#2889) (@ascott)
|
||||
- [#2800](https://github.com/apache/incubator-superset/pull/2800) [slices] add simple new slice form (#2800) (@ascott)
|
||||
- [#2923](https://github.com/apache/incubator-superset/pull/2923) updating react-alert dependency to v2.0.1 (#2923) (@dennybiasiolli)
|
||||
- [#2906](https://github.com/apache/incubator-superset/pull/2906) Ignore pyenv files in .gitignore. (#2906) (@xiaohanyu)
|
||||
- [9aba77d](https://github.com/apache/incubator-superset/commit/9aba77db74f8c7e823fcba73fc4e0a1b7efbadd4) 0.18.5-alpha.1 (@mistercrunch)
|
||||
- [#2910](https://github.com/apache/incubator-superset/pull/2910) [dashboard]Add timeout message on Dashboard view (#2910) (@graceguo-supercat)
|
||||
- [#2908](https://github.com/apache/incubator-superset/pull/2908) [explore] fix IN filter on numeric field (#2908) (@mistercrunch)
|
||||
- [#2911](https://github.com/apache/incubator-superset/pull/2911) Removed time column from druid metadata refresh, added long and double schema support (#2911) (@joshwalters)
|
||||
- [#2897](https://github.com/apache/incubator-superset/pull/2897) fix visualize modal checkbox alignment (#2897) (@graceguo-supercat)
|
||||
- [#2902](https://github.com/apache/incubator-superset/pull/2902) update for the italian translation (#2902) (@napo)
|
||||
- [#2888](https://github.com/apache/incubator-superset/pull/2888) [docs faq] how do I add new columns to an existing table (#2888) (@mistercrunch)
|
||||
- [#2903](https://github.com/apache/incubator-superset/pull/2903) update contributing a bit re contributing code (#2903) (@xrmx)
|
||||
- [#2904](https://github.com/apache/incubator-superset/pull/2904) travis: no need to install python3.5 (#2904) (@xrmx)
|
||||
|
||||
### 0.18.4 (2017/06/05 00:54 +00:00)
|
||||
- [72291d6](https://github.com/apache/incubator-superset/commit/72291d65c929306792bc62aeaff51e083bc8c09f) 0.18.4 (@mistercrunch)
|
||||
- [#2895](https://github.com/apache/incubator-superset/pull/2895) fix a linting error (#2895) (@graceguo-supercat)
|
||||
- [#2894](https://github.com/apache/incubator-superset/pull/2894) fix js error on explore view (#2894) (@ascott)
|
||||
- [155fec0](https://github.com/apache/incubator-superset/commit/155fec0a6bcb9733c64301e9e8b86aa2c384673b) Updating CHANGELOG.md to 0.18.3 (@mistercrunch)
|
||||
|
||||
### 0.18.3 (2017/06/02 15:27 +00:00)
|
||||
- [d90044c](https://github.com/airbnb/superset/commit/d90044cd523253aa01b5cdf6509b43abeef34079) 0.18.3 (@mistercrunch)
|
||||
- [62bd4eb](https://github.com/airbnb/superset/commit/62bd4eb2118e4f1e771b58cd455b928be002a461) Converting filter argument to number if column is number (#2891) (@fabianmenges)
|
||||
- [677c427](https://github.com/airbnb/superset/commit/677c427b1615a2a9b9054932b5e07868d7d63e42) delete DataPreviewModal, it doesn't get used anywhere (#2882) (@ascott)
|
||||
- [52b0716](https://github.com/airbnb/superset/commit/52b0716571c5b68f65d08719e54343e0a6ec8c8e) [bugfix] allow database macro to work when CSRF is diabled (#2884) (@justinr1234)
|
||||
- [04b662e](https://github.com/airbnb/superset/commit/04b662ea1154b75e2c362aed97e33946251d1bed) Fix a type error in rst' sub list. (#2881) (@xiaohanyu)
|
||||
- [db052b1](https://github.com/airbnb/superset/commit/db052b17ea1782c472687095e1365d071e592dd0) Add visualize advise for long query (#2879) (@graceguo-supercat)
|
||||
- [e300273](https://github.com/airbnb/superset/commit/e300273e71f0b6ca8b63ae974cc13534d94c56de) [explore] adding y_axis_bounds to force Y axis bounds (#2878) (@mistercrunch)
|
||||
- [c5f2eaf](https://github.com/airbnb/superset/commit/c5f2eafc906bebf1d238e62ff5a8821cf549220c) [explore] 'Save as' -> 'Save' as it can be used to overwrite (#2875) (@mistercrunch)
|
||||
- [90e4d64](https://github.com/airbnb/superset/commit/90e4d6469d3d420cf839a4c9f3a2408ab0ff0a42) [js-testing] more tests for SelectControl (#2877) (@ascott)
|
||||
- [1e7773e](https://github.com/airbnb/superset/commit/1e7773eb169d29607991d0c4619ee930104e18de) Improve visualize modal test coverage (#2811) (@graceguo-supercat)
|
||||
- [3c89c8c](https://github.com/airbnb/superset/commit/3c89c8cc4613d938e4e8726c30142fa32b1249f7) 0.18.3-alpha.3 (@mistercrunch)
|
||||
- [74086da](https://github.com/airbnb/superset/commit/74086dae2ba66029917a7ed640cfcfc7555c0520) [bars] fix sort numeric bar on x axis (#2812) (@mistercrunch)
|
||||
- [66403f1](https://github.com/airbnb/superset/commit/66403f1876bb7bcf31eb8187517c116a2d5b6b96) [explore] viz type selector as modal (#2787) (@mistercrunch)
|
||||
- [3a4cd3a](https://github.com/airbnb/superset/commit/3a4cd3ae24c811e21fb76c5f9efecb2a6c4a6da2) Applying specified limit in bubble plot (#2815) (@mistercrunch)
|
||||
- [4ffc1f6](https://github.com/airbnb/superset/commit/4ffc1f613e1d2bf012dc5eb66751fea8c698804e) Fix filter values populating for views (#2816) (@mistercrunch)
|
||||
- [dfbba84](https://github.com/airbnb/superset/commit/dfbba84400986451f5068354a7626537e7b377a4) 0.18.3-alpha.2 (@mistercrunch)
|
||||
- [77864e6](https://github.com/airbnb/superset/commit/77864e6cf4d5394a5080300097ae21cf9abfcc53) reduce clientside timeout limit (#2820) (@graceguo-supercat)
|
||||
- [4d12251](https://github.com/airbnb/superset/commit/4d1225180618b4c4f05c67f6534bf273692a9243) [explore] include ControlHeader as part of Control interface (#2809) (@mistercrunch)
|
||||
- [0c9f9b6](https://github.com/airbnb/superset/commit/0c9f9b695b921c7e17cec83e1d51e4aa3cae7cc9) [clarity/consistency] rename /explorev2/ -> /explore/ (#2802) (@ascott)
|
||||
- [a4a2bf7](https://github.com/airbnb/superset/commit/a4a2bf7ae9cc1075a38cc980bb696d6512125f2b) filter_box: allow creatable entries (#2804) (@vavrusa)
|
||||
- [d0a04cd](https://github.com/airbnb/superset/commit/d0a04cde49c86185b779b16f1da05450b1ccf571) apply redux for VisualizeModal (#2795) (@graceguo-supercat)
|
||||
- [69685b9](https://github.com/airbnb/superset/commit/69685b9dcc0c26f819ff7edeedc10ee302e97f83) Fixing country maps (#2801) (@mistercrunch)
|
||||
- [b308a3e](https://github.com/airbnb/superset/commit/b308a3eb4eb08de39edbff6490c06a6bef7b7ce1) Added Country Map : New Visualization tools (#2708) (@ymatagne)
|
||||
- [bfa40bd](https://github.com/airbnb/superset/commit/bfa40bd360021874628477ee3eb2272033cd2d54) [hotfix] 'filter box from and to date filter #2649' (#2785) (@yamdraco)
|
||||
- [b0e2904](https://github.com/airbnb/superset/commit/b0e2904c245e5569473f425af2806271e33a5176) Updating permission when refreshing druid datasource (#2655) (@ShengyaoQian)
|
||||
- [ce506bd](https://github.com/airbnb/superset/commit/ce506bdf65b46f5bccee84ca8254417f63b124a5) Logging a few more actions (#2783) (@mistercrunch)
|
||||
- [922cc03](https://github.com/airbnb/superset/commit/922cc037bf859c935cc5eacbcd96bf6fa004c5fe) 0.18.3-alpha.1 (@mistercrunch)
|
||||
- [8252ada](https://github.com/airbnb/superset/commit/8252ada1f9ac94866b91eac55b77ed6d0ef7d02f) [docs] more details on how filters are applied (#2778) (@mistercrunch)
|
||||
- [a2d2f8b](https://github.com/airbnb/superset/commit/a2d2f8bb8c006adcf80bb2ac18b82f3b486f366a) Enable filter value autocomplete in examples (#2781) (@mistercrunch)
|
||||
- [7c5f61d](https://github.com/airbnb/superset/commit/7c5f61d6a61e1a3cb6d20d0918610abafa2cd326) Adding some STATSD logging (#2715) (@mistercrunch)
|
||||
- [841e18a](https://github.com/airbnb/superset/commit/841e18a08c4b375fdff5b846f5d9f108903a3eb6) [sql lab] make database ordering alphabetical in left panel (#2769) (@mistercrunch)
|
||||
- [dbc7fef](https://github.com/airbnb/superset/commit/dbc7fef7f501cd59ebd99524fa171d9e4dee0325) [sql lab] fix user timestamp is off (#2774) (@mistercrunch)
|
||||
|
||||
### 0.18.2 (2017/05/17 06:08 +00:00)
|
||||
- [cbfe3cb](https://github.com/airbnb/superset/commit/cbfe3cb2dcadedeedfcf55f2bb4883b76a484b36) 0.18.2 (@mistercrunch)
|
||||
- [5fcd25d](https://github.com/airbnb/superset/commit/5fcd25def15b5990c10b5045cb89b88f94ba8716) 0.18.1-alpha.2 (@mistercrunch)
|
||||
- [fe3f5f6](https://github.com/airbnb/superset/commit/fe3f5f69ae83eaf96415926661b272ebb460a4e0) [hotfix] 'No numeric types to aggregate' (@mistercrunch)
|
||||
- [2395fbb](https://github.com/airbnb/superset/commit/2395fbbdaaa5c81c3559f17cedf2e998b8341cb9) Adding `end_result_backend_time` to Query model (#2766) (@mistercrunch)
|
||||
- [960b26c](https://github.com/airbnb/superset/commit/960b26c7a2cad58b39c359f44c385980434dacb8) Show clear and actionable query timeout error message (#2763) (@graceguo-supercat)
|
||||
- [28ac350](https://github.com/airbnb/superset/commit/28ac3504d67f76c31aac23435dd15d76e0ca75bf) 0.18.1-alpha.1 (@mistercrunch)
|
||||
- [ecc00bd](https://github.com/airbnb/superset/commit/ecc00bdd26517a832a35529f0fdd7d17972e6f8f) [explore] a bit less margin in left panel (#2758) (@mistercrunch)
|
||||
- [e794645](https://github.com/airbnb/superset/commit/e7946451d6aa84229d0c70b7a683b29b784ca1a1) fixed 500 error when export dashboard (#2760) (@eeve)
|
||||
- [9b34600](https://github.com/airbnb/superset/commit/9b34600c8e8df72ecbdfaaf94bdf023c08e26701) Remove duplicate text (#2761) (@awbush)
|
||||
- [8846108](https://github.com/airbnb/superset/commit/884610861b8d39da91e4c1bce7934172d2486da9) 0.18.0 (@mistercrunch)
|
||||
- [d9bd3d6](https://github.com/airbnb/superset/commit/d9bd3d646006d9e6ddf2ccded21d7984935c98c8) fix percentage change viz (#2757) (@yileic)
|
||||
- [38375be](https://github.com/airbnb/superset/commit/38375be5c3062caf9f6cd4d6ac62109e1940bd10) Fix issues around % signs and Presto (#2755) (@mistercrunch)
|
||||
- [91d951a](https://github.com/airbnb/superset/commit/91d951ac422a6411e59b2ec195011ea4dc44b0b1) Change hardcoded references to 'User' security model to allow custom class override (#2728) (@RichRadics)
|
||||
|
||||
### 0.18.0 (2017/05/12 03:36 +00:00)
|
||||
- [d79a45f](https://github.com/airbnb/superset/commit/d79a45ff32ff8e2b5d601601507680dccf693bbc) add number format to pivot table (#2703) (@yileic)
|
||||
- [818251f](https://github.com/airbnb/superset/commit/818251fc8519167be7e0730083c4a694972fb06b) make margin consistent (#2753) (@yileic)
|
||||
- [75abd1f](https://github.com/airbnb/superset/commit/75abd1f44a12208fd54f28a1185d40ea8639396a) 0.18.0-alpha.4 (@mistercrunch)
|
||||
- [f55df3b](https://github.com/airbnb/superset/commit/f55df3b18b67ff58d5ad3f6f12f7fe76e9697084) [sql lab] fix responsivity of grid (#2742) (@mistercrunch)
|
||||
- [5dbfdef](https://github.com/airbnb/superset/commit/5dbfdefae82674d71ab1f1464622d199a6f72f30) [sql lab] fix partitionned table has no partitions (#2740) (@mistercrunch)
|
||||
- [e558444](https://github.com/airbnb/superset/commit/e5584440cecdb0d9a79ba6c4ff1050e73e774035) Speed up all CRUD list views (#2747) (@mistercrunch)
|
||||
- [d5e9d5d](https://github.com/airbnb/superset/commit/d5e9d5d045d342ef203c7d7cd480011626b6d7a1) fix auto select override pre-selected value bug (#2745) (@graceguo-supercat)
|
||||
- [3208a01](https://github.com/airbnb/superset/commit/3208a014ffccfe44238fb5982f6e391a1764d4b3) fix dual line chart margin (#2737) (@yileic)
|
||||
- [874c12a](https://github.com/airbnb/superset/commit/874c12ad2d99059b2f8f979bdd05e77d8768db03) 0.18.0-alpha.3 (@mistercrunch)
|
||||
- [22d8075](https://github.com/airbnb/superset/commit/22d8075c536bdfc1790b23381e0017720cc921a5) Making the stop button instantaneous (#2738) (@mistercrunch)
|
||||
- [baebba1](https://github.com/airbnb/superset/commit/baebba115930e95076e9252987fb4e107ddd23d5) 0.18.0-alpha.2 (@mistercrunch)
|
||||
- [04748b4](https://github.com/airbnb/superset/commit/04748b4cdac7a4fd53f5d7716a36ceebea7bf7ca) [SQL Lab] fix gamma metadata access (#2702) (@mistercrunch)
|
||||
- [a471afe](https://github.com/airbnb/superset/commit/a471afe206ca3357ea4c27c1accf94d44c8f5122) [sql lab] improvements to the left panel (#2709) (@mistercrunch)
|
||||
- [5d0a01d](https://github.com/airbnb/superset/commit/5d0a01d0d099a9d73ba04fded7cad223a10e86f2) Decimal is a valid numeric type (#2720) (@hajdbo)
|
||||
- [9e1272e](https://github.com/airbnb/superset/commit/9e1272e97c88a3ce2e8dfd15fa819de52e331342) 0.18.0-alpha.1 (@mistercrunch)
|
||||
- [aeebd88](https://github.com/airbnb/superset/commit/aeebd8840d0551a7cd9a2d43039dcd07648d66ed) [table] fixing CSS glitches on table view (#2725) (@mistercrunch)
|
||||
- [55d3b01](https://github.com/airbnb/superset/commit/55d3b012e504f788732488bf11a1ec7ef223a821) refactor: recentActions ajax call is redundant (#2722) (@S-YOU)
|
||||
- [a6e1e18](https://github.com/airbnb/superset/commit/a6e1e18244951b5bf68ac76e897a16713c7d279b) [sql lab] fix CREATE TABLE AS (#2719) (@mistercrunch)
|
||||
- [46d7a92](https://github.com/airbnb/superset/commit/46d7a925bb4be8891c89ac05d2f447e5ec750bf5) chore: remove unused methods with invalid models.Query usage (#2721) (@S-YOU)
|
||||
- [5929ab7](https://github.com/airbnb/superset/commit/5929ab76890232068bef5412f23a54226dbed0ec) [dashboard] fix missing datasource issue (#2718) (@mistercrunch)
|
||||
- [fffb7b5](https://github.com/airbnb/superset/commit/fffb7b500a313b9f9d76eecab18241bf0406c933) [sql lab]Add autoSelect (#2713) (@graceguo-supercat)
|
||||
- [cb14640](https://github.com/airbnb/superset/commit/cb14640a823c3c6cc768169391779064c2469a68) Removing uneeded results_backends.py (#2717) (@mistercrunch)
|
||||
- [d65054e](https://github.com/airbnb/superset/commit/d65054e01533f62e63e1c8788da4b97309f65cee) [sql lab] fix csv export where `%` in query (#2711) (@mistercrunch)
|
||||
- [5d5060e](https://github.com/airbnb/superset/commit/5d5060eca61ad1a7f6baf7adced2985088c82d95) Remove unecessary handling of %% (#2714) (@mistercrunch)
|
||||
- [9ff3515](https://github.com/airbnb/superset/commit/9ff351532ada993afc4da5060b9a942216e2a74b) Basic integration with ClickHouse (#1844) (@vavrusa)
|
||||
- [59a6f44](https://github.com/airbnb/superset/commit/59a6f447ec1e92a0319a617ecdf4e22847bf5d95) Fix missing curUserId from SliderAdder.jsx (#2705) (@songyanho)
|
||||
|
||||
### 0.17.6 (2017/05/01 20:13 +00:00)
|
||||
- [1887b5e](https://github.com/airbnb/superset/commit/1887b5e934b17864850a46d6e88a606b594e0634) 0.17.6 (@mistercrunch)
|
||||
- [33758bf](https://github.com/airbnb/superset/commit/33758bfff59b9cdc86b58973244ef0613942dc80) 0.17.6-alpha.2 (@mistercrunch)
|
||||
- [2d5beb1](https://github.com/airbnb/superset/commit/2d5beb1f91c304df948e943100cbfb66345a00e9) improve csrf expiration error handling (#2695) (@ascott)
|
||||
- [5fd0e7d](https://github.com/airbnb/superset/commit/5fd0e7d02828df4bb02b6a3b34779517fe637123) [vis] bar values should match y axis format (#2701) (@justinpark)
|
||||
- [ef0c4be](https://github.com/airbnb/superset/commit/ef0c4be06743083da5c33ed9ffbda7ff77b43e74) Fix for referring specific svg (#2612) (@songyanho)
|
||||
- [ac3aba7](https://github.com/airbnb/superset/commit/ac3aba7c7da905f0f4bfeb0f80efb87136812b90) [sql lab] visualization flow: fixing the groupby parameter (#2681) (@mistercrunch)
|
||||
- [0fdb57a](https://github.com/airbnb/superset/commit/0fdb57a18153912c2675b54a2c4e5e00691c7cc0) fix (#2696) (@yileic)
|
||||
- [3e7b5df](https://github.com/airbnb/superset/commit/3e7b5df2876d1014a8411a57cdd7bb18ce64e5d9) [explore] fix empty chart when changing viz type (#2698) (@mistercrunch)
|
||||
- [3cd16cf](https://github.com/airbnb/superset/commit/3cd16cf3680169dd17a542d83c84f94ca8220805) Fix test's warnings (#2697) (@dennybiasiolli)
|
||||
- [a58adc8](https://github.com/airbnb/superset/commit/a58adc862ec28842a3ac7f9f1f205fa1c173015e) Fix orm query in HiveEngineSpec.handle_cursor (#2699) (@xrmx)
|
||||
- [7d88f80](https://github.com/airbnb/superset/commit/7d88f80a9b2003f4529560160aea41c444283a9e) hack to dynamically adjust y axis left margin (#2689) (@yileic)
|
||||
- [09be02f](https://github.com/airbnb/superset/commit/09be02f70a716819332629144160360e21c8920b) fix x axis label (#2691) (@yileic)
|
||||
- [50fcdd3](https://github.com/airbnb/superset/commit/50fcdd3a34f3efe58435760ba0bf321d6767a3a5) Adding tails.com to inthewild (#2685) (@alanmcruickshank)
|
||||
- [dee3649](https://github.com/airbnb/superset/commit/dee36491c5e9394c19dfbc00def353675079aa83) Fix js warnings (#2693) (@dennybiasiolli)
|
||||
- [903612a](https://github.com/airbnb/superset/commit/903612ac6c802dd042417c1fa8a742812a2094bb) fix (#2692) (@yileic)
|
||||
- [ce70505](https://github.com/airbnb/superset/commit/ce705054fa2e738612d746c8f07b577f6941a6e3) fix a bug in 'getMaxLabelSize' and x axis label not shown problem (#2694) (@yileic)
|
||||
- [c589616](https://github.com/airbnb/superset/commit/c5896168830c0901a6488817d970a92ce3fa8f9a) [sql lab] Update event handler name (#2680) (@graceguo-supercat)
|
||||
- [58309f2](https://github.com/airbnb/superset/commit/58309f275f3b9d123f75e795fe3e42b918a66aab) Mark a few more string for translation (#2651) (@xrmx)
|
||||
- [edf4e4f](https://github.com/airbnb/superset/commit/edf4e4f24e9eeceb44e2b9a98d2cb02d8cefa6dd) Update README.md (#2676) (@aioue)
|
||||
- [b3e0b5b](https://github.com/airbnb/superset/commit/b3e0b5b586d530cdd1def10ef38550f680f1922b) Specifying cryptography version in install docs (@mistercrunch)
|
||||
- [6880298](https://github.com/airbnb/superset/commit/68802989bc8a13f76988eed004dc07fa06208733) Pinning cryptography lib to 1.7.2 (@mistercrunch)
|
||||
- [70887d7](https://github.com/airbnb/superset/commit/70887d72e2a54fdae2ba58ad8f408528bd694878) 0.17.6-alpha.1 (@ascott)
|
||||
- [1922225](https://github.com/airbnb/superset/commit/192222504292aed3ffa7368f85ca6cdc7f92aab5) Alternate fix for #2665 (#2671) (@mistercrunch)
|
||||
- [0bdc301](https://github.com/airbnb/superset/commit/0bdc3010d8da0789df99d588105d6e62cc6b3280) [vis] fix pivot table scrolling when using more than 1 groupy col (#2674) (@ascott)
|
||||
- [1df37e6](https://github.com/airbnb/superset/commit/1df37e6e4d609f7c0751faf2360a98a896e30f46) add option for pulling favourited dashboards by username (#2661) (@robert-digit)
|
||||
- [e9ed416](https://github.com/airbnb/superset/commit/e9ed4166549cb515f5c15357b2395c3858736df1) fix csrf error on import_dashboards (#2672) (@ascott)
|
||||
- [03c42b5](https://github.com/airbnb/superset/commit/03c42b5b87429f2a29ce1b5ef8c13e9a004b907e) Showing slices on datasource edit form (#2645) (@mistercrunch)
|
||||
- [e055e6d](https://github.com/airbnb/superset/commit/e055e6d2c22e6087bf7c906174c08d543617a514) Fixing PropTypes warning messages (#2670) (@mistercrunch)
|
||||
- [2978082](https://github.com/airbnb/superset/commit/29780821e8797fee3fbcbcfacbe3e0871750d19b) [druid] fixing the having clause in the explore view (#2648) (@mistercrunch)
|
||||
- [f10ee13](https://github.com/airbnb/superset/commit/f10ee139011767fd72e20ff0fb6a6411f6b06d6b) [druid] fix FilterBox viz gets timestamps as values if granularity != all (#2647) (@mistercrunch)
|
||||
- [cdfc4a3](https://github.com/airbnb/superset/commit/cdfc4a35b22e8b07bf2b0503214074761143e7d9) Optimizing the standalone view (#2663) (@mistercrunch)
|
||||
- [eb762c8](https://github.com/airbnb/superset/commit/eb762c8bfec56a0da664c4aa71baf2197f58042f) add the missing right bracket (#2662) (@yileic)
|
||||
- [83abfef](https://github.com/airbnb/superset/commit/83abfef8304a8fe83248d959136e7421ba0e04a8) superset: fix argument swap for SqliteEngineSpec.get_table_names (#2664) (@xrmx)
|
||||
- [54137ad](https://github.com/airbnb/superset/commit/54137ad023f046780bd0e2089ccc57620787f118) Updating CHANGELOG (@mistercrunch)
|
||||
|
||||
### 0.17.5 (2017/04/21 20:56 +00:00)
|
||||
- [4be6bfa](https://github.com/airbnb/superset/commit/4be6bfafaa07695cf47a9a27977855ab30ff87e4) 0.17.5 (@mistercrunch)
|
||||
- [9ba6d48](https://github.com/airbnb/superset/commit/9ba6d489f31d2aba38594dac3cb7d75fbabcdc78) v0.17.5-alpha.10 (#2654) (@ascott)
|
||||
- [af4bd40](https://github.com/airbnb/superset/commit/af4bd40853d477e5104d62c81931b65be0026b50) fix scrolling on markup vis (#2644) (@ascott)
|
||||
- [84fa0d1](https://github.com/airbnb/superset/commit/84fa0d19407d7fe662ea1945bb0f9e2570945e50) don't default sort by to first column (#2653) (@ascott)
|
||||
- [938e13a](https://github.com/airbnb/superset/commit/938e13a4297f13354ae7a989de1268cddbf042c4) [hotfix] Presto's latest_sub_partion rendering fail (@mistercrunch)
|
||||
- [dc364da](https://github.com/airbnb/superset/commit/dc364daffddd740bd827aaaa71d07c13a928c7ef) [query-search] fix scrolling on query search and pagination styling (#2646) (@ascott)
|
||||
- [1cadfec](https://github.com/airbnb/superset/commit/1cadfecd4bc0c69e0c66ddce12727fd5607b4364) update core.py label and zh po file (#2642) (@RoganW)
|
||||
- [5b26667](https://github.com/airbnb/superset/commit/5b26667fd520ccf2b668f9d3f7b1a928a1bdaba7) 0.17.5-alpha.9 (@ascott)
|
||||
- [899caf9](https://github.com/airbnb/superset/commit/899caf94497e22ab8d6a59f695d3805999ab2e4c) [sql-lab] fix scrolling in left hand panel for table meta data (#2641) (@ascott)
|
||||
- [e6063f2](https://github.com/airbnb/superset/commit/e6063f2ddf14ae9ddb8c9fd8b5ebd548e272e7d5) 0.17.5-alpha.8 (@mistercrunch)
|
||||
- [46486f8](https://github.com/airbnb/superset/commit/46486f82d9352cd7d340e4dfb6bd9ba2676b2c6c) Moving the warning message to the navbar (#2640) (@mistercrunch)
|
||||
- [0089762](https://github.com/airbnb/superset/commit/00897629558a4d89c5a500b173b345d8136f52fa) 0.17.5-alpha.7 (@ascott)
|
||||
- [2bd60c0](https://github.com/airbnb/superset/commit/2bd60c074716faf57a8a10e3a9c73b9fe500080f) [vis] fix line chart when slice is really narrow (#2620) (@ascott)
|
||||
- [db6cd21](https://github.com/airbnb/superset/commit/db6cd215040220f3cf3636f1decb25139f395cad) [sqllab] table refactor (#2587) (@ascott)
|
||||
- [f40499e](https://github.com/airbnb/superset/commit/f40499e550ae3ed7fea534b8c657c2c76d9f6070) [dashboard] improve error handling on dashboard (#2624) (@mistercrunch)
|
||||
- [67a85b9](https://github.com/airbnb/superset/commit/67a85b9831f86a78fe987037000c8f2e6bd9c7d7) Fix dashboard edit button is disabled (#2634) (@mistercrunch)
|
||||
- [cb3384b](https://github.com/airbnb/superset/commit/cb3384b3b225c1c392453616ce09c1c9e7136baa) Improving Presto error message in explore/dashboard (#2633) (@mistercrunch)
|
||||
- [ac51a30](https://github.com/airbnb/superset/commit/ac51a30f98019d8cc593f03cd0f542aa35646889) Remove metrics control non-null validator in Table context (#2635) (@mistercrunch)
|
||||
- [91fe02c](https://github.com/airbnb/superset/commit/91fe02cdc879097d517cddc06a8492536bc3b6ea) Setting adjust_database_uri for HiveEngineSpec (#2636) (@mistercrunch)
|
||||
- [76042be](https://github.com/airbnb/superset/commit/76042be7c3b52c5019114b372dc841137205e14f) [hotfix/sqllab] setting up the connection in the try: block (@mistercrunch)
|
||||
- [d3f55a0](https://github.com/airbnb/superset/commit/d3f55a0905e4aa7a2da22113ea8e25c174903c9f) 0.17.5-alpha.6 (@mistercrunch)
|
||||
- [efaef8f](https://github.com/airbnb/superset/commit/efaef8fe0924ff39e77edbe8fe5e2ed337adccf3) [hotfix] fix endpoint (@mistercrunch)
|
||||
- [8757a24](https://github.com/airbnb/superset/commit/8757a24d89e44c13b44b8ae84be9ae12a50b8d48) 0.17.5-alpha.5 (@mistercrunch)
|
||||
- [63785f0](https://github.com/airbnb/superset/commit/63785f039c0f7763c410c9e7a40a0d477b9bf23a) [hotfix] using UTC for caching timestamps (@mistercrunch)
|
||||
- [d6689ee](https://github.com/airbnb/superset/commit/d6689ee700102926ebd7efa352cb3c66d970445f) 0.17.5-alpha.4 (@mistercrunch)
|
||||
- [787daf6](https://github.com/airbnb/superset/commit/787daf6005d325b68a52644804d802a1168cf314) A nice CacheLabel React component (#2628) (@mistercrunch)
|
||||
- [23aeee5](https://github.com/airbnb/superset/commit/23aeee5a9c1c17ef486fa5106da964acc0b4bd43) Slice level cache_timeout isn't taken into consideration (#2631) (@mistercrunch)
|
||||
- [70c6cad](https://github.com/airbnb/superset/commit/70c6cad0e3b5e276158c1d9057de40b6fd9498eb) Add UNIX socket option to runserver (#2627) (@scaba)
|
||||
- [6b1bf3b](https://github.com/airbnb/superset/commit/6b1bf3b395a61a8549b9f3297c8411bb41db52fa) [hotfix] missing explore's main.css (@mistercrunch)
|
||||
- [f5216f6](https://github.com/airbnb/superset/commit/f5216f60479a2580b5a5532ec8c1b0882905d7a0) Adding owner(s) to dashboard makes them own underlying slices (#2610) (@mistercrunch)
|
||||
- [15654a3](https://github.com/airbnb/superset/commit/15654a3082f4d6030fafd38d671299670443374e) fix filters on dashboard (#2619) (@ascott)
|
||||
- [baff0cb](https://github.com/airbnb/superset/commit/baff0cba38554ae28e1024f2114ee5765648c45b) Fix separator widget CSS (#2623) (@mistercrunch)
|
||||
- [c4ee098](https://github.com/airbnb/superset/commit/c4ee098bb7ffc0db970eba608bfe464ee7b3e60b) 0.17.5-alpha.3 (@mistercrunch)
|
||||
- [612b8ca](https://github.com/airbnb/superset/commit/612b8ca3d7de9988f22b8f7f81c583ff0b8b19bc) [hotfix] legacy url not handled properly (@mistercrunch)
|
||||
- [c43a9fd](https://github.com/airbnb/superset/commit/c43a9fd5541d5de0987607d913eddd899ee84e75) [hotfix] fixing the build (@mistercrunch)
|
||||
- [6c68a21](https://github.com/airbnb/superset/commit/6c68a21e4f77757df57042eedbb91a96b21fa040) [sql lab] fix alt-enter runs out-of-date SQL (#2603) (@mistercrunch)
|
||||
- [db02b33](https://github.com/airbnb/superset/commit/db02b33e09dd6391fb1d8f777b19d5c16a511abe) [explore] fix query text modal while loading (#2596) (@mistercrunch)
|
||||
- [2df6baa](https://github.com/airbnb/superset/commit/2df6baa7a741a4bfff786b0f675f1165b122aaac) [sql lab] sorting database names in dropdowns (#2611) (@mistercrunch)
|
||||
- [fc7bd63](https://github.com/airbnb/superset/commit/fc7bd630399c9f4f936b59be347d5d4d0e516744) [sql lab] fixes issues specific to Sqlite (#2606) (@mistercrunch)
|
||||
- [959a09c](https://github.com/airbnb/superset/commit/959a09cc92682854e0051fae302bd866d9d5b8b5) [dashboard] fix css padding for markup viz (#2602) (@mistercrunch)
|
||||
- [366ecef](https://github.com/airbnb/superset/commit/366ecefbaaf4cc31234cc981ebab7eb420efe019) Bumping the JS libs to fix the build (#2616) (@mistercrunch)
|
||||
- [a2b30f3](https://github.com/airbnb/superset/commit/a2b30f35fcc3c081448d55df31ad445d4d9cec6c) 0.17.5-alpha.2 (@mistercrunch)
|
||||
- [8bceda8](https://github.com/airbnb/superset/commit/8bceda8134c6e53f62b5b30910ec0eeb02f051e7) [hotfix] fix iframe viz (@mistercrunch)
|
||||
- [bae1067](https://github.com/airbnb/superset/commit/bae1067015a4b8041d39b806062a45c1950e3f7c) 0.17.5-alpha.1 (@mistercrunch)
|
||||
- [116dca3](https://github.com/airbnb/superset/commit/116dca3e6fc78ef109f0385b6c4dbf2650dda080) validationErrors is undedfined (@mistercrunch)
|
||||
- [b448394](https://github.com/airbnb/superset/commit/b448394077eef18b9ed01c9703c58cf05f14d34c) 0.17.5-alpha.0 (@mistercrunch)
|
||||
- [09f407f](https://github.com/airbnb/superset/commit/09f407f553eb8bca90f6da79cf60c742296488c7) add tooltips to big number vis (#2599) (@ascott)
|
||||
- [0479118](https://github.com/airbnb/superset/commit/0479118efc0069da2b62c20dc631ebbd00493758) 0.17.5.dev0 (@mistercrunch)
|
||||
- [c93411b](https://github.com/airbnb/superset/commit/c93411b1e75bc59b174d1256f3108d783eea3264) Fix for merge string as array (#2597) (@songyanho)
|
||||
- [31283f1](https://github.com/airbnb/superset/commit/31283f14246ccd9f7cac4df238bd65cdd68c840b) Fix metric formating in Dashboard view + some refactoring (#2598) (@mistercrunch)
|
||||
- [93c6597](https://github.com/airbnb/superset/commit/93c6597cf4f2c47869f9cf4f62cfdbe80cd37760) Adding docs/ to .eslintignore (@mistercrunch)
|
||||
- [4446c74](https://github.com/airbnb/superset/commit/4446c745a88d4b31de8a30ccb45b4cd6dcc49dae) Fix backend-sync 2 (@mistercrunch)
|
||||
- [38e90fe](https://github.com/airbnb/superset/commit/38e90fe3098018655a8e2206a053c60c8d7e64aa) Fix backend-sync (@mistercrunch)
|
||||
- [f548946](https://github.com/airbnb/superset/commit/f5489467e534f3625079843cad82ae12de6cbf3a) Use correct dialect for escaping functions. (#2593) (@steveniemitz)
|
||||
- [ab0bc5a](https://github.com/airbnb/superset/commit/ab0bc5a3fa81f3951b50828400de6bfc54235860) handle percentage case for tooltips (#2570) (@ascott)
|
||||
- [412634c](https://github.com/airbnb/superset/commit/412634cb57f6094bbba168d252b8b5dbd56da954) Add missing flask-wtf dependency (#2586) (@xrmx)
|
||||
- [a0ddbb9](https://github.com/airbnb/superset/commit/a0ddbb9ec954a65a77350bc054b83e35bc4dffeb) Make form_data dict a macro (#2585) (@mistercrunch)
|
||||
- [a803705](https://github.com/airbnb/superset/commit/a803705ddca1c869ccd50977d033faa5c8a0464b) [bugfix] clarifying how to create a slice (#2565) (@mistercrunch)
|
||||
- [75a358c](https://github.com/airbnb/superset/commit/75a358c616bf30e15dc752da59de1c3cd333a89c) [explore] force control validation before runQuery (#2544) (@mistercrunch)
|
||||
- [493ba18](https://github.com/airbnb/superset/commit/493ba1836241146502d5dfa4d5c9ea57f4d8ad6c) Adding macros current_user_id & current_username (#2582) (@mistercrunch)
|
||||
- [5e4fca4](https://github.com/airbnb/superset/commit/5e4fca4ea4b896a9c427032f30a30b59efbcec63) Bumping a set of Python libraries to the latest release (#2575) (@mistercrunch)
|
||||
- [d289783](https://github.com/airbnb/superset/commit/d289783b67ef6503f58a330bcd729e3301c20393) Adding Vertica to installation docs (#2581) (@mistercrunch)
|
||||
- [ac84fc2](https://github.com/airbnb/superset/commit/ac84fc2b65976c1473488e2ed47979d880df34f5) Fixing confusion when selecting schema across engines (#2572) (@mistercrunch)
|
||||
- [40b3d3b](https://github.com/airbnb/superset/commit/40b3d3b3ef61124ec38d49130b57d751b98a1a67) [hotfix] add csrf_token api endpoint (@mistercrunch)
|
||||
- [50a9e13](https://github.com/airbnb/superset/commit/50a9e13f9bb9bf0c10ca3b748e1989a15c97ee8a) [hotfix] add csrf_token api endpoint (@mistercrunch)
|
||||
- [66bff01](https://github.com/airbnb/superset/commit/66bff01b45658547d9853e0d0c22e788550d8267) Changelog for 0.17.4 (@mistercrunch)
|
||||
- [9691234](https://github.com/airbnb/superset/commit/9691234b7e33d8162253a6971f6eb298c037b748) [hotfix] casting db_id to int (@mistercrunch)
|
||||
|
||||
### 0.17.4 (2017/04/07 17:57 +00:00)
|
||||
- [ddeabdd](https://github.com/airbnb/superset/commit/ddeabdd048296732c24bb7ca2317e5d3683fa17d) Fixing CSRF issues (#2569) (@mistercrunch)
|
||||
- [3ed45ab](https://github.com/airbnb/superset/commit/3ed45ab98c2e351ced9520bcfce222dd34d45a94) [bugfix] saved query restore wouldn't pick the db (#2568) (@mistercrunch)
|
||||
- [ca08e70](https://github.com/airbnb/superset/commit/ca08e7051ef47b5a8693dc5088c3af23b582b267) 0.17.4rc5 (@mistercrunch)
|
||||
- [1fb21b8](https://github.com/airbnb/superset/commit/1fb21b8b45f1bdde4e89386ec791cfa7620986c4) [revert] reverting big num changes (#2567) (@ascott)
|
||||
- [c581ea8](https://github.com/airbnb/superset/commit/c581ea8661dd229f42d5959a6745a26ce8f03289) Alternative PR for: Some bytes/str issues in py3 w/ zlib and json (#2558) (@rumbin)
|
||||
- [f19d195](https://github.com/airbnb/superset/commit/f19d1958c51212ae19cef98cfa135b8898cb6bea) INTHEWILD: added Endress+Hauser (#2562) (@rumbin)
|
||||
- [9c99be5](https://github.com/airbnb/superset/commit/9c99be510b3aaeb4329e1a33413129e1aaacebdd) [hotfix] iframe viz is broken (@mistercrunch)
|
||||
- [7a08cdc](https://github.com/airbnb/superset/commit/7a08cdcb1c4378986cb1dc6934143a684ab49502) 0.17.4rc3 (@ascott)
|
||||
- [f24ddfd](https://github.com/airbnb/superset/commit/f24ddfd467731d82206b5cf8185ac0c576a8a6f9) [big num] make sure scatterplot dots align properly (#2559) (@ascott)
|
||||
- [23a8ea5](https://github.com/airbnb/superset/commit/23a8ea563693bd10635e0dadd97403958ca9d891) v0.17.4rc2 (@mistercrunch)
|
||||
- [2c04d3c](https://github.com/airbnb/superset/commit/2c04d3c25098d15c9cc6f30a70f787eae6899c74) [bugfix] save dash fails with CSRF related error (#2552) (@mistercrunch)
|
||||
- [337454b](https://github.com/airbnb/superset/commit/337454b646c71bc313714b849dec49b4d7459a4d) [hotfix] slice with missing datasource related (@mistercrunch)
|
||||
- [b7f46eb](https://github.com/airbnb/superset/commit/b7f46ebe75b23d5a26d3c17fd219e1b05bff9327) [hotfix] dashboard fails when a slice is missing its datasource (@mistercrunch)
|
||||
- [10773f9](https://github.com/airbnb/superset/commit/10773f96a7197197bcd5d6dea6d959c081d23156) URL Params macro (#2537) (@mistercrunch)
|
||||
- [b97a827](https://github.com/airbnb/superset/commit/b97a8275d48c40beaff0a6fb7cf56257dd281fe6) Clarify docs on Redis package required for caching (#2557) (@rhunwicks)
|
||||
- [081bdca](https://github.com/airbnb/superset/commit/081bdca71ef4979b77e0b7d5f9ab5cc8e6cde2dc) [hotfix] [sql lab] fix sqlite errors when schema is selected (@mistercrunch)
|
||||
- [62959ca](https://github.com/airbnb/superset/commit/62959ca38ba31e5cc5a1d2b7b9e16bf981f97300) Db2 Grain Correct Data Format (#2545) (@openmax)
|
||||
- [fe68bc3](https://github.com/airbnb/superset/commit/fe68bc31c334e553131cf6e7f6da7d2359646f6c) Revert "measure x axis labels too and use the longest to determine margins" (#2550) (@ascott)
|
||||
- [3d2c791](https://github.com/airbnb/superset/commit/3d2c791ff1279af4c19108ee220a37c24710686a) [bug num vis] fix sizing for single digits (#2548) (@ascott)
|
||||
- [d40ce52](https://github.com/airbnb/superset/commit/d40ce52139d7b9319ac8b86e5d77d3f4998b5926) v0.17.4rc1 (@mistercrunch)
|
||||
- [122891c](https://github.com/airbnb/superset/commit/122891c29b8f46c986207d4903ae584b0ac44a8e) [sql lab] allow users to save their queries (#2528) (@mistercrunch)
|
||||
- [c1d9918](https://github.com/airbnb/superset/commit/c1d9918abeb3bca33721fc5af9be59e89fffccbf) [vis] bug num improvements (#2523) (@ascott)
|
||||
- [d93b1fc](https://github.com/airbnb/superset/commit/d93b1fc686e0f0518b04203e1b65967f6b84d441) [sql-lab] make query history scrollable (#2499) (@ascott)
|
||||
- [02c5cac](https://github.com/airbnb/superset/commit/02c5cac26f853634bb0d244579c366abcb400c77) [hotfix] adding filterable to DruidColumnInlineView.edit_columns (@mistercrunch)
|
||||
- [6566377](https://github.com/airbnb/superset/commit/65663777402c6770b796ca3f65fedc59d756da82) [sql lab] fix table dropdown with large schema make UI unresponsive (#2547) (@mistercrunch)
|
||||
- [db6b2f3](https://github.com/airbnb/superset/commit/db6b2f3ae19740c86a537f031ec7fbee4b341742) pylint errors will now break the build (#2543) (@mistercrunch)
|
||||
- [c31210b](https://github.com/airbnb/superset/commit/c31210b96d0b3aa96e826657da6e6754c87e59a0) Some column description clarifications (#2536) (@mistercrunch)
|
||||
- [dcc6f2a](https://github.com/airbnb/superset/commit/dcc6f2a18fadda5ddb1a507508cf049b9932f02b) serve roboto font locally (#2519) (@ascott)
|
||||
- [0c0666c](https://github.com/airbnb/superset/commit/0c0666caa0e7ce5725416115389fe797113b731c) druid: use six.string_types instead of basestring (#2541) (@xrmx)
|
||||
- [243eead](https://github.com/airbnb/superset/commit/243eeadfd6994c6ac93467a334601fb23278888f) installation instructions for AWS Athena (#2538) (@dwa)
|
||||
- [9ba5b49](https://github.com/airbnb/superset/commit/9ba5b49d8ac197a5ba908b229bd9061ce98c5fca) WIP: Initial commit to support the athena DB (#2531) (@dwa)
|
||||
|
||||
### 0.17.3 (2017/04/01 23:55 +00:00)
|
||||
- [c870bd4](https://github.com/airbnb/superset/commit/c870bd414ecafe9b83f223dd5894544dc34fba0f) 0.17.3 (@mistercrunch)
|
||||
- [4b01e92](https://github.com/airbnb/superset/commit/4b01e92509a903bcc25260749ee055be12e5949c) [dashboard] allow bar charts to scroll on x axis (#2513) (@mistercrunch)
|
||||
- [513a090](https://github.com/airbnb/superset/commit/513a090cdc852c287c62c5d4dc47d6168974251c) [sql lab] address lingering spinner in schema select (#2512) (@mistercrunch)
|
||||
- [abe79d1](https://github.com/airbnb/superset/commit/abe79d1427b94fb126bd3aec5511bbe2c905d94c) Deprecate is_featured as a datasource attribute (#2485) (@mistercrunch)
|
||||
- [b81968d](https://github.com/airbnb/superset/commit/b81968dc2051d0cef22da1633fb315f076c7d94c) Redirect to explore view when saving a table (#2479) (@mistercrunch)
|
||||
- [66cc546](https://github.com/airbnb/superset/commit/66cc546a300d63dd06385a0c35e2268453f70fd6) [hotfix] fixing the (one js lint err in the) build (@mistercrunch)
|
||||
- [6e899ac](https://github.com/airbnb/superset/commit/6e899ac55f5fe093a9081c4001e28b945bc0f8f6) added tobii (#2526) (@dwa)
|
||||
- [6b52384](https://github.com/airbnb/superset/commit/6b523840244ae55519641e621d83aac1342fc51b) [hotfix] fix pending queries race condition (@mistercrunch)
|
||||
- [0a1d8db](https://github.com/airbnb/superset/commit/0a1d8db35783d37c2eea774f2e0c3b4d6a064fde) v0.17.3rc3 (@mistercrunch)
|
||||
- [6f68ddb](https://github.com/airbnb/superset/commit/6f68ddb50516efff1525f6aebc28f67dbad8c38b) Adding to polling states (@mistercrunch)
|
||||
- [4f59abf](https://github.com/airbnb/superset/commit/4f59abf189f9b34654854607c5f943e774fbccbe) v0.17.3rc2 (@mistercrunch)
|
||||
- [5c441f4](https://github.com/airbnb/superset/commit/5c441f4ddb84a58080b577497760ea65b7537f53) [hotfix] queries trigger polling (#2517) (@mistercrunch)
|
||||
- [be023ab](https://github.com/airbnb/superset/commit/be023aba8d972ad5460beed07f768f10398621c4) 0.17.3rc1 (@mistercrunch)
|
||||
- [5399020](https://github.com/airbnb/superset/commit/53990201bc97ad2035e10500eda0d4c935f3bfb1) forgotten query_datasources_by_name function (#2497) (@wyndhblb)
|
||||
- [37783d6](https://github.com/airbnb/superset/commit/37783d685fe7c7b52a3188ace5f1504f8e2eb367) Updating CHANGELOG (@mistercrunch)
|
||||
|
||||
### 0.17.2 (2017/03/29 14:46 +00:00)
|
||||
- [25fdcac](https://github.com/airbnb/superset/commit/25fdcaca8b1dd32c05ecd7fd57d4cf32e8f72447) v0.17.2 (@mistercrunch)
|
||||
- [ce6e7c1](https://github.com/airbnb/superset/commit/ce6e7c135943130fb104b10d284aca93e4f2d4dc) [hotfix] missing logging import in db_engined_specs (@mistercrunch)
|
||||
- [9116766](https://github.com/airbnb/superset/commit/91167665b19ca094fd51dadf9538c12fd61bc55a) Track both query start time and button push time to track delay (#2502) (@mistercrunch)
|
||||
- [f374345](https://github.com/airbnb/superset/commit/f374345860f4a3e307ea1772b099ce038868aa71) Adding a .pylintrc file and a bit of linting (#2507) (@mistercrunch)
|
||||
- [d3b50cb](https://github.com/airbnb/superset/commit/d3b50cb92e046de316725f0e02fdd816573b6234) [explore] remove grey background in standalone mode (#2503) (@mistercrunch)
|
||||
- [a58194b](https://github.com/airbnb/superset/commit/a58194bdb06a966c6d642bdfa7c80195cc9cf996) 0.17.2rc4 (@mistercrunch)
|
||||
- [5f3484a](https://github.com/airbnb/superset/commit/5f3484ac5981f2dd6aa447cbc2e4f2a9afe4518c) Handle errors when the MQ is down (#2494) (@mistercrunch)
|
||||
- [e14b74f](https://github.com/airbnb/superset/commit/e14b74fdbf876aeeeea7baa125926dcf719a0098) [explore] fixing bugs in controls (#2496) (@mistercrunch)
|
||||
- [56f2885](https://github.com/airbnb/superset/commit/56f28859b7315767d3e312aa3777b777156a658d) Fixing filter_box css padding (#2498) (@mistercrunch)
|
||||
- [f3cdb3b](https://github.com/airbnb/superset/commit/f3cdb3b787b804071a8f183569027169e432cb46) Add ibm_db_sa TimeStamp and Datatime Grain Spec. (#2500) (@openmax)
|
||||
- [b35f6b0](https://github.com/airbnb/superset/commit/b35f6b0a94df2017b3bd908c6589d786f9feec6b) 0.17.2rc3 (@mistercrunch)
|
||||
- [5574cfe](https://github.com/airbnb/superset/commit/5574cfef59a7326487f7cebf9a575070ab19a3c2) Fixing out-of-sync security (#2493) (@mistercrunch)
|
||||
- [c301558](https://github.com/airbnb/superset/commit/c3015583ce09f259bf36e018ebd0820f9c0cb92f) Stabilizing master (#2478) (@mistercrunch)
|
||||
- [7cc2c93](https://github.com/airbnb/superset/commit/7cc2c930ede176242cc9066baf16c00fccd23e01) [docs] adding notes on the Public role (#2486) (@mistercrunch)
|
||||
- [2662bf1](https://github.com/airbnb/superset/commit/2662bf19df690c0a133318406a6935a27245a82f) v0.17.2rc2 (@mistercrunch)
|
||||
- [62e3fe2](https://github.com/airbnb/superset/commit/62e3fe2345afa6fa8b8cb0da7f20bb44b48a0e54) [hotfix] SqlaTable has no attribute column_cls (@mistercrunch)
|
||||
- [7d25d17](https://github.com/airbnb/superset/commit/7d25d171e29dce859c455a03d33cc4c3054775c7) [release] update to 0.17.2rc1 (#2492) (@ascott)
|
||||
- [c5859c7](https://github.com/airbnb/superset/commit/c5859c7254448d2cdbc877b00580bd95fa6e7e2e) [hotfix] druid queries 'There was no query executed' issue (@mistercrunch)
|
||||
- [dd7b4b8](https://github.com/airbnb/superset/commit/dd7b4b8310e27310f80a0415a2bd877f3098127b) Revert "[sql-lab] revert react-virtualized-select (#2489)" (#2491) (@ascott)
|
||||
- [93551a6](https://github.com/airbnb/superset/commit/93551a65b845f430aaefaa50f75a40857f1b6ed6) only fetch tables if we have a schema, otherwise reset options. (#2490) (@ascott)
|
||||
- [7eafbab](https://github.com/airbnb/superset/commit/7eafbabe65b430a2347ed6bba3e08d1f4d8c1946) [sql-lab] revert react-virtualized-select (#2489) (@ascott)
|
||||
- [43dd948](https://github.com/airbnb/superset/commit/43dd948476190cf75649164f57a9b73687ca3d99) [sql-lab] performance updates - make ui more responsive (#2469) (@ascott)
|
||||
- [75e7f2d](https://github.com/airbnb/superset/commit/75e7f2d22c7185f2a6393b7ded7a2b5d0558cfca) [hotfix] bumping QUERY_UPDATE_FREQ from 1000 to 2000ms (@mistercrunch)
|
||||
- [26662ee](https://github.com/airbnb/superset/commit/26662eed9e08475a4c41d715f5a3608876a1afd1) Fixed CSS syntax for background linear-gradient (#2482) (@songyanho)
|
||||
- [121b1d0](https://github.com/airbnb/superset/commit/121b1d0951049ac30ab35a225269c03451d14bbc) Refactoring more in the connector base classes (#2431) (@mistercrunch)
|
||||
- [398036d](https://github.com/airbnb/superset/commit/398036d77e0c817796e3735797eae56e80dce437) [hotfix] 'NoneType' object has no attribute 'upper' (@mistercrunch)
|
||||
- [59d5fcf](https://github.com/airbnb/superset/commit/59d5fcf88c0f484a189c7f02968982b2d39512ad) [hotfix] fixing checkboxes in Tables->Columns (@mistercrunch)
|
||||
- [1f8e48b](https://github.com/airbnb/superset/commit/1f8e48b374adb091bf41e60634e99b132a37bf62) [sqllab] assign types for visualize flow (#2458) (@mistercrunch)
|
||||
- [7bf19b1](https://github.com/airbnb/superset/commit/7bf19b12327504aec2be2c2fd36404efb1faec05) [WiP] making doubling '%' not required (#2459) (@mistercrunch)
|
||||
- [1590b8c](https://github.com/airbnb/superset/commit/1590b8c7e5a070183a3c0e3153aec63992e3c60f) Speeding up polling by not checking access (#2466) (@mistercrunch)
|
||||
- [22522fc](https://github.com/airbnb/superset/commit/22522fc05f8859b94299576f4a8b07bd42eaba00) [sql-lab] improve table select performance (#2457) (@ascott)
|
||||
- [c9b59fa](https://github.com/airbnb/superset/commit/c9b59fab1fded7fa08fc9d44a8c18427865e11dd) Update INTHEWILD.md (#2455) (@jakubczaplicki)
|
||||
- [69152e0](https://github.com/airbnb/superset/commit/69152e087a2b9900e53a8a97ed318c271f725649) [explore] remove 'SQL Clauses' section when using Druid (#2449) (@mistercrunch)
|
||||
- [652e572](https://github.com/airbnb/superset/commit/652e572b56054cefdfe83403db2125a9d85f5a6a) [sql-lab] make results table scroll in static container (#2426) (@ascott)
|
||||
- [65c89f5](https://github.com/airbnb/superset/commit/65c89f54dc845ee4f77b230fb334eba225bb14e6) [hotfix] merging db migration scripts (#2448) (@mistercrunch)
|
||||
- [edf5c0e](https://github.com/airbnb/superset/commit/edf5c0e83b2c9023ef3ad9cabc7ce19d32551d84) [dist_bar] fix x scroll when overflowing (#2440) (@mistercrunch)
|
||||
- [a4abbfe](https://github.com/airbnb/superset/commit/a4abbfe1266ab1593ba82ef23d6e733b3d8e8e33) Fix formatting in README.md (#2441) (@imagejan)
|
||||
- [7b28bce](https://github.com/airbnb/superset/commit/7b28bcef15cd37284780e605f5076ede2864afb4) Fix documentation for adding a Redshift database (#2447) (@alexdebrie)
|
||||
- [8042ac8](https://github.com/airbnb/superset/commit/8042ac876e80c08d72489287777cb1e9672b177a) [explore] improved filters (#2330) (@mistercrunch)
|
||||
- [82bc907](https://github.com/airbnb/superset/commit/82bc907088be26206a7c8d1c84311ca399eb73b9) fix a bug in pie chart (#2423) (@yileic)
|
||||
- [e2b572d](https://github.com/airbnb/superset/commit/e2b572d9e229fee503128cab8d7bff02a9cd881b) Prevent alarming users with stacktrace when using sqlite (@mistercrunch)
|
||||
- [e71596d](https://github.com/airbnb/superset/commit/e71596dc45f96e6a3fdfb09f5ee6b00a9cdd018c) make dualline thumbnail have consistent size as other thumbnails (#2434) (@yileic)
|
||||
- [c3be58d](https://github.com/airbnb/superset/commit/c3be58db437746c168e706e8a5710e2a1d363d0d) Add verbose name to db and druid cluster (#2429) (@bkyryliuk)
|
||||
- [3d77a12](https://github.com/airbnb/superset/commit/3d77a12aa9b27375a02f7092c16a2883bd171913) Display the first partition. (#2425) (@bkyryliuk)
|
||||
- [36deb8d](https://github.com/airbnb/superset/commit/36deb8da7157893d08d01148ab538f963aacf140) Allow users to alter column types (#2424) (@mistercrunch)
|
||||
|
||||
### 0.17.1 (2017/03/16 15:44 +00:00)
|
||||
- [05ee8c0](https://github.com/airbnb/superset/commit/05ee8c0e3675b0ab88cf85d061971177ed871144) v0.17.1 (@mistercrunch)
|
||||
- [5ca55a5](https://github.com/airbnb/superset/commit/5ca55a55858a59f6340284cfe4081fd26d2be489) [hotfix on dist_bar] bringing back overwritten handling of ints and tuples (@mistercrunch)
|
||||
- [1b330a8](https://github.com/airbnb/superset/commit/1b330a8c55f0ec114970855c6682627434216ab5) Use connector registry for metrics (#2420) (@bkyryliuk)
|
||||
- [696678c](https://github.com/airbnb/superset/commit/696678c9816d934c10243395e12e8483e2a42df0) Replace query once query response returned (#2415) (@vera-liu)
|
||||
- [20aec3c](https://github.com/airbnb/superset/commit/20aec3cfcad082f921cdfc347382b2d0d4a4fd54) Use connector registry to fetch the table column class. (#2419) (@bkyryliuk)
|
||||
- [4ded37e](https://github.com/airbnb/superset/commit/4ded37e71edf1306ee9652cf32324b5dc14a1328) [hotfix] handle missing or empty column type (@mistercrunch)
|
||||
- [0674ed8](https://github.com/airbnb/superset/commit/0674ed846c478bd97e7b6953c375b5a3ab26802b) Use list instead of numpy array (#2412) (@bkyryliuk)
|
||||
- [3107152](https://github.com/airbnb/superset/commit/3107152f5bb973b8b1a9c5cf3bc2bee1d7f47e0d) Revert "Preprocess the where clauses." (#2411) (@bkyryliuk)
|
||||
- [5b19528](https://github.com/airbnb/superset/commit/5b19528662f5ea645ead5b066144d69469ecbf7c) Display full name. (#2378) (@bkyryliuk)
|
||||
- [357773c](https://github.com/airbnb/superset/commit/357773c631ad39260109ec45d9c313d6d45cea89) Preprocess the where clauses. (#2405) (@bkyryliuk)
|
||||
- [5e43d07](https://github.com/airbnb/superset/commit/5e43d074c3be9b909fe0b473f00e743b4ba9d56e) [explore ] templating can now reference query elements (#2388) (@mistercrunch)
|
||||
- [08bdcd5](https://github.com/airbnb/superset/commit/08bdcd52b856f5ed6c91ab9c3805cf259223da0a) Fix bad d3.format metric setting and/or value === Infinity (#2399) (@mistercrunch)
|
||||
- [0b8522b](https://github.com/airbnb/superset/commit/0b8522be502988d8b9bf64a8ea203068adf5957d) [filter_box] fix time filter and inverted instantFilter (#2402) (@mistercrunch)
|
||||
- [c02a7fe](https://github.com/airbnb/superset/commit/c02a7fe7634b311c6f42968a9f7bafef147092e1) Add more tests to Save Modal specs (#2313) (@vera-liu)
|
||||
- [dcd5bde](https://github.com/airbnb/superset/commit/dcd5bdeb00b8333d67234bde79397b5195fbb8f9) fix unicode issues (#2308 #2282) (#2401) (@asdf2014)
|
||||
- [562b4f0](https://github.com/airbnb/superset/commit/562b4f04156f20a2aeec8d2c27758571d0aaa514) Do not silence error message for query. (#2396) (@bkyryliuk)
|
||||
- [6160a3f](https://github.com/airbnb/superset/commit/6160a3fdffdcebe618191462633414c0dff7de30) Implement stop query functionality. (#2387) (@bkyryliuk)
|
||||
- [0779da6](https://github.com/airbnb/superset/commit/0779da6d244c5686f6ab5faf2ef5067019266460) Keep column order in .csv (#2377) (@bkyryliuk)
|
||||
- [740624b](https://github.com/airbnb/superset/commit/740624ba01edcfa305d6ff0a2676d413e59377f4) Fix monthly time grain in sqllite (#2380) (@bkyryliuk)
|
||||
- [2969cc9](https://github.com/airbnb/superset/commit/2969cc9993325acc730b794f9d0d0b07fe1a60ec) Refactoring Druid & SQLa into a proper "Connector" interface (#2362) (@mistercrunch)
|
||||
- [9a8c3a0](https://github.com/airbnb/superset/commit/9a8c3a044710bcfc578b77b498af1f15685f2bca) [table] metric ordering is wrong in some cases (#2373) (@mistercrunch)
|
||||
- [e817382](https://github.com/airbnb/superset/commit/e817382efd5f18e09534a70f95cc47332288356e) Add more tests to Filter spec (#2315) (@vera-liu)
|
||||
- [422d1fe](https://github.com/airbnb/superset/commit/422d1feb3e2ac964b77cd9756ed0fc1293056373) 0.17.1rc2 (@mistercrunch)
|
||||
- [2b0cb2b](https://github.com/airbnb/superset/commit/2b0cb2b0a56d033cd59c13ae3326c3d922d53b22) Fix partition query (#2353) (@bkyryliuk)
|
||||
- [705d09d](https://github.com/airbnb/superset/commit/705d09d3d07e05e3a5e070d25a348a45288d7721) Remove duplicate (#2351) (@bkyryliuk)
|
||||
- [9114d86](https://github.com/airbnb/superset/commit/9114d86ecd0dbd0ad20c24d56f1fd29604de2047) Add hive to superset + monkey patch the pyhive (#2134) (@bkyryliuk)
|
||||
- [ad4a950](https://github.com/airbnb/superset/commit/ad4a950b5646abef823357274298014292af091f) Fixes filters emitted from table viz (#2335) (@mistercrunch)
|
||||
- [bd480e0](https://github.com/airbnb/superset/commit/bd480e0c6b9d5127d96d8c18fd53ebe6193aec70) Fix duplicate property DruidDatasource.database (#2348) (@mistercrunch)
|
||||
- [af3415b](https://github.com/airbnb/superset/commit/af3415b0406399ba41c1592d31440b722556f90b) [filter_box] option to delay filtering with apply button (#2338) (@mistercrunch)
|
||||
- [b4a96bd](https://github.com/airbnb/superset/commit/b4a96bd8409d38462ea14d2fbafa2f975defd741) Fix for RuntimeError: dictionary changed size during iteration (#2320) (@moranrf)
|
||||
- [9d8d421](https://github.com/airbnb/superset/commit/9d8d4213840cc07d95ac971437632aeae4ff58b5) [hotfix] fix world map (@mistercrunch)
|
||||
- [f6ffc00](https://github.com/airbnb/superset/commit/f6ffc007481c658293ae209982dfc369c0f82f95) Allow running Flask Blueprints alongside Superset (#2337) (@mistercrunch)
|
||||
- [e35016f](https://github.com/airbnb/superset/commit/e35016f07d3880cd557f48c72c617e68d61b125d) remove unneeded tooltip/description text (#2303) (@ascott)
|
||||
- [af8e252](https://github.com/airbnb/superset/commit/af8e2523a820080e06aaf3e50ff309ada1422bc6) fix version (#2336) (@ascott)
|
||||
- [492df94](https://github.com/airbnb/superset/commit/492df94b2a3a4767af40edfb5ab074632baaea4d) [sqllab] reserved words should be upper case (#2316) (@mistercrunch)
|
||||
- [b62f7e2](https://github.com/airbnb/superset/commit/b62f7e2820fc140a318b69b84c54a8a5fe965ed0) [version] use rc for production only releases (#2334) (@ascott)
|
||||
- [5cc2fc1](https://github.com/airbnb/superset/commit/5cc2fc157cfc2dc14363424533eade67e1f48543) v0.17.1 (#2333) (@ascott)
|
||||
- [266c049](https://github.com/airbnb/superset/commit/266c049f2df96bb7c815c91dd9f650fbefd6b513) Fix bug with breakdown (#2312) (@vera-liu)
|
||||
- [4e848c8](https://github.com/airbnb/superset/commit/4e848c8cb55be50c5c5ddbb58694b20d4223a2a3) Updating CHANGELOG (@mistercrunch)
|
||||
- [efff1ac](https://github.com/airbnb/superset/commit/efff1ac4a1d2b26ef932ac6937be0456fb901c09) Temp hack to make druid filters work in dashboard (#2300) (@vera-liu)
|
||||
- [fc64a75](https://github.com/airbnb/superset/commit/fc64a75fbd5a3aed7a62b741a9a057acb2b9dca8) v0.17.0 (#2298) (@vera-liu)
|
||||
|
||||
### 0.17.0 (2017/02/28 19:47 +00:00)
|
||||
0.17.0 introduces major changes that **YOU CANNOT ROLLBACK FROM**, take
|
||||
a backup of your app's database before starting the upgrade progress.
|
||||
|
||||
* **bookmarks:** the URL scheme for the explore view changed, but previous
|
||||
URLs are still supported, though there may be some edge cases there
|
||||
* **translations**: 0.17.0 has a major regression around translations as
|
||||
much of the logic in the explore view moved from the backend to the frontend
|
||||
where we currently do not have a translation framework setup. If
|
||||
translations are important to you, you should skip 0.17.* and get involved
|
||||
in getting translations to work well in future versions. `1.0` will have
|
||||
translations
|
||||
|
||||
- [dd9f431](https://github.com/airbnb/superset/commit/dd9f431b6fe6179ebdae015a375640adccb388c0) v0.17.0 (@mistercrunch)
|
||||
- [c894c54](https://github.com/airbnb/superset/commit/c894c54d00af8b6981c8aafcde02be7195973a38) [table] Allowing to show the time grain in table view (#2294) (@mistercrunch)
|
||||
- [4d349c7](https://github.com/airbnb/superset/commit/4d349c788559ee3fd7de6792d0e153b98d799487) [hotfix] Fix filter for sqlalchemy and druid (#2293) (@vera-liu)
|
||||
- [675b819](https://github.com/airbnb/superset/commit/675b819e0a2601b23e21b37aedf0b49757e218f4) Revert "[hotfix] Fix druid filters" (#2292) (@vera-liu)
|
||||
- [09f1083](https://github.com/airbnb/superset/commit/09f1083c509a690c1f5fcf68f9823fea661ba80f) [table viz] allow showing time granularity in table (#2284) (#2291) (@vera-liu)
|
||||
- [47be3ef](https://github.com/airbnb/superset/commit/47be3ef3ea385925b5ef67cdecb0ba36adc2b3db) Fixing bugs in Sankey diagrams (#2290) (@mistercrunch)
|
||||
- [9dd7778](https://github.com/airbnb/superset/commit/9dd7778597e3429c7bb93788172a2850dd33656e) [table viz] allow showing time granularity in table (#2284) (@mistercrunch)
|
||||
- [efffa92](https://github.com/airbnb/superset/commit/efffa925edf3f54f76acb03660a5b85728133004) rc7 (@mistercrunch)
|
||||
- [fa9bc92](https://github.com/airbnb/superset/commit/fa9bc92c9551669d5dc1fb99f06e8d49052938d1) [hotfix] filters broken on multi-datasource dashboards (@mistercrunch)
|
||||
- [227c66c](https://github.com/airbnb/superset/commit/227c66c2c50dd88bdc1ae4eb81dcd2f8189aea98) [hotfix] add regex for druid filters (#2288) (@vera-liu)
|
||||
- [e91bc9d](https://github.com/airbnb/superset/commit/e91bc9dfcceeb22b88efd57e6defe80d520079f0) added gcc-c++ for RHEL OS dependencies (#2286) (@soccerties)
|
||||
- [bc29035](https://github.com/airbnb/superset/commit/bc29035bdadad7c2df6d430661314a02d1bafea4) 0.16.1rc6 (@mistercrunch)
|
||||
- [f10e453](https://github.com/airbnb/superset/commit/f10e453c9bf0a0988769e7a5f126e94e40b50a49) Fixing bar charts x_axis labels (#2280) (@mistercrunch)
|
||||
- [d4b59b3](https://github.com/airbnb/superset/commit/d4b59b36a801e0f50cde85c15da0538848a5a202) Fixed a bug when querying with schema path to Redshift/Postgresql (#1789) (@sungjuly)
|
||||
- [4f644cd](https://github.com/airbnb/superset/commit/4f644cd0cae02af685cb12e42edc2875cb32acca) 0.16.1rc5 (@mistercrunch)
|
||||
- [ed2935e](https://github.com/airbnb/superset/commit/ed2935ec69d72765d66d8c9afe45e0a0b070cc6a) Fixing multi value parsing on old URL (#2277) (@mistercrunch)
|
||||
- [ea72c6b](https://github.com/airbnb/superset/commit/ea72c6b0188e9c5a662358e89c95801b319296f8) [bugfix] css editor dooesn't pop up (#2243) (@mistercrunch)
|
||||
- [2df6ab3](https://github.com/airbnb/superset/commit/2df6ab36bf5dab7366ff76fc8d9454cb62a49046) Add Udemy to INTHEWILD (#2275) (@sungjuly)
|
||||
- [10ea635](https://github.com/airbnb/superset/commit/10ea63557a29859e09cbc5bf93a539a9b9f3ea55) [hotfix] not grouped by -2 (@mistercrunch)
|
||||
- [55e462d](https://github.com/airbnb/superset/commit/55e462d90b0d01baca8d5c5f2877220b039524ce) 0.16.1rc3 (@mistercrunch)
|
||||
- [7339392](https://github.com/airbnb/superset/commit/73393925c0482007e498afa745be6d20d8c49b83) [hotfix] Table view doesn't allow SELECT (no group by) (#2274) (@mistercrunch)
|
||||
- [f9852bc](https://github.com/airbnb/superset/commit/f9852bc807f5335987d0d3d46c665b975a5fb0c1) v0.16.1rc2 (#2272) (@ascott)
|
||||
- [6e1901e](https://github.com/airbnb/superset/commit/6e1901e8e83d9e2a6e5fc20e3f8e3e996e1ea712) d is not defined, fix (#2270) (@ascott)
|
||||
- [8758296](https://github.com/airbnb/superset/commit/87582962d98424050ff6f61794fd42fe1f5c0c2f) [Hotfix] access slice_id when slice exists (#2268) (@vera-liu)
|
||||
- [3de2698](https://github.com/airbnb/superset/commit/3de2698657b389476a9778754fcbc6fb5acc6853) Introducing support for pre-depercate_v1 URL scheme (#2267) (@mistercrunch)
|
||||
- [ec1f022](https://github.com/airbnb/superset/commit/ec1f0221cd48bb168d0280f55082832d73583f04) Parse filter values for possible integers and floats (#2263) (@vera-liu)
|
||||
- [4d900c9](https://github.com/airbnb/superset/commit/4d900c9ee1e2ab2db0bf42a2c14268cf4ce91186) Do not add slice_name when slice doesn't exist (#2265) (@vera-liu)
|
||||
- [3a75890](https://github.com/airbnb/superset/commit/3a758900eb295039c52be89ecfc13e1260c9b1da) [hotfix] separator renders markdown (@mistercrunch)
|
||||
- [1ea7178](https://github.com/airbnb/superset/commit/1ea7178d17c5b2459e36d213611abcaac0b05620) v0.16.1rc1 (#2260) (@ascott)
|
||||
- [c85c998](https://github.com/airbnb/superset/commit/c85c9988df3d4bba2a9bce36ebfa681225400e42) fix index error for bar charts (#2258) (@ascott)
|
||||
- [34f6807](https://github.com/airbnb/superset/commit/34f68073a28d3dacc4162df7c0e2421cb527afe1) Default action to overwrite for users with overwrite permissions (#2257) (@vera-liu)
|
||||
|
||||
### 0.16.1 (2017/02/24 18:56 +00:00)
|
||||
- [acc880c](https://github.com/airbnb/superset/commit/acc880c4dfc2a02b8d46249895259961e2574c42) [v0.16.1] bump version for prod release (#2250) (@ascott)
|
||||
- [557b557](https://github.com/airbnb/superset/commit/557b557503b1835412337a4d0d4a574535133ec1) [bugfix] avoid caching errors (#2244) (@mistercrunch)
|
||||
- [3018356](https://github.com/airbnb/superset/commit/301835658838fc0d9cb2d807ee8fa06b0ed44550) Support more druid postaggregations. (#2235) (@bkyryliuk)
|
||||
- [ede4dff](https://github.com/airbnb/superset/commit/ede4dffcb71f6d31f9c062af4bcdeeaa9d4ca252) Add trailing slash (#2236) (@bkyryliuk)
|
||||
- [cad392e](https://github.com/airbnb/superset/commit/cad392eb768e65f11b664ad1e2aeffa9741e1bd4) Fetch schemas separately. (#2227) (@bkyryliuk)
|
||||
- [0296158](https://github.com/airbnb/superset/commit/02961581005ddb3abea89b38b1cce6af9247b8db) [docs] more specific about python versions (@mistercrunch)
|
||||
- [b2a4692](https://github.com/airbnb/superset/commit/b2a4692a02a2e6864aa1a8c66f7f63502be3e40e) 0.16.0rc3 (@mistercrunch)
|
||||
- [2fbadea](https://github.com/airbnb/superset/commit/2fbadea9e328554312742d7a8259d7f773ad314a) Fixing exploring a table (#2233) (@mistercrunch)
|
||||
- [dc05be3](https://github.com/airbnb/superset/commit/dc05be36a60237c930ca60184bbbc054182eeab1) Check if the query is in state first. (#2226) (@bkyryliuk)
|
||||
- [dac0d1d](https://github.com/airbnb/superset/commit/dac0d1d0dce2f5ab0c1d5b43814773688ef033c3) 0.16.0rc2 (@mistercrunch)
|
||||
- [459f716](https://github.com/airbnb/superset/commit/459f7160ac7587f92c8213b496fb64518329c1be) Fixing filtering issues (#2223) (@mistercrunch)
|
||||
- [aff524d](https://github.com/airbnb/superset/commit/aff524d84389b605e2f390350f4608f12ed67241) **Allow user to put dbname in url (#2209) (@vera-liu)
|
||||
- [3a91667](https://github.com/airbnb/superset/commit/3a91667e92e0b3bbadd0df4d35d03558268fb6d3) Update cache for the command line command. (#2213) (@bkyryliuk)
|
||||
- [3e0d358](https://github.com/airbnb/superset/commit/3e0d3584f77b2f493687c1c61af63fb4f321bd36) v0.16.0rc1 (@mistercrunch)
|
||||
- [1e47d6f](https://github.com/airbnb/superset/commit/1e47d6fb41b8095e2ab24704c8340c16cf8c13e6) Renaming field to control (#2210) (@mistercrunch)
|
||||
- [d5ba88b](https://github.com/airbnb/superset/commit/d5ba88b4072d45efbb82cc6492645627560794c1) Fixing the CACHING (#2203) (@mistercrunch)
|
||||
- [#2202](https://github.com/airbnb/superset/pull/2202) Merge pull request #2202 from mistercrunch/clean_cli (@mistercrunch)
|
||||
- [ec84aa7](https://github.com/airbnb/superset/commit/ec84aa75770b8a6c8f40f6519596571a5dfb48b5) Fixing typo (@mistercrunch)
|
||||
- [8b4d72c](https://github.com/airbnb/superset/commit/8b4d72cf32fbaa05a196995246090907e197bf7f) Reverting react-select to rc2 (@mistercrunch)
|
||||
- [85e6e65](https://github.com/airbnb/superset/commit/85e6e65a47e5d419b181876f2659038461b24974) Fixing the build (@mistercrunch)
|
||||
- [7cad365](https://github.com/airbnb/superset/commit/7cad3655f5f0638acc76e2a0396baeb28702906a) Bumping react-select to 1.0.0-rc.3 (@mistercrunch)
|
||||
- [b9e7f29](https://github.com/airbnb/superset/commit/b9e7f292c38610a23b75b57cf2ba04d1722fa94f) Cleaning up CLI stdout on startup (@mistercrunch)
|
||||
- [fc85034](https://github.com/airbnb/superset/commit/fc85034c60422d3b504e039e6af87dfd2608d12a) Better error handling for presto (#2161) (@vera-liu)
|
||||
- [f5e3d0c](https://github.com/airbnb/superset/commit/f5e3d0cc02628a51178001eecb65eaa6f04ec667) [hotfix] incompatible diamond flask-sqlalchemy version (@mistercrunch)
|
||||
- [fe377e8](https://github.com/airbnb/superset/commit/fe377e8b9472cc6d16cb2034c2876c758df7ba34) [hotfix] dashboard won't load, error in fields.js (@mistercrunch)
|
||||
- [5bb8713](https://github.com/airbnb/superset/commit/5bb87138e95a07f604e5b82dbac460b6ece06a40) [hotfix] Trends example slice is broken (@mistercrunch)
|
||||
- [579e582](https://github.com/airbnb/superset/commit/579e58206e16b53e49fc736569d6d4ab4e234f70) Bumping up some of the python lib deps (@mistercrunch)
|
||||
|
||||
### 0.16.0 (2017/02/17 01:48 +00:00)
|
||||
- [172b6ce](https://github.com/airbnb/superset/commit/172b6ce8920f79a78e19d49197864ac72ea6647a) v0.16.0 (@mistercrunch)
|
||||
- [0cc8eff](https://github.com/airbnb/superset/commit/0cc8eff1c3f4296bccf495c9deba01eb73b72b83) [WiP] Deprecate Explore v1 (#2064) (@mistercrunch)
|
||||
- [3b023e5](https://github.com/airbnb/superset/commit/3b023e5eaa7e5a4be7957a2a48a90672d2c65e71) add css to the data object to be saved (#2188) (@ascott)
|
||||
- [615d8f1](https://github.com/airbnb/superset/commit/615d8f1624d890f6ce0d5bfe7469394a9245759b) Moving branding assets to folder (@mistercrunch)
|
||||
- [b4409ac](https://github.com/airbnb/superset/commit/b4409ace2171158350ac6243e6b72bce6f89a864) Adding branding assets in the repo (@mistercrunch)
|
||||
- [dbee6ac](https://github.com/airbnb/superset/commit/dbee6aca1fbe2d48c685b3976acbb8dfff3f0624) use pre-wrap for long lines (#2181) (@ascott)
|
||||
- [acfe62e](https://github.com/airbnb/superset/commit/acfe62eaf793da4711a90cdb69aa6ec1ea292447) Add command to refresh datasources (#2180) (@bkyryliuk)
|
||||
- [527a8af](https://github.com/airbnb/superset/commit/527a8af060798c014cde0f9b32d31a2e6540dd57) Return original state for query if query was stopped (#2164) (@vera-liu)
|
||||
- [a5a931a](https://github.com/airbnb/superset/commit/a5a931a670871a9d6f1db9310512c5a064f005a0) Fix werkzeug instance was created twice in Debug Mode (#2135) (#2136) (@asdf2014)
|
||||
- [2f05efa](https://github.com/airbnb/superset/commit/2f05efaf121f6bbcd091f88630115a7e006717c4) Set default time range of query search to the past month (#2162) (@vera-liu)
|
||||
- [83ef8a2](https://github.com/airbnb/superset/commit/83ef8a2e1274ba57f1a64e5e71c94b021da4d933) Add parsing for nested json objects in resultset (#2163) (@vera-liu)
|
||||
- [c564881](https://github.com/airbnb/superset/commit/c564881867abcda7b8dc354e6e2205371ab0a97c) Implement caching and dynamic data fetching. (#1466) (@bkyryliuk)
|
||||
- [b16930f](https://github.com/airbnb/superset/commit/b16930f35dbba1a7d5e3a625dfb4a181cc3aa182) Keep order of axis data when storing df (#2092) (@vera-liu)
|
||||
- [2d910e3](https://github.com/airbnb/superset/commit/2d910e3f07b1e86efba69c6d8e07dbdb5f63ce37) [vis] render line breaks in TableViz (#2118) (@ascott)
|
||||
- [daa1420](https://github.com/airbnb/superset/commit/daa1420c8ec31a813d836474e3e2b04c4db54ab7) adding tests for #1131 (#1902) (@SalehHindi)
|
||||
- [cea310e](https://github.com/airbnb/superset/commit/cea310e50b61f3c8c37d86207dd982d35ba19e28) Using the time zone with specific name for querying Druid (#2143) (@asdf2014)
|
||||
- [fcdd5c6](https://github.com/airbnb/superset/commit/fcdd5c67523a81ffc6db68dbe27d13deb00b6084) [slices axis] fix axis spacing on dashboard and explore slices (#2145) (@ascott)
|
||||
- [2ace73e](https://github.com/airbnb/superset/commit/2ace73e9a1f1cf1a20eff632d08ea440f5f88607) [sql-lab] make datasource name in visualize flow more descriptive (#2103) (@ascott)
|
||||
- [80cfb08](https://github.com/airbnb/superset/commit/80cfb08794d3c8d91514f9b7731b057664628cf3) only call drawGraph once (#2132) (@ascott)
|
||||
- [1edc2b9](https://github.com/airbnb/superset/commit/1edc2b91cf15f669097939c36c6bc8acef5b5913) Fix ExtDeprecationWarning (#2137) (#2138) (@asdf2014)
|
||||
- [1f58e18](https://github.com/airbnb/superset/commit/1f58e18b6f134e2ad4c6865c6b63b40135889ebc) Some code refactoring (#2139) (@asdf2014)
|
||||
- [f2bf316](https://github.com/airbnb/superset/commit/f2bf3160583533bd0dc5004f248f81251aa8c57e) Add NUMERIC num_type (#2127) (@auxsvr)
|
||||
- [9cd38fa](https://github.com/airbnb/superset/commit/9cd38fa1eda63152c27b76c29dd948f29444b686) little code refactor in models.py (#2124) (@asdf2014)
|
||||
- [edb0111](https://github.com/airbnb/superset/commit/edb0111775a05ed164019246ee3d7764a9fdba67) Increase query limit to 1M, add separate display limit. (#2111) (@bkyryliuk)
|
||||
- [#2113](https://github.com/airbnb/superset/pull/2113) Merge pull request #2113 from airbnb/byolken/s3_cache_implementation (@airbnb)
|
||||
- [461e41c](https://github.com/airbnb/superset/commit/461e41cd610d1bff33ac10c6ea5879b498a16f41) Use BytesIO instead of StringIO for python2/3 compatibility
|
||||
- [7164061](https://github.com/airbnb/superset/commit/716406198e50b04d2f6600c518b01f65ad690748) Clean up imports of cPickle and StringIO
|
||||
- [68592ae](https://github.com/airbnb/superset/commit/68592aeddfdd88a2cb291533a9e595cff9b5d6d2) Fix StringIO import in results_backends module
|
||||
- [b927ff6](https://github.com/airbnb/superset/commit/b927ff6eef7e948be1f2a7e828f0d7de9458d2c2) Fix indentation errors in results_backends module
|
||||
- [ce50e6e](https://github.com/airbnb/superset/commit/ce50e6e4fe2147cdf61288d687d49e174f3b7b1d) Fix python3 cPickle import errors
|
||||
- [167ed33](https://github.com/airbnb/superset/commit/167ed33bba160f091e613bc2a351ca5ddc7c8189) Fix name of test in results_backends_tests module
|
||||
- [0ee1abf](https://github.com/airbnb/superset/commit/0ee1abf31a021d2c9e40d9b3c321fce14d4d7179) Misc. fixes in response to code review feedback
|
||||
- [6a0a1af](https://github.com/airbnb/superset/commit/6a0a1af67ebfc11fde51eb3d77db7b9ac6569c3c) Fix misc. style issues
|
||||
- [f85481d](https://github.com/airbnb/superset/commit/f85481d51b3481d7e0ee7f9b73991fb5e2b219ef) Fix long lines in superset/results_backends.py
|
||||
- [00b6b0a](https://github.com/airbnb/superset/commit/00b6b0ac68571df1a7c8e16fd0e79c64cbfe0a60) Misc. style tweaks to S3Cache changes and tests
|
||||
- [1546b1a](https://github.com/airbnb/superset/commit/1546b1ae716d47dad7c583100dbf73665d88aa3b) Add tests for S3Cache
|
||||
- [1e94498](https://github.com/airbnb/superset/commit/1e94498d9d548cbea6466a45dafa3b919c65bd1f) Add initial implementation of S3Cache
|
||||
- [0f7189b](https://github.com/airbnb/superset/commit/0f7189b859f4a782fd43af694012029645f81b44) Do not fail is the filter cannot be parsed. (#2105) (@bkyryliuk)
|
||||
- [a6e0f1b](https://github.com/airbnb/superset/commit/a6e0f1b75a5b60dbb81288b22d78d9686c3b565c) Add an option to configure celery workers size. (#2085) (@bkyryliuk)
|
||||
- [543c22b](https://github.com/airbnb/superset/commit/543c22bb508a90741ff770e50670b412a45e1871) [dashboard] fix nvd3 tooltips (#2096) (@ascott)
|
||||
- [07e067c](https://github.com/airbnb/superset/commit/07e067cf0b8fae39e5e7093914f0fc1795b15f41) Revert "Bump version to 0.15.4.1" (#2095) (@bkyryliuk)
|
||||
- [6c256a3](https://github.com/airbnb/superset/commit/6c256a34a98a9323f1044b138c458d5c60e0e01f) Bump version to 0.15.4.1 (#2094) (@bkyryliuk)
|
||||
- [6b2eb04](https://github.com/airbnb/superset/commit/6b2eb04a73a475b1d597076b15bc39c5e0156842) Put back a default count * metric (#2091) (@bkyryliuk)
|
||||
- [898d80b](https://github.com/airbnb/superset/commit/898d80ba3837b44c00092f9339fc0ba25efc3162) Viz the compiled query rather than user input. (#2086) (@bkyryliuk)
|
||||
- [ea8e4ad](https://github.com/airbnb/superset/commit/ea8e4ad05b7298db023c3cfb5079dff92a5da1d3) Display all columns if none are specified. (#2077) (@bkyryliuk)
|
||||
- [27aeac6](https://github.com/airbnb/superset/commit/27aeac6859da39fea0aebc4920c1fce08fde61e5) Remove fetch results button for async queries (#2084) (@vera-liu)
|
||||
- [8da371e](https://github.com/airbnb/superset/commit/8da371e324e490bec74d80eb84ca040c86dd6765) Make show query button work for v1 (#2080) (@vera-liu)
|
||||
- [0c59fe9](https://github.com/airbnb/superset/commit/0c59fe933d0012eb63acfa02bb51273327b4e218) Only call topn when having_filters don't exist (#2075) (@vera-liu)
|
||||
- [e169c67](https://github.com/airbnb/superset/commit/e169c67760b8ef3b0cafa3eebaf17ea662589ea4) [vis] fix axis labels display (#2066) (@ascott)
|
||||
- [3a5a927](https://github.com/airbnb/superset/commit/3a5a927dc6e43fe095a0b5592505cea09c42f5e4) check if tempTable exists for ctas queries (#2073) (@vera-liu)
|
||||
- [2d419e4](https://github.com/airbnb/superset/commit/2d419e4253c8a8874c1a913b4193402c3a4e0187) Return alert instead of fetch button when async results has no data (#2072) (@vera-liu)
|
||||
- [87869a2](https://github.com/airbnb/superset/commit/87869a29c98b3fadbe1d6879437530f5623d774f) Customize tooltip with axis format (#2068) (@vera-liu)
|
||||
- [544211f](https://github.com/airbnb/superset/commit/544211f5ecbe63958de72bcc014bc4de23f30bb7) Revert "Display no data alert when async result has zero rows" (#2069) (@vera-liu)
|
||||
- [f6ac95e](https://github.com/airbnb/superset/commit/f6ac95e2dd14eff2ba6c86cc1512a88992e18538) Convert objects to json (#2050) (@bkyryliuk)
|
||||
- [63bef2f](https://github.com/airbnb/superset/commit/63bef2f8440620407b6dfe9ebadf8305450fce28) [bugfix] only pop slice_id when it exists in url (#2065) (@vera-liu)
|
||||
- [4a8cd04](https://github.com/airbnb/superset/commit/4a8cd04de6f1fd6aea060ee62968903dc3892fb8) Display no data when async result has zero rows (#2055) (@vera-liu)
|
||||
- [8580662](https://github.com/airbnb/superset/commit/85806624db3d4651bc9d1b15e32b34c9d644cfdd) Use a key-value store model for sharing long queries (#1951) (@vera-liu)
|
||||
- [1ac2273](https://github.com/airbnb/superset/commit/1ac22739848fef09b663ca3fbad9bf84eb706211) Reimplement has_access. (#2028) (@bkyryliuk)
|
||||
- [a8c29c4](https://github.com/airbnb/superset/commit/a8c29c4ffec1bcf631cea0afbb40e95a4817cf07) Change validator of timeshift to allow for strings (#2051) (@vera-liu)
|
||||
- [31af01c](https://github.com/airbnb/superset/commit/31af01c4f2b54c05a0f4bc66c7fcaaa9fe0b0681) Splitting dev-reqs.txt into requirements for development and docs (dev-reqs-for-docs.txt). Updating CONTRIBUTING.md accordingly (#2049) (@dylburger)
|
||||
- [b1bba96](https://github.com/airbnb/superset/commit/b1bba96d04b636d77d557ca066e22d3f2bd3289b) Fix csv download. (#2036) (@bkyryliuk)
|
||||
- [c5c7302](https://github.com/airbnb/superset/commit/c5c730224e6ab89cfbffb26f1c9a1fc0429e2299) Check datasource level perms for downloading csv and fetching results (#2032) (@bkyryliuk)
|
||||
- [7441cf7](https://github.com/airbnb/superset/commit/7441cf7d39ffcdab4def1c9b098203610a067794) Fix inner query labels for Vertica (#2041) (@0x0ece)
|
||||
- [45c72d2](https://github.com/airbnb/superset/commit/45c72d25df68dfceb1bcf5d305700c0972d48407) New administrator tutorial (#2046) (@dylburger)
|
||||
- [3fff631](https://github.com/airbnb/superset/commit/3fff631b32579ed1d3fa5b50349542b83dc62fda) Expanded on documentation section, running through an example of committing a change to the docs end-to-end and describing the process for adding static assets (#2047) (@dylburger)
|
||||
- [bfa2891](https://github.com/airbnb/superset/commit/bfa2891b23426740836226be31e160f0d6e132ae) models: add real to numeric types (#2044) (@xrmx)
|
||||
- [5715f52](https://github.com/airbnb/superset/commit/5715f52fef633473d5e7e1d554a7be97c0840fa8) [hotfix] delete DAR when datasource requested does not exist anymore (#2040) (@vera-liu)
|
||||
- [1f2126f](https://github.com/airbnb/superset/commit/1f2126f4637d6099bb1591f4c7715bd3c4385878) Fix Druid granularity timeZone (#2037) (@0x0ece)
|
||||
- [27ed0b3](https://github.com/airbnb/superset/commit/27ed0b37bf3291a688124be5687738ecb37fa8b3) Cleanup fulfilled requests after approve (#1953) (@vera-liu)
|
||||
- [cdbd2f8](https://github.com/airbnb/superset/commit/cdbd2f850706825f16a08afc40682237d6f6d54f) Guess the filter value type (#1978) (@bkyryliuk)
|
||||
- [e46ba2b](https://github.com/airbnb/superset/commit/e46ba2b4a4f5ccc9f584db0a3c7c1fbaf2b7fdf0) Simplifying the viz interface (#2005) (@mistercrunch)
|
||||
- [1c338ba](https://github.com/airbnb/superset/commit/1c338ba742108139c3fe5885765633f298734be5) [WIP] [explorev2] Refactor filter into FieldSet (#1981) (@vera-liu)
|
||||
- [2b7673a](https://github.com/airbnb/superset/commit/2b7673ad5d95f63b3e251f08f6141f82447d0e23) Fixing pypi_push.sh (@mistercrunch)
|
||||
|
||||
### 0.15.4 (2017/01/24 19:33 +00:00)
|
||||
- [2f27353](https://github.com/airbnb/superset/commit/2f27353015e18a1eab8ca415131023e91adf5399) v0.15.4 (@mistercrunch)
|
||||
- [1b8c3f4](https://github.com/airbnb/superset/commit/1b8c3f420a6f74fa8dd6e5a0762e14d9ba5f7426) avoid py3 error in setup.py (#2030) (@wyndhblb)
|
||||
- [a3a0708](https://github.com/airbnb/superset/commit/a3a070855ccea84e75f89389c835772bbde66d10) Use dist instead of src in mapbox (#2027) (@0x0ece)
|
||||
- [e84c639](https://github.com/airbnb/superset/commit/e84c6393b8658c7e8d9b321c08f0dea33335aa28) Correcting docs to `run npm build` instead of prod (@mistercrunch)
|
||||
|
||||
### 0.15.3 (2017/01/24 16:10 +00:00)
|
||||
- [7413dd9](https://github.com/airbnb/superset/commit/7413dd9f4b99752d064024e764284beabb82a3cc) v0.15.3 (@mistercrunch)
|
||||
- [9cbd667](https://github.com/airbnb/superset/commit/9cbd667eb7af96cb2cafaf05778906110cf50520) [explore-v2] Fix edit datasource link for druid datasources (#1982) (@ascott)
|
||||
- [37fb56c](https://github.com/airbnb/superset/commit/37fb56c61ceb339079ff117971fc91bdd678db80) Week beginning Monday time grain for MySQL (#2014) (@alanmcruickshank)
|
||||
- [404a94c](https://github.com/airbnb/superset/commit/404a94cadbe44a463bda2201b22f268201a7474c) [hotfix] fixing the hotfix (@mistercrunch)
|
||||
- [0807a8d](https://github.com/airbnb/superset/commit/0807a8d0162ff824151df70e7d045f9179668ac0) [hotfix] load selectors in render (@mistercrunch)
|
||||
- [4a98881](https://github.com/airbnb/superset/commit/4a9888157ebcd8513c083f381fdb417fc5f700de) Update INTHEWILD.md (#2000) (@silashundt)
|
||||
- [83fbdcc](https://github.com/airbnb/superset/commit/83fbdcceac0c5ee836345ff6b0fe03b1c2c6d69f) Add Qunar to INTHEWILD (#2001) (@flametest)
|
||||
- [b070ef5](https://github.com/airbnb/superset/commit/b070ef5fdb2ce61b288362878cfd7622d6e1270c) added Digit to inthewild (#1997) (@robert-digit)
|
||||
- [7d380dc](https://github.com/airbnb/superset/commit/7d380dcd14939f8100405f9f1551a3e2a74054ce) Adding Clark.de and Yahoo to INTHEWILD (@mistercrunch)
|
||||
- [a15dbd9](https://github.com/airbnb/superset/commit/a15dbd992d53870280700e6dd15f604bd76aa4fc) Adding Clark.de to INTHEWILD (@mistercrunch)
|
||||
- [52c5d23](https://github.com/airbnb/superset/commit/52c5d235af43f659a36ddd0baeece95756395f1b) Add analysisTypes to refresh druid (#1983) (@noppanit)
|
||||
- [495f646](https://github.com/airbnb/superset/commit/495f6460a40f4a2622f52c03f511778c4060b1f5) Add email functionality (#1914) (@bkyryliuk)
|
||||
- [a96024d](https://github.com/airbnb/superset/commit/a96024d0e7c54e5559205beb4f770db1e0ff85bb) [explorev2] Fields can validate input and handle errors (#1980) (@mistercrunch)
|
||||
- [99b84d2](https://github.com/airbnb/superset/commit/99b84d29091fcbdd233c91cc239cc6d2cf4b2e74) Reverting CLI changes in #1713 (#1964) (@mistercrunch)
|
||||
- [24728b8](https://github.com/airbnb/superset/commit/24728b8b47037ba809be95e759dc73ce7a8f73a5) Permissions cleanup: remove none and duplicates. (#1967) (@bkyryliuk)
|
||||
- [9750e49](https://github.com/airbnb/superset/commit/9750e49df8ff95d9dcbd25bea426eaa1ddcb67bd) Add the missing argument (#1969) (@flametest)
|
||||
- [bf31783](https://github.com/airbnb/superset/commit/bf31783d0ccc62712800ed3cc7caf63890ba36b5) v0.15.2 (@ascott)
|
||||
|
||||
### 0.15.2 (2017/01/13 07:05 +00:00)
|
||||
- [87eacf8](https://github.com/airbnb/superset/commit/87eacf88c3ee82f6fe3cf79c54672f6c64b7f3fb) fix timestamp error in table view (#1960) (@flametest)
|
||||
- [1dbfb99](https://github.com/airbnb/superset/commit/1dbfb99ead4be6669752853e58504b0f0eab351d) Leave metrics empty if not specified (#1965) (@vera-liu)
|
||||
- [ff4020e](https://github.com/airbnb/superset/commit/ff4020ea732de873feb82d94971cadcc5d5c0e74) [explorev2] using label in 'Visualization Type' Select instead of key (#1927) (@mistercrunch)
|
||||
- [0ce7fc1](https://github.com/airbnb/superset/commit/0ce7fc18a883af3ba9d35a498912fcf49ab1e70c) Adding a way to see the git SHA from the website (#1956) (@mistercrunch)
|
||||
- [470a6e9](https://github.com/airbnb/superset/commit/470a6e9d768493e7f9671d3cbe436e03ff15f137) [explorev2] adding support for client side validators on controls (#1920) (@mistercrunch)
|
||||
- [fc74fbe](https://github.com/airbnb/superset/commit/fc74fbeeaa0834f1dcf5f83b25d3b709b1b9fd95) [explore-v2] make control panel sections and fields more dense (#1954) (@ascott)
|
||||
- [9c6a579](https://github.com/airbnb/superset/commit/9c6a5793b9841686c483f818f9ef1af4cf0b9b73) Fix none view_menues. (#1950) (@bkyryliuk)
|
||||
- [49b6b38](https://github.com/airbnb/superset/commit/49b6b387410987ef19da36118fc06b4a52d69c85) Pass query instead of slice to Action buttons to prevent lagging query (#1948) (@vera-liu)
|
||||
- [a385ee9](https://github.com/airbnb/superset/commit/a385ee9e978c1175f95b3704669ab70489469860) Use POST in sqllab_viz instead of url params to avoid error with long queries (#1933) (@vera-liu)
|
||||
- [f0917c6](https://github.com/airbnb/superset/commit/f0917c62f20e5f1a36e3fa99f155787ff5e54afd) Add a Async Select that fetches options from given endpoint (#1909) (@vera-liu)
|
||||
- [94d2016](https://github.com/airbnb/superset/commit/94d20168dab4b85fc3f2d2172a2ae899de5aa2ba) Change fields for dual_line to match with new SelectField structure (#1932) (@vera-liu)
|
||||
- [2d866e3](https://github.com/airbnb/superset/commit/2d866e3ffa9bfedd3b3dad0d3463767aae879a14) [hotfix] fix the logging fix that broke the build (#1940) (@mistercrunch)
|
||||
- [5d94d70](https://github.com/airbnb/superset/commit/5d94d7067e3cc052f27c736c46a0d74c270ca387) [explore-v2] add edit link below datasource select (#1919) (@ascott)
|
||||
- [7323f4c](https://github.com/airbnb/superset/commit/7323f4c2ab2eda54e91274a6e9281f0a98160850) Make up the user link string (#1947) (@flametest)
|
||||
- [eca6dfe](https://github.com/airbnb/superset/commit/eca6dfef6afa05929fa240177e389e6c9a989aaf) switch order of period compare and rolling periods (#1946) (@patrickleotardif)
|
||||
- [761462e](https://github.com/airbnb/superset/commit/761462ef930fa8ac1094629b403d0ec09bb5c0ab) Revert "#views users for created dashboards on profile page" (#1943) (@vera-liu)
|
||||
- [98e8325](https://github.com/airbnb/superset/commit/98e83255e6efa18b72b7b17413d55d49ee9213b9) Added extra details around setting up admin user (#1937) (@mobcdi)
|
||||
- [cbf3562](https://github.com/airbnb/superset/commit/cbf3562a6f4d2edaaf14592c0bee6cab8394108c) Fix double scrollbar in pivot table (UI bug) (#1931) (@SalehHindi)
|
||||
- [a2c41bb](https://github.com/airbnb/superset/commit/a2c41bbace99eb3e749c59a3b2805c6e8e2b7130) viz: hotfix for saving in cache (#1922) (@xrmx)
|
||||
- [2a12a3c](https://github.com/airbnb/superset/commit/2a12a3c70267987c4bc3ecfad08aba4a5769fa10) [hotfix] logging is down (@mistercrunch)
|
||||
- [2ab6a41](https://github.com/airbnb/superset/commit/2ab6a411f4b9fa75bc86b83f4aa4e3707e90e002) Druid dashboard import/export. (#1930) (@bkyryliuk)
|
||||
- [14ed10b](https://github.com/airbnb/superset/commit/14ed10bdb0f6868e87c8cf39d770fcc616273e72) Fixing docs generation (@mistercrunch)
|
||||
- [49e6fd5](https://github.com/airbnb/superset/commit/49e6fd5bfbdb90020bf821f843a7e850e70a4c6b) Revert "Druid dashboard import/export. " (#1923) (@mistercrunch)
|
||||
- [af872fa](https://github.com/airbnb/superset/commit/af872fa4d4fbafb29bf47418c7c2b6716846f509) Druid dashboard import/export. (#1811) (@bkyryliuk)
|
||||
- [cec4cf0](https://github.com/airbnb/superset/commit/cec4cf014c91e5b664cc3dbfba34619388fd492e) #views users for created dashboards on profile page (#1667) (@vera-liu)
|
||||
- [783ad70](https://github.com/airbnb/superset/commit/783ad703d06a1e3b75c76307174af02d843cda0d) [hotfix] delete ipdb breakpoint (#1917) (@vera-liu)
|
||||
- [2226716](https://github.com/airbnb/superset/commit/222671675c31bdad9b8e2c8f3a5b814a02d85bee) [exploreV2] mapStateToProps for fields (#1882) (@mistercrunch)
|
||||
- [9a62d94](https://github.com/airbnb/superset/commit/9a62d9463005631f2d43b57a0d782453db98931e) [sqllab] bugfix visualizing a query with a semi-colon (#1869) (@mistercrunch)
|
||||
- [c3edc6e](https://github.com/airbnb/superset/commit/c3edc6e24bb55dcf26d29603b624ba513a562232) [WIP] Add dual-axis line chart to viz (#1782) (@vera-liu)
|
||||
- [119b0c5](https://github.com/airbnb/superset/commit/119b0c55e972d4b4b93ff9df4d7e99d14b9b8453) [explore] fix height in embed mode (#1898) (@mistercrunch)
|
||||
- [c14c7ed](https://github.com/airbnb/superset/commit/c14c7edc5ee798eb24b53ae65fec9a876fbe1fd9) [explore] show the broken query when failing (#1871) (@mistercrunch)
|
||||
- [e3b296c](https://github.com/airbnb/superset/commit/e3b296c558dcad4f77b6c82c37ed20903b1699bf) utils: teach our json serializer to handle more types (#1907) (@xrmx)
|
||||
- [c2d29fb](https://github.com/airbnb/superset/commit/c2d29fb54bbe8e57bdee03f4f4940469b48c2a92) Change ordering of fields when adding a table (#1899) (@mistercrunch)
|
||||
- [7aab8b0](https://github.com/airbnb/superset/commit/7aab8b0ae3d6816cf861c09193c9e2e166e2d18a) Simplifying the Fields (Controls) interface (#1868) (@mistercrunch)
|
||||
- [861a3bd](https://github.com/airbnb/superset/commit/861a3bd4ae85da2bb227c3d44a4ff56b9a836caf) docs: 8088 is the default port, no need to specify it (#1861) (@andreamelloncelli)
|
||||
- [9bc7ad9](https://github.com/airbnb/superset/commit/9bc7ad9cd53b9204a044c5dff16185ca49bd66a4) Do not use persistState for explorev2 (#1894) (@vera-liu)
|
||||
- [a1e3fc1](https://github.com/airbnb/superset/commit/a1e3fc1c230239c5535573cf708ff0e03d5eaa8a) [explorev2] giving more room for long textboxes (#1881) (@mistercrunch)
|
||||
- [242869d](https://github.com/airbnb/superset/commit/242869db3aa8eab99558d19f0e99923a78fb9840) [sql lab] only show single run query button (#1858) (@ascott)
|
||||
- [8924bb7](https://github.com/airbnb/superset/commit/8924bb79e74704632cc4401f0ed1f7134be11a1d) [explorev2] moving the "Time" section up to 2nd section (#1885) (@mistercrunch)
|
||||
- [a0d103d](https://github.com/airbnb/superset/commit/a0d103dac33201b55b2587d10d11f293bed0a0e7) Fix small typo (#1888) (@davejm)
|
||||
- [d52b299](https://github.com/airbnb/superset/commit/d52b299df8812ff4af5fb05ded2c1b3aedaae865) Updating CHANGELOG (@mistercrunch)
|
||||
|
||||
### 0.15.1 (2016/12/28 21:29 +00:00)
|
||||
- [092432f](https://github.com/airbnb/superset/commit/092432f04f0033e60493f009728a7bfd6a744b22) v0.15.1 (@mistercrunch)
|
||||
- [ea8e663](https://github.com/airbnb/superset/commit/ea8e6634d6c304cde3a42c65d37ec694f76b8cec) read anon user role from config, remove reference to public role (#1878) (@willgroves)
|
||||
@@ -11,7 +933,6 @@
|
||||
- [bb04e6f](https://github.com/airbnb/superset/commit/bb04e6fcfa1042b4532b50d8898555813be7fa29) Use APP_ICON in template (#1855) (@szmate1618)
|
||||
- [007ee88](https://github.com/airbnb/superset/commit/007ee88d33f92e6d052122b35ccad84d176029a7) [explorev2] improving the scrolling/scrollbars placement (#1840) (@mistercrunch)
|
||||
|
||||
### airbnb_prod.0.15.0.1 (2016/12/15 22:06 +00:00)
|
||||
- [7a5bb94](https://github.com/airbnb/superset/commit/7a5bb947542fdc20e2ec70e18b1cf418b8d1dba8) Stop ChartContainer from rendering twice on chartStatus change (#1828) (@vera-liu)
|
||||
- [e06a0cd](https://github.com/airbnb/superset/commit/e06a0cd89bc84f3a7e75ee6f03df8c9c3a2badeb) Add force_ctas_schema to query model when enabled (#1825) (@vera-liu)
|
||||
- [b6cba13](https://github.com/airbnb/superset/commit/b6cba13293101f3022c16e120e96383b59cae03e) [explorev2] enabling redux dev tools (#1842) (@mistercrunch)
|
||||
@@ -46,10 +967,8 @@
|
||||
- [74edb93](https://github.com/airbnb/superset/commit/74edb936a599ed54528389814ddf83e74f8452fd) [WIP] Add http to copied url and move function to componentWillReceiveProps (#1780) (@vera-liu)
|
||||
- [c155857](https://github.com/airbnb/superset/commit/c1558578d7c555fb7bb9ee30eb98bad4d28fbd07) [explorev2] Breaking down large files, fixing JS warnings (#1773) (@mistercrunch)
|
||||
|
||||
### airbnb_prod.0.13.0.3 (2016/12/06 07:18 +00:00)
|
||||
- [3597fdb](https://github.com/airbnb/superset/commit/3597fdb7f869929e0b09ff0144ff430b81e67853) Filter table list based on the user permissions. (#1769) (@bkyryliuk)
|
||||
|
||||
### airbnb_prod.0.13.0.2 (2016/12/06 01:17 +00:00)
|
||||
- [43f2a37](https://github.com/airbnb/superset/commit/43f2a379a1b88b260d0a4bdeac97b3cb4478afcf) Make cell-click filter in table viz optional (#1762) (@vera-liu)
|
||||
- [69702e3](https://github.com/airbnb/superset/commit/69702e3a1956ef5587e5aea2bffb3720b9b4cd35) Create users if not found. (#1753) (@bkyryliuk)
|
||||
- [eb0655c](https://github.com/airbnb/superset/commit/eb0655cf85daad4329cf8630fe99e2a50d0e7e5a) [sqllab] Fixed js error when results are not available (#1715) (@vera-liu)
|
||||
@@ -69,8 +988,6 @@
|
||||
- [168a252](https://github.com/airbnb/superset/commit/168a25239e712fe9eccf676f26df75fd91bd126f) State that npm should be between 3.9 and 4 (@bkyryliuk)
|
||||
- [7eef46e](https://github.com/airbnb/superset/commit/7eef46e9413b01ec15be515567a9619c695d5501) Adding links pointing to the new user profile page (#1704) (@mistercrunch)
|
||||
- [50da4f8](https://github.com/airbnb/superset/commit/50da4f8c0708f91ff24c0abd7189a137a1415bf6) Support running superset via pex (#1713) (@yolken)
|
||||
|
||||
### airbnb_prod.0.13.0.1 (2016/12/01 19:59 +00:00)
|
||||
- [2d0ebea](https://github.com/airbnb/superset/commit/2d0ebeae1bfd5e385000c9aa952891cf474821c6) [explorev2] Make chart container more responsive (#1724) (@vera-liu)
|
||||
- [1a16491](https://github.com/airbnb/superset/commit/1a164919715d6eaf1a999b97daaa53acb94a827d) Display full table name (schema + name) if possible. (#1728) (@bkyryliuk)
|
||||
- [7f4f250](https://github.com/airbnb/superset/commit/7f4f25097046dac9b436ef87f041debe2713827a) Redirects to login page if user not logged in at welcome page (#1723) (@vera-liu)
|
||||
@@ -179,7 +1096,6 @@
|
||||
- [a475551](https://github.com/airbnb/superset/commit/a475551b23d5830ab2945f615328f31d48df36ca) [sqllab] bind alt+enter shortcut in AceEditor to run a query (#1554) (@mistercrunch)
|
||||
- [bad7676](https://github.com/airbnb/superset/commit/bad7676414662b28a4b72eb680fbf42a5c6281a5) Bump cryptography dependency to 1.5.3 (#1569) (@xrmx)
|
||||
|
||||
### airbnb_prod.0.12.0.1 (2016/11/08 23:55 +00:00)
|
||||
- [51c0470](https://github.com/airbnb/superset/commit/51c0470f0be438312e90f2efb1f2e37291a30ce4) [explore v2] populate dynamic select field options (#1543) (@ascott)
|
||||
- [4530047](https://github.com/airbnb/superset/commit/4530047c769ba6d5953ef1547b8507c62f657942) Added action buttons to Chart Container of explore V2 (#1562) (@vera-liu)
|
||||
- [1bf83c3](https://github.com/airbnb/superset/commit/1bf83c3bf78de422df1b21c3049d106b1cb29385) [explore-v2] render columns based on length of fieldSets array (#1559) (@ascott)
|
||||
@@ -414,7 +1330,6 @@
|
||||
- [508feb2](https://github.com/airbnb/caravel/commit/508feb2bad581068a47193e06d35ed5926b25191) [hotfix] getting presto on track
|
||||
- [9f8eef4](https://github.com/airbnb/caravel/commit/9f8eef498c93ce2945e3d17cda1c3d2a24d05c92) [theme] a little bit less blue (#1024) (@mistercrunch)
|
||||
|
||||
### airbnb_prod.0.10.0.2 (2016/08/30 18:08 +00:00)
|
||||
- [561828c](https://github.com/airbnb/caravel/commit/561828c2f890e179c4116f773cc7507103804dc6) [SQL Lab] moving the db/schema/table select to the left (#1038) (@mistercrunch)
|
||||
- [fc1e637](https://github.com/airbnb/caravel/commit/fc1e63761cc86a5673433b0e2efc0081325684d3) Adding celery_tests.py (@mistercrunch)
|
||||
- [38b8db8](https://github.com/airbnb/caravel/commit/38b8db8051490375d021c51fb76a9f1bdc3ccf1f) SQL Lab - A multi-tab SQL editor (#514) (@mistercrunch)
|
||||
@@ -437,7 +1352,6 @@
|
||||
- [c7467f5](https://github.com/airbnb/caravel/commit/c7467f544c10281538b8504add9510f3fcf20e60) Documenting making your own build (#990) (@mistercrunch)
|
||||
- [30ef8eb](https://github.com/airbnb/caravel/commit/30ef8eba37073c2cb0d2a6356fe3a9bcabab4913) [ui] hack bootswatch/cosmo theme to get better tabs for sql-lab (and other things) (#975) (@ascott)
|
||||
|
||||
### airbnb_prod.0.10.0.1 (2016/08/18 07:02 +00:00)
|
||||
- [23a5463](https://github.com/airbnb/caravel/commit/23a54632081aa589e05a820ac774c8b4f6993252) Hack around the "last migration doesn't stamp" Alembic bug (#967) (@mistercrunch)
|
||||
- [84213ab](https://github.com/airbnb/caravel/commit/84213ab8cd27369f796131c68c075f12f8bd0ce2) [line] growth vs factor option for 'Period Ratio' (#970) (@mistercrunch)
|
||||
- [379cf6c](https://github.com/airbnb/caravel/commit/379cf6cbd9527617b6aae60501ad2fa4e252bb8f) [ui] tweaks and improvements (#965) (@ascott)
|
||||
|
||||
145
CONTRIBUTING.md
@@ -18,6 +18,9 @@ If you are reporting a bug, please include:
|
||||
troubleshooting.
|
||||
- Detailed steps to reproduce the bug.
|
||||
|
||||
When you post python stack traces please quote them using
|
||||
[markdown blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/).
|
||||
|
||||
### Fix Bugs
|
||||
|
||||
Look through the GitHub issues for bugs. Anything tagged with "bug" is
|
||||
@@ -26,7 +29,7 @@ open to whoever wants to implement it.
|
||||
### Implement Features
|
||||
|
||||
Look through the GitHub issues for features. Anything tagged with
|
||||
"feature" is open to whoever wants to implement it.
|
||||
"feature" or "starter_task" is open to whoever wants to implement it.
|
||||
|
||||
### Documentation
|
||||
|
||||
@@ -46,10 +49,32 @@ If you are proposing a feature:
|
||||
implement.
|
||||
- Remember that this is a volunteer-driven project, and that
|
||||
contributions are welcome :)
|
||||
|
||||
### Questions
|
||||
|
||||
There is a dedicated [tag](https://stackoverflow.com/questions/tagged/apache-superset) on [stackoverflow](https://stackoverflow.com/). Please use it when asking questions.
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
Before you submit a pull request from your forked repo, check that it
|
||||
meets these guidelines:
|
||||
|
||||
1. The pull request should include tests, either as doctests,
|
||||
unit tests, or both.
|
||||
2. If the pull request adds functionality, the docs should be updated
|
||||
as part of the same PR. Doc string are often sufficient, make
|
||||
sure to follow the sphinx compatible standards.
|
||||
3. The pull request should work for Python 2.7, and ideally python 3.4+.
|
||||
``from __future__ import`` will be required in every `.py` file soon.
|
||||
4. Code will be reviewed by re running the unittests, flake8 and syntax
|
||||
should be as rigorous as the core Python project.
|
||||
5. Please rebase and resolve all conflicts before submitting.
|
||||
6. If you are asked to update your pull request with some changes there's
|
||||
no need to create a new one. Push your changes to the same branch.
|
||||
|
||||
## Documentation
|
||||
|
||||
The latest documentation and tutorial are available [here](http://airbnb.io/superset).
|
||||
The latest documentation and tutorial are available [here](https://superset.incubator.apache.org/).
|
||||
|
||||
Contributing to the official documentation is relatively easy, once you've setup
|
||||
your environment and done an edit end-to-end. The docs can be found in the
|
||||
@@ -64,7 +89,7 @@ Before you start changing the docs, you'll want to
|
||||
[fork the Superset project on Github](https://help.github.com/articles/fork-a-repo/).
|
||||
Once that new repository has been created, clone it on your local machine:
|
||||
|
||||
git clone git@github.com:your_username/superset.git
|
||||
git clone git@github.com:your_username/incubator-superset.git
|
||||
|
||||
At this point, you may also want to create a
|
||||
[Python virtual environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/)
|
||||
@@ -76,7 +101,7 @@ to manage the Python packages you're about to install:
|
||||
Finally, to make changes to the rst files and build the docs using Sphinx,
|
||||
you'll need to install a handful of dependencies from the repo you cloned:
|
||||
|
||||
cd superset
|
||||
cd incubator-superset
|
||||
pip install -r dev-reqs-for-docs.txt
|
||||
|
||||
To get the feel for how to edit and build the docs, let's edit a file, build
|
||||
@@ -123,7 +148,7 @@ referenced in the rst, e.g.
|
||||
|
||||
aren't actually included in that directory. _Instead_, you'll want to add and commit
|
||||
images (and any other static assets) to the _superset/assets/images_ directory.
|
||||
When the docs are being pushed to [airbnb.io](http://airbnb.io/superset/), images
|
||||
When the docs are being pushed to [Apache Superset (incubating)](https://superset.incubator.apache.org/), images
|
||||
will be moved from there to the _\_static/img_ directory, just like they're referenced
|
||||
in the docs.
|
||||
|
||||
@@ -140,19 +165,19 @@ instead.
|
||||
|
||||
## Setting up a Python development environment
|
||||
|
||||
Check the [OS dependencies](http://airbnb.io/superset/installation.html#os-dependencies) before follows these steps.
|
||||
Check the [OS dependencies](https://superset.incubator.apache.org/installation.html#os-dependencies) before follows these steps.
|
||||
|
||||
# fork the repo on GitHub and then clone it
|
||||
# alternatively you may want to clone the main repo but that won't work
|
||||
# so well if you are planning on sending PRs
|
||||
# git clone git@github.com:airbnb/superset.git
|
||||
# git clone git@github.com:apache/incubator-superset.git
|
||||
|
||||
# [optional] setup a virtual env and activate it
|
||||
virtualenv env
|
||||
source env/bin/activate
|
||||
|
||||
# install for development
|
||||
python setup.py develop
|
||||
pip install -e .
|
||||
|
||||
# Create an admin user
|
||||
fabmanager create-admin --app superset
|
||||
@@ -202,8 +227,13 @@ To install third party libraries defined in `package.json`, run the
|
||||
following within the `superset/assets/` directory which will install them in a
|
||||
new `node_modules/` folder within `assets/`.
|
||||
|
||||
```
|
||||
npm install
|
||||
```bash
|
||||
# from the root of the repository, move to where our JS package.json lives
|
||||
cd superset/assets/
|
||||
# install yarn, a replacement for `npm install` that is faster and more deterministic
|
||||
npm install -g yarn
|
||||
# run yarn to fetch all the dependencies
|
||||
yarn
|
||||
```
|
||||
|
||||
To parse and generate bundled files for superset, run either of the
|
||||
@@ -231,9 +261,20 @@ npm run dev
|
||||
|
||||
## Testing
|
||||
|
||||
Python tests can be run with:
|
||||
Before running python unit tests, please setup local testing environment:
|
||||
```
|
||||
pip install -r dev-reqs.txt
|
||||
```
|
||||
|
||||
All python tests can be run with:
|
||||
|
||||
./run_tests.sh
|
||||
|
||||
Alternatively, you can run a specific test with:
|
||||
|
||||
./run_specific_test.sh tests.core_tests:CoreTests.test_function_name
|
||||
|
||||
Note that before running specific tests, you have to both setup the local testing environment and run all tests.
|
||||
|
||||
We use [Mocha](https://mochajs.org/), [Chai](http://chaijs.com/) and [Enzyme](http://airbnb.io/enzyme/) to test Javascript. Tests can be run with:
|
||||
|
||||
@@ -245,9 +286,8 @@ We use [Mocha](https://mochajs.org/), [Chai](http://chaijs.com/) and [Enzyme](ht
|
||||
|
||||
Lint the project with:
|
||||
|
||||
# for python changes
|
||||
flake8 changes tests
|
||||
flake8 changes superset
|
||||
# for python
|
||||
flake8
|
||||
|
||||
# for javascript
|
||||
npm run lint
|
||||
@@ -292,23 +332,6 @@ The `variables.less` and `bootswatch.less` files that ship with Superset are der
|
||||
[Bootswatch](https://bootswatch.com) and thus extend Bootstrap. Modify variables in these files directly, or
|
||||
swap them out entirely with the equivalent files from other Bootswatch (themes)[https://github.com/thomaspark/bootswatch.git]
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
Before you submit a pull request from your forked repo, check that it
|
||||
meets these guidelines:
|
||||
|
||||
1. The pull request should include tests, either as doctests,
|
||||
unit tests, or both.
|
||||
2. If the pull request adds functionality, the docs should be updated
|
||||
as part of the same PR. Doc string are often sufficient, make
|
||||
sure to follow the sphinx compatible standards.
|
||||
3. The pull request should work for Python 2.6, 2.7, and ideally python 3.3.
|
||||
``from __future__ import`` will be required in every `.py` file soon.
|
||||
4. Code will be reviewed by re running the unittests, flake8 and syntax
|
||||
should be as rigorous as the core Python project.
|
||||
5. Please rebase and resolve all conflicts before submitting.
|
||||
|
||||
|
||||
## Translations
|
||||
|
||||
We use [Babel](http://babel.pocoo.org/en/latest/) to translate Superset. The
|
||||
@@ -317,6 +340,8 @@ key is to instrument the strings that need translation using
|
||||
a module, all you have to do is to `_("Wrap your strings")` using the
|
||||
underscore `_` "function".
|
||||
|
||||
We use `import {t, tn, TCT} from locales;` in js, JSX file, locales is in `./superset/assets/javascripts/` directory.
|
||||
|
||||
To enable changing language in your environment, you can simply add the
|
||||
`LANGUAGES` parameter to your `superset_config.py`. Having more than one
|
||||
options here will add a language selection dropdown on the right side of the
|
||||
@@ -329,14 +354,15 @@ navigation bar.
|
||||
}
|
||||
|
||||
As per the [Flask AppBuilder documentation] about translation, to create a
|
||||
new language dictionary, run the following command:
|
||||
new language dictionary, run the following command (where `es` is replaced with
|
||||
the language code for your target language):
|
||||
|
||||
pybabel init -i ./babel/messages.pot -d superset/translations -l es
|
||||
pybabel init -i superset/translations/messages.pot -d superset/translations -l es
|
||||
|
||||
Then it's a matter of running the statement below to gather all stings that
|
||||
Then it's a matter of running the statement below to gather all strings that
|
||||
need translation
|
||||
|
||||
fabmanager babel-extract --target superset/translations/
|
||||
fabmanager babel-extract --target superset/translations/ --output superset/translations/messages.pot --config superset/translations/babel.cfg -k _ -k __ -k t -k tn -k tct
|
||||
|
||||
You can then translate the strings gathered in files located under
|
||||
`superset/translation`, where there's one per language. For the translations
|
||||
@@ -344,6 +370,19 @@ to take effect, they need to be compiled using this command:
|
||||
|
||||
fabmanager babel-compile --target superset/translations/
|
||||
|
||||
In the case of JS translation, we need to convert the PO file into a JSON file, and we need the global download of the npm package po2json.
|
||||
We need to be compiled using this command:
|
||||
|
||||
npm install po2json -g
|
||||
|
||||
Execute this command to convert the en PO file into a json file:
|
||||
|
||||
po2json -d superset -f jed1.x superset/translations/en/LC_MESSAGES/messages.po superset/translations/en/LC_MESSAGES/messages.json
|
||||
|
||||
If you get errors running `po2json`, you might be running the ubuntu package with the same
|
||||
name rather than the nodejs package (they have a different format for the arguments). You
|
||||
need to be running the nodejs version, and so if there is a conflict you may need to point
|
||||
directly at `/usr/local/bin/po2json` rather than just `po2json`.
|
||||
|
||||
## Adding new datasources
|
||||
|
||||
@@ -360,3 +399,39 @@ to take effect, they need to be compiled using this command:
|
||||
`ADDITIONAL_MODULE_DS_MAP = {'superset.my_models': ['MyDatasource', 'MyOtherDatasource']}`
|
||||
|
||||
This means it'll register MyDatasource and MyOtherDatasource in superset.my_models module in the source registry.
|
||||
|
||||
## Creating a new visualization type
|
||||
|
||||
Here's an example as a Github PR with comments that describe what the
|
||||
different sections of the code do:
|
||||
https://github.com/apache/incubator-superset/pull/3013
|
||||
|
||||
## Refresh documentation website
|
||||
|
||||
Every once in a while we want to compile the documentation and publish it.
|
||||
Here's how to do it.
|
||||
|
||||
.. code::
|
||||
|
||||
# install doc dependencies
|
||||
pip install -r dev-reqs-for-docs.txt
|
||||
|
||||
# build the docs
|
||||
python setup.py build_sphinx
|
||||
|
||||
# copy html files to temp folder
|
||||
cp -r docs/_build/html/ /tmp/tmp_superset_docs/
|
||||
|
||||
# clone the docs repo
|
||||
cd ~/
|
||||
git clone https://git-wip-us.apache.org/repos/asf/incubator-superset-site.git
|
||||
|
||||
# copy
|
||||
cp -r /tmp/tmp_superset_docs/ ~/incubator-superset-site.git/
|
||||
|
||||
# commit and push to `asf-site` branch
|
||||
cd ~/incubator-superset-site.git/
|
||||
git checkout asf-site
|
||||
git add .
|
||||
git commit -a -m "New doc version"
|
||||
git push origin master
|
||||
|
||||
21
INTHEWILD.md
@@ -1,21 +0,0 @@
|
||||
Please use [pull requests](https://github.com/airbnb/superset/pull/new/master)
|
||||
to add your organization and/or project to this document!
|
||||
|
||||
Organizations
|
||||
----------
|
||||
- [Airbnb](https://github.com/airbnb)
|
||||
- [GfK Data Lab] (http://datalab.gfk.com)
|
||||
- [Maieutical Labs] (https://cloudschooling.it)
|
||||
- [Shopkick] (https://www.shopkick.com)
|
||||
- [Amino] (https://amino.com)
|
||||
- [Faasos] (http://faasos.com/)
|
||||
- [Clark.de] (http://clark.de/)
|
||||
- [Yahoo!] (www.yahoo.com)
|
||||
- [Digit Game Studios] (https://www.digitgaming.com/)
|
||||
- [Brilliant.org] (https://brilliant.org/)
|
||||
- [Qunar] (https://www.qunar.com/)
|
||||
- [Udemy] (https://www.udemy.com/)
|
||||
|
||||
Projects
|
||||
----------
|
||||
- None we know of yet
|
||||
14
MANIFEST.in
@@ -1,9 +1,9 @@
|
||||
recursive-include superset/templates *
|
||||
recursive-include superset/static *
|
||||
recursive-exclude superset/static/assets/node_modules *
|
||||
recursive-include superset/static/assets/node_modules/font-awesome *
|
||||
recursive-exclude superset/static/docs *
|
||||
recursive-exclude superset/static/spec *
|
||||
recursive-exclude tests *
|
||||
recursive-include superset/data *
|
||||
recursive-include superset/migrations *
|
||||
recursive-include superset/static *
|
||||
recursive-exclude superset/static/docs *
|
||||
recursive-exclude superset/static/spec *
|
||||
recursive-exclude superset/static/assets/node_modules *
|
||||
recursive-include superset/templates *
|
||||
recursive-include superset/translations *
|
||||
recursive-exclude tests *
|
||||
|
||||
173
README.md
@@ -1,17 +1,14 @@
|
||||
Superset
|
||||
=========
|
||||
|
||||
[](https://travis-ci.org/airbnb/superset)
|
||||
[](https://travis-ci.org/apache/incubator-superset)
|
||||
[](https://badge.fury.io/py/superset)
|
||||
[](https://coveralls.io/github/airbnb/superset?branch=master)
|
||||
[](https://codeclimate.com/github/airbnb/superset/coverage)
|
||||
[](https://landscape.io/github/airbnb/superset/master)
|
||||
[](https://codeclimate.com/github/airbnb/superset)
|
||||
[](https://coveralls.io/github/apache/incubator-superset?branch=master)
|
||||
[](https://pypi.python.org/pypi/superset)
|
||||
[](https://requires.io/github/airbnb/superset/requirements/?branch=master)
|
||||
[](https://gitter.im/airbnb/superset?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](http://airbnb.io/superset/)
|
||||
[](https://david-dm.org/airbnb/superset?path=superset/assets)
|
||||
[](https://requires.io/github/apache/incubator-superset/requirements/?branch=master)
|
||||
[](https://gitter.im/apache/incubator-superset?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://superset.incubator.apache.org)
|
||||
[](https://david-dm.org/apache/incubator-superset?path=superset/assets)
|
||||
|
||||
<img
|
||||
src="https://cloud.githubusercontent.com/assets/130878/20946612/49a8a25c-bbc0-11e6-8314-10bef902af51.png"
|
||||
@@ -19,8 +16,8 @@ Superset
|
||||
width="500"
|
||||
/>
|
||||
|
||||
**Superset** is a data exploration platform designed to be visual, intuitive
|
||||
and interactive.
|
||||
**Apache Superset** (incubating) is a modern, enterprise-ready
|
||||
business intelligence web application
|
||||
|
||||
[this project used to be named **Caravel**, and **Panoramix** in the past]
|
||||
|
||||
@@ -29,41 +26,49 @@ Screenshots & Gifs
|
||||
------------------
|
||||
|
||||
**View Dashboards**
|
||||
|
||||

|
||||
|
||||
<br/>
|
||||
|
||||
**View/Edit a Slice**
|
||||
|
||||

|
||||
|
||||
<br/>
|
||||
|
||||
**Query and Visualize with SQL Lab**
|
||||
|
||||

|
||||
|
||||
<br/>
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Superset
|
||||
---------
|
||||
Superset's main goal is to make it easy to slice, dice and visualize data.
|
||||
It empowers users to perform **analytics at the speed of thought**.
|
||||
Apache Superset
|
||||
---------------
|
||||
Apache Superset is a data exploration and visualization web application.
|
||||
|
||||
Superset provides:
|
||||
* A quick way to intuitively visualize datasets by allowing users to create
|
||||
and share interactive dashboards
|
||||
* A rich set of visualizations to analyze your data, as well as a flexible
|
||||
way to extend the capabilities
|
||||
* An intuitive interface to explore and visualize datasets, and
|
||||
create interactive dashboards.
|
||||
* A wide array of beautiful visualizations to showcase your data.
|
||||
* Easy, code-free, user flows to drill down and slice and dice the data
|
||||
underlying exposed dashboards. The dashboards and charts acts as a starting
|
||||
point for deeper analysis.
|
||||
* A state of the art SQL editor/IDE exposing a rich metadata browser, and
|
||||
an easy workflow to create visualizations out of any result set.
|
||||
* An extensible, high granularity security model allowing intricate rules
|
||||
on who can access which features, and integration with major
|
||||
authentication providers (database, OpenID, LDAP, OAuth & REMOTE_USER
|
||||
through Flask AppBuiler)
|
||||
* A simple semantic layer, allowing to control how data sources are
|
||||
displayed in the UI, by defining which fields should show up in
|
||||
which dropdown and which aggregation and function (metrics) are
|
||||
made available to the user
|
||||
on who can access which product features and datasets.
|
||||
Integration with major
|
||||
authentication backends (database, OpenID, LDAP, OAuth, REMOTE_USER, ...)
|
||||
* A lightweight semantic layer, allowing to control how data sources are
|
||||
exposed to the user by defining dimensions and metrics
|
||||
* Out of the box support for most SQL-speaking databases
|
||||
* Deep integration with Druid allows for Superset to stay blazing fast while
|
||||
slicing and dicing large, realtime datasets
|
||||
* Fast loading dashboards with configurable caching
|
||||
@@ -72,15 +77,41 @@ Superset provides:
|
||||
Database Support
|
||||
----------------
|
||||
|
||||
Superset was originally designed on top of Druid.io, but quickly broadened
|
||||
its scope to support other databases through the use of SQLAlchemy, a Python
|
||||
Superset speaks many SQL dialects through SQLAlchemy, a Python
|
||||
ORM that is compatible with
|
||||
[most common databases](http://docs.sqlalchemy.org/en/rel_1_0/core/engines.html).
|
||||
|
||||
Superset can be used to visualize data out of most databases:
|
||||
* MySQL
|
||||
* Postgres
|
||||
* Vertica
|
||||
* Oracle
|
||||
* Microsoft SQL Server
|
||||
* SQLite
|
||||
* Greenplum
|
||||
* Firebird
|
||||
* MariaDB
|
||||
* Sybase
|
||||
* IBM DB2
|
||||
* Exasol
|
||||
* MonetDB
|
||||
* Snowflake
|
||||
* Redshift
|
||||
* **more!** look for the availability of a SQLAlchemy dialect for your database
|
||||
to find out whether it will work with Superset
|
||||
|
||||
What is Druid?
|
||||
-------------
|
||||
From their website at http://druid.io
|
||||
|
||||
Druid!
|
||||
------
|
||||
|
||||
On top of having the ability to query your relational databases,
|
||||
Superset has ships with deep integration with Druid (a real time distributed
|
||||
column-store). When querying Druid,
|
||||
Superset can query humongous amounts of data on top of real time dataset.
|
||||
Note that Superset does not require Druid in any way to function, it's simply
|
||||
another database backend that it can query.
|
||||
|
||||
Here's a description of Druid from the http://druid.io website:
|
||||
|
||||
*Druid is an open-source analytics data store designed for
|
||||
business intelligence (OLAP) queries on event data. Druid provides low
|
||||
@@ -93,7 +124,59 @@ power analytic dashboards and applications.*
|
||||
Installation & Configuration
|
||||
----------------------------
|
||||
|
||||
[See in the documentation](http://airbnb.io/superset/installation.html)
|
||||
[See in the documentation](https://superset.incubator.apache.org/installation.html)
|
||||
|
||||
|
||||
Resources
|
||||
-------------
|
||||
* [Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org/)
|
||||
* [Gitter (live chat) Channel](https://gitter.im/airbnb/superset)
|
||||
* [Docker image](https://hub.docker.com/r/amancevice/superset/) (community contributed)
|
||||
* [Slides from Strata (March 2016)](https://drive.google.com/open?id=0B5PVE0gzO81oOVJkdF9aNkJMSmM)
|
||||
* [Stackoverflow tag](https://stackoverflow.com/questions/tagged/apache-superset)
|
||||
* [DEPRECATED Google Group](https://groups.google.com/forum/#!forum/airbnb_superset)
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Interested in contributing? Casual hacking? Check out
|
||||
[Contributing.MD](https://github.com/airbnb/superset/blob/master/CONTRIBUTING.md)
|
||||
|
||||
|
||||
Who uses Apache Superset (incubating)?
|
||||
--------------------------------------
|
||||
|
||||
Here's a list of organizations who have taken the time to send a PR to let
|
||||
the world know they are using Superset. Join our growing community!
|
||||
|
||||
- [AiHello](https://www.aihello.com)
|
||||
- [Airbnb](https://github.com/airbnb)
|
||||
- [Amino](https://amino.com)
|
||||
- [Brilliant.org](https://brilliant.org/)
|
||||
- [Capital Service S.A.](http://capitalservice.pl)
|
||||
- [Clark.de](http://clark.de/)
|
||||
- [Digit Game Studios](https://www.digitgaming.com/)
|
||||
- [Douban](https://www.douban.com/)
|
||||
- [Endress+Hauser](http://www.endress.com/)
|
||||
- [FBK - ICT center](http://ict.fbk.eu)
|
||||
- [Faasos](http://faasos.com/)
|
||||
- [GfK Data Lab](http://datalab.gfk.com)
|
||||
- [Konfío](http://konfio.mx)
|
||||
- [Lyft](https://www.lyft.com/)
|
||||
- [Maieutical Labs](https://cloudschooling.it)
|
||||
- [Pronto Tools](http://www.prontotools.io)
|
||||
- [Qunar](https://www.qunar.com/)
|
||||
- [Shopee](https://shopee.sg)
|
||||
- [Shopkick](https://www.shopkick.com)
|
||||
- [Tails.com](https://tails.com)
|
||||
- [Tobii](http://www.tobii.com/)
|
||||
- [Tooploox](https://www.tooploox.com/)
|
||||
- [Twitter](https://twitter.com/)
|
||||
- [Udemy](https://www.udemy.com/)
|
||||
- [VIPKID](https://www.vipkid.com.cn/)
|
||||
- [Yahoo!](https://yahoo.com/)
|
||||
- [Zalando](https://www.zalando.com)
|
||||
|
||||
|
||||
More screenshots
|
||||
@@ -114,29 +197,3 @@ More screenshots
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
Resources
|
||||
-------------
|
||||
* [Superset Google Group](https://groups.google.com/forum/#!forum/airbnb_superset)
|
||||
* [Gitter (live chat) Channel](https://gitter.im/airbnb/superset)
|
||||
* [Docker image](https://hub.docker.com/r/amancevice/superset/) (community contributed)
|
||||
* [Slides from Strata (March 2016)](https://drive.google.com/open?id=0B5PVE0gzO81oOVJkdF9aNkJMSmM)
|
||||
|
||||
|
||||
Tip of the Hat
|
||||
--------------
|
||||
|
||||
Superset would not be possible without these great frameworks / libs
|
||||
|
||||
* Flask App Builder - Allowing us to focus on building the app quickly while
|
||||
getting the foundation for free
|
||||
* The Flask ecosystem - Simply amazing. So much Plug, easy play.
|
||||
* NVD3 - One of the best charting libraries out there
|
||||
* Much more, check out the `install_requires` section in the [setup.py](https://github.com/airbnb/superset/blob/master/setup.py) file!
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Interested in contributing? Casual hacking? Check out [Contributing.MD](https://github.com/airbnb/superset/blob/master/CONTRIBUTING.md)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[ignore: superset/assets/node_modules/**]
|
||||
[python: superset/**.py]
|
||||
[jinja2: superset/**/templates/**.html]
|
||||
encoding = utf-8
|
||||
1809
babel/messages.pot
@@ -1,10 +1,14 @@
|
||||
codeclimate-test-reporter
|
||||
coveralls
|
||||
flake8
|
||||
flask_cors
|
||||
mock
|
||||
mysqlclient
|
||||
nose
|
||||
psycopg2
|
||||
pylint
|
||||
pyyaml
|
||||
redis
|
||||
statsd
|
||||
# Also install everything we need to build Sphinx docs
|
||||
-r dev-reqs-for-docs.txt
|
||||
|
||||
1
docs/_build/html/README.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Folder containing the sphinx-generated documentation
|
||||
@@ -51,7 +51,7 @@ source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = "Superset's documentation"
|
||||
project = "Apache Superset"
|
||||
copyright = None
|
||||
author = u'Maxime Beauchemin'
|
||||
|
||||
|
||||
136
docs/faq.rst
@@ -48,12 +48,21 @@ https://github.com/airbnb/superset/issues?q=label%3Aexample+is%3Aclosed
|
||||
Why are my queries timing out?
|
||||
------------------------------
|
||||
|
||||
If you are seeing timeouts (504 Gateway Time-out) when running queries,
|
||||
it's because the web server is timing out web requests. If you want to
|
||||
increase the default (50), you can specify the timeout when starting the
|
||||
web server with the ``-t`` flag, which is expressed in seconds.
|
||||
There are many reasons may cause long query timing out.
|
||||
|
||||
``superset runserver -t 300``
|
||||
|
||||
- For running long query from Sql Lab, by default Superset allows it run as long as 6 hours before it being killed by celery. If you want to increase the time for running query, you can specify the timeout in configuration. For example:
|
||||
|
||||
``SQLLAB_ASYNC_TIME_LIMIT_SEC = 60 * 60 * 6``
|
||||
|
||||
|
||||
- Superset is running on gunicorn web server, which may time out web requests. If you want to increase the default (50), you can specify the timeout when starting the web server with the ``-t`` flag, which is expressed in seconds.
|
||||
|
||||
``superset runserver -t 300``
|
||||
|
||||
- If you are seeing timeouts (504 Gateway Time-out) when loading dashboard or explore slice, you are probably behind gateway or proxy server (such as Nginx). If it did not receive a timely response from Superset server (which is processing long queries), these web servers will send 504 status code to clients directly. Superset has a client-side timeout limit to address this issue. If query didn't come back within clint-side timeout (60 seconds by default), Superset will display warning message to avoid gateway timeout message. If you have a longer gateway timeout limit, you can change the timeout settings in ``superset_config.py``:
|
||||
|
||||
``SUPERSET_WEBSERVER_TIMEOUT = 60``
|
||||
|
||||
|
||||
Why is the map not visible in the mapbox visualization?
|
||||
@@ -78,6 +87,11 @@ The widget also has a checkbox ``Date Filter``, which enables time filtering
|
||||
capabilities to your dashboard. After checking the box and refreshing, you'll
|
||||
see a ``from`` and a ``to`` dropdown show up.
|
||||
|
||||
By default, the filtering will be applied to all the slices that are built
|
||||
on top of a datasource that shares the column name that the filter is based
|
||||
on. It's also a requirement for that column to be checked as "filterable"
|
||||
in the column tab of the table editor.
|
||||
|
||||
But what about if you don't want certain widgets to get filtered on your
|
||||
dashboard? You can do that by editing your dashboard, and in the form,
|
||||
edit the ``JSON Metadata`` field, more specifically the
|
||||
@@ -93,7 +107,8 @@ never be affected by any dashboard level filtering.
|
||||
"filter_immune_slice_fields": {
|
||||
"177": ["country_name", "__from", "__to"],
|
||||
"32": ["__from", "__to"]
|
||||
}
|
||||
},
|
||||
"timed_refresh_immune_slices": [324]
|
||||
}
|
||||
|
||||
In the json blob above, slices 324, 65 and 92 won't be affected by any
|
||||
@@ -110,12 +125,115 @@ But what happens with filtering when dealing with slices coming from
|
||||
different tables or databases? If the column name is shared, the filter will
|
||||
be applied, it's as simple as that.
|
||||
|
||||
|
||||
How to limit the timed refresh on a dashboard?
|
||||
----------------------------------------------
|
||||
By default, the dashboard timed refresh feature allows you to automatically re-query every slice
|
||||
on a dashboard according to a set schedule. Sometimes, however, you won't want all of the slices
|
||||
to be refreshed - especially if some data is slow moving, or run heavy queries. To exclude specific
|
||||
slices from the timed refresh process, add the ``timed_refresh_immune_slices`` key to the dashboard
|
||||
``JSON Metadata`` field:
|
||||
|
||||
..code::
|
||||
|
||||
{
|
||||
"filter_immune_slices": [],
|
||||
"expanded_slices": {},
|
||||
"filter_immune_slice_fields": {},
|
||||
"timed_refresh_immune_slices": [324]
|
||||
}
|
||||
|
||||
In the example above, if a timed refresh is set for the dashboard, then every slice except 324 will
|
||||
be automatically re-queried on schedule.
|
||||
|
||||
Slice refresh will also be staggered over the specified period. You can turn off this staggering
|
||||
by setting the ``stagger_refresh`` to ``false`` and modify the stagger period by setting
|
||||
``stagger_time`` to a value in milliseconds in the ``JSON Metadata`` field:
|
||||
|
||||
..code::
|
||||
|
||||
{
|
||||
"stagger_refresh": false,
|
||||
"stagger_time": 2500
|
||||
}
|
||||
|
||||
Here, the entire dashboard will refresh at once if periodic refresh is on. The stagger time of
|
||||
2.5 seconds is ignored.
|
||||
|
||||
Why does fabmanager or superset freezed/hung/not responding when started (my home directory is NFS mounted)?
|
||||
-----------------------------------------------------------------------------------------
|
||||
superset creates and uses an sqlite database at ``~/.superset/superset.db``. Sqlite is known to `don't work well if used on NFS`__ due to broken file locking implementation on NFS.
|
||||
By default, superset creates and uses an sqlite database at ``~/.superset/superset.db``. Sqlite is known to `don't work well if used on NFS`__ due to broken file locking implementation on NFS.
|
||||
|
||||
__ https://www.sqlite.org/lockingv3.html
|
||||
|
||||
One work around is to create a symlink from ~/.superset to a directory located on a non-NFS partition.
|
||||
You can override this path using the ``SUPERSET_HOME`` environment variable.
|
||||
|
||||
Another work around is to change where superset stores the sqlite database by adding ``SQLALCHEMY_DATABASE_URI = 'sqlite:////new/localtion/superset.db'`` in superset_config.py (create the file if needed), then adding the directory where superset_config.py lives to PYTHONPATH environment variable (e.g. ``export PYTHONPATH=/opt/logs/sandbox/airbnb/``).
|
||||
Another work around is to change where superset stores the sqlite database by adding ``SQLALCHEMY_DATABASE_URI = 'sqlite:////new/location/superset.db'`` in superset_config.py (create the file if needed), then adding the directory where superset_config.py lives to PYTHONPATH environment variable (e.g. ``export PYTHONPATH=/opt/logs/sandbox/airbnb/``).
|
||||
|
||||
What if the table schema changed?
|
||||
---------------------------------
|
||||
|
||||
Table schemas evolve, and Superset needs to reflect that. It's pretty common
|
||||
in the life cycle of a dashboard to want to add a new dimension or metric.
|
||||
To get Superset to discover your new columns, all you have to do is to
|
||||
go to ``Menu -> Sources -> Tables``, click the ``edit`` icon next to the
|
||||
table who's schema has changed, and hit ``Save`` from the ``Detail`` tab.
|
||||
Behind the scene, the new columns will get merged it. Following this,
|
||||
you may want to
|
||||
re-edit the table afterwards to configure the ``Column`` tab, check the
|
||||
appropriate boxes and save again.
|
||||
|
||||
How do I go about developing a new visualization type?
|
||||
------------------------------------------------------
|
||||
Here's an example as a Github PR with comments that describe what the
|
||||
different sections of the code do:
|
||||
https://github.com/airbnb/superset/pull/3013
|
||||
|
||||
What database engine can I use as a backend for Superset?
|
||||
---------------------------------------------------------
|
||||
|
||||
To clarify, the *database backend* is an OLTP database used by Superset to store its internal
|
||||
information like your list of users, slices and dashboard definitions.
|
||||
|
||||
Superset is tested using Mysql, Postgresql and Sqlite for its backend. It's recommended you
|
||||
install Superset on one of these database server for production.
|
||||
|
||||
Using a column-store, non-OLTP databases like Vertica, Redshift or Presto as a database backend simply won't work as these databases are not designed for this type of workload. Installation on Oracle, Microsoft SQL Server, or other OLTP databases may work but isn't tested.
|
||||
|
||||
Please note that pretty much any databases that have a SqlAlchemy integration should work perfectly fine as a datasource for Superset, just not as the OLTP backend.
|
||||
|
||||
How can i configure OAuth authentication and authorization?
|
||||
-----------------------------------------------------------
|
||||
|
||||
You can take a look at this Flask-AppBuilder `configuration example
|
||||
<https://github.com/dpgaspar/Flask-AppBuilder/blob/master/examples/oauth/config.py>`_.
|
||||
|
||||
How can I set a default filter on my dashboard?
|
||||
-----------------------------------------------
|
||||
|
||||
Easy. Simply apply the filter and save the dashboard while the filter
|
||||
is active.
|
||||
|
||||
How do I get Superset to refresh the schema of my table?
|
||||
--------------------------------------------------------
|
||||
|
||||
When adding columns to a table, you can have Superset detect and merge the
|
||||
new columns in by using the "Refresh Metadata" action in the
|
||||
``Source -> Tables`` page. Simply check the box next to the tables
|
||||
you want the schema refreshed, and click ``Actions -> Refresh Metadata``.
|
||||
|
||||
Is there a way to force the use specific colors?
|
||||
------------------------------------------------
|
||||
|
||||
It is possible on a per-dashboard basis by providing a mapping of
|
||||
labels to colors in the ``JSON Metadata`` attribute using the
|
||||
``label_colors`` key.
|
||||
|
||||
..code::
|
||||
|
||||
{
|
||||
"label_colors": {
|
||||
"Girls": "#FF69B4",
|
||||
"Boys": "#ADD8E6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,48 @@
|
||||
Superset's documentation
|
||||
''''''''''''''''''''''''
|
||||
.. image:: _static/img/s.png
|
||||
|
||||
Apache Superset (incubating)
|
||||
''''''''''''''''''''''''''''
|
||||
|
||||
Apache Superset (incubating) is a modern, enterprise-ready business
|
||||
intelligence web application
|
||||
|
||||
Superset is a data exploration platform designed to be visual, intuitive
|
||||
and interactive.
|
||||
|
||||
----------------
|
||||
|
||||
.. warning:: This project was originally named Panoramix, was renamed to
|
||||
Caravel in March 2016, and is currently named Superset as of November 2016
|
||||
|
||||
.. important::
|
||||
|
||||
**Disclaimer**: Apache Superset is an effort undergoing incubation at The
|
||||
Apache Software Foundation (ASF), sponsored by the Apache Incubator.
|
||||
Incubation is required of all newly accepted projects until a further
|
||||
review indicates that the infrastructure, communications, and
|
||||
decision making process have stabilized in a manner consistent with
|
||||
other successful ASF projects. While incubation status is not
|
||||
necessarily a reflection of the completeness or stability of
|
||||
the code, it does indicate that the project has yet to be fully
|
||||
endorsed by the ASF.
|
||||
|
||||
Overview
|
||||
=======================================
|
||||
|
||||
Features
|
||||
---------
|
||||
|
||||
- A rich set of data visualizations, integrated from some of the best
|
||||
visualization libraries
|
||||
- Create and share simple dashboards
|
||||
- An extensible, high-granularity security/permission model allowing
|
||||
intricate rules on who can access individual features and the dataset
|
||||
- A rich set of data visualizations
|
||||
- An easy-to-use interface for exploring and visualizing data
|
||||
- Create and share dashboards
|
||||
- Enterprise-ready authentication with integration with major authentication
|
||||
providers (database, OpenID, LDAP, OAuth & REMOTE_USER through
|
||||
Flask AppBuilder)
|
||||
- An extensible, high-granularity security/permission model allowing
|
||||
intricate rules on who can access individual features and the dataset
|
||||
- A simple semantic layer, allowing users to control how data sources are
|
||||
displayed in the UI by defining which fields should show up in which
|
||||
drop-down and which aggregation and function metrics are made available
|
||||
to the user
|
||||
- Integration with most RDBMS through SqlAlchemy
|
||||
- Integration with most SQL-speaking RDBMS through SQLAlchemy
|
||||
- Deep integration with Druid.io
|
||||
|
||||
------
|
||||
@@ -55,6 +70,7 @@ Contents
|
||||
tutorial
|
||||
security
|
||||
sqllab
|
||||
visualization
|
||||
videos
|
||||
gallery
|
||||
druid
|
||||
|
||||
@@ -8,6 +8,32 @@ Superset is tested against Python ``2.7`` and Python ``3.4``.
|
||||
Airbnb currently uses 2.7.* in production. We do not plan on supporting
|
||||
Python ``2.6``.
|
||||
|
||||
Cloud-native!
|
||||
-------------
|
||||
|
||||
Superset is designed to be highly available. It is
|
||||
"cloud-native" as it has been designed scale out in large,
|
||||
distributed environments, and works well inside containers.
|
||||
While you can easily
|
||||
test drive Superset on a modest setup or simply on your laptop,
|
||||
there's virtually no limit around scaling out the platform.
|
||||
Superset is also cloud-native in the sense that it is
|
||||
flexible and lets you choose your web server (Gunicorn, Nginx, Apache),
|
||||
your metadata database engine (MySQL, Postgres, MariaDB, ...),
|
||||
your message queue (Redis, RabbitMQ, SQS, ...),
|
||||
your results backend (S3, Redis, Memcached, ...), your caching layer
|
||||
(memcached, Redis, ...), works well with services like NewRelic, StatsD and
|
||||
DataDog, and has the ability to run analytic workloads against
|
||||
most popular database technologies.
|
||||
|
||||
Superset is battle tested in large environments with hundreds
|
||||
of concurrent users. Airbnb's production environment runs inside
|
||||
Kubernetes and serves 600+ daily active users viewing over 100K charts a
|
||||
day.
|
||||
|
||||
The Superset web server and the Superset Celery workers (optional)
|
||||
are stateless, so you can scale out by running on as many servers
|
||||
as needed.
|
||||
|
||||
OS dependencies
|
||||
---------------
|
||||
@@ -36,7 +62,7 @@ that the required dependencies are installed: ::
|
||||
**OSX**, system python is not recommended. brew's python also ships with pip ::
|
||||
|
||||
brew install pkg-config libffi openssl python
|
||||
env LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" pip install cryptography
|
||||
env LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" pip install cryptography==1.9
|
||||
|
||||
**Windows** isn't officially supported at this point, but if you want to
|
||||
attempt it, download `get-pip.py <https://bootstrap.pypa.io/get-pip.py>`_, and run ``python get-pip.py`` which may need admin access. Then run the following: ::
|
||||
@@ -107,10 +133,40 @@ the credential you entered while creating the admin account, and navigate to
|
||||
your datasources for Superset to be aware of, and they should show up in
|
||||
`Menu -> Datasources`, from where you can start playing with your data!
|
||||
|
||||
Please note that *gunicorn*, Superset default application server, does not
|
||||
work on Windows so you need to use the development web server.
|
||||
The development web server though is not intended to be used on production systems
|
||||
so better use a supported platform that can run *gunicorn*.
|
||||
A proper WSGI HTTP Server
|
||||
-------------------------
|
||||
|
||||
While you can setup Superset to run on Nginx or Apache, many use
|
||||
Gunicorn, preferably in **async mode**, which allows for impressive
|
||||
concurrency even and is fairly easy to install and configure. Please
|
||||
refer to the
|
||||
documentation of your preferred technology to set up this Flask WSGI
|
||||
application in a way that works well in your environment.
|
||||
|
||||
While the `superset runserver` command act as an quick wrapper
|
||||
around `gunicorn`, it doesn't expose all the options you may need,
|
||||
so you'll want to craft your own `gunicorn` command in your production
|
||||
environment. Here's an **async** setup known to work well: ::
|
||||
|
||||
gunicorn \
|
||||
-w 10 \
|
||||
-k gevent \
|
||||
--timeout 120 \
|
||||
-b 0.0.0.0:6666 \
|
||||
--limit-request-line 0 \
|
||||
--limit-request-field_size 0 \
|
||||
--statsd-host localhost:8125 \
|
||||
superset:app
|
||||
|
||||
Refer to the
|
||||
[Gunicorn documentation](http://docs.gunicorn.org/en/stable/design.html)
|
||||
for more information.
|
||||
|
||||
Note that *gunicorn* does not
|
||||
work on Windows so the `superset runserver` command is not expected to work
|
||||
in that context. Also note that the development web
|
||||
server (`superset runserver -d`) is not intended for production use.
|
||||
|
||||
|
||||
Configuration behind a load balancer
|
||||
------------------------------------
|
||||
@@ -156,7 +212,9 @@ of the parameters you can copy / paste in that configuration module: ::
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:////path/to/superset.db'
|
||||
|
||||
# Flask-WTF flag for CSRF
|
||||
CSRF_ENABLED = True
|
||||
WTF_CSRF_ENABLED = True
|
||||
# Add endpoints that need to be exempt from CSRF protection
|
||||
WTF_CSRF_EXEMPT_LIST = []
|
||||
|
||||
# Set this API key to enable Mapbox visualizations
|
||||
MAPBOX_API_KEY = ''
|
||||
@@ -172,6 +230,11 @@ Please make sure to change:
|
||||
* *SQLALCHEMY_DATABASE_URI*, by default it is stored at *~/.superset/superset.db*
|
||||
* *SECRET_KEY*, to a long random string
|
||||
|
||||
In case you need to exempt endpoints from CSRF, e.g. you are running a custom
|
||||
auth postback endpoint, you can add them to *WTF_CSRF_EXEMPT_LIST*
|
||||
|
||||
WTF_CSRF_EXEMPT_LIST = ['']
|
||||
|
||||
Database dependencies
|
||||
---------------------
|
||||
|
||||
@@ -196,7 +259,7 @@ Here's a list of some of the recommended packages.
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
| sqlite | | ``sqlite://`` |
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
| Redshift | ``pip install sqlalchemy-redshift`` | ``redshift+psycopg2://`` |
|
||||
| Redshift | ``pip install sqlalchemy-redshift`` | ``postgresql+psycopg2://`` |
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
| MSSQL | ``pip install pymssql`` | ``mssql://`` |
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
@@ -206,12 +269,31 @@ Here's a list of some of the recommended packages.
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
| Greenplum | ``pip install psycopg2`` | ``postgresql+psycopg2://`` |
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
| Athena | ``pip install "PyAthenaJDBC>1.0.9"``| ``awsathena+jdbc://`` |
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
| Vertica | ``pip install | ``vertica+vertica_python://`` |
|
||||
| | sqlalchemy-vertica-python`` | |
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
| ClickHouse | ``pip install | ``clickhouse://`` |
|
||||
| | sqlalchemy-clickhouse`` | |
|
||||
+---------------+-------------------------------------+-------------------------------------------------+
|
||||
|
||||
Note that many other database are supported, the main criteria being the
|
||||
existence of a functional SqlAlchemy dialect and Python driver. Googling
|
||||
the keyword ``sqlalchemy`` in addition of a keyword that describes the
|
||||
database you want to connect to should get you to the right place.
|
||||
|
||||
(AWS) Athena
|
||||
------------
|
||||
|
||||
The connection string for Athena looks like this ::
|
||||
|
||||
awsathena+jdbc://{aws_access_key_id}:{aws_secret_access_key}@athena.{region_name}.amazonaws.com/{schema_name}?s3_staging_dir={s3_staging_dir}&...
|
||||
|
||||
Where you need to escape/encode at least the s3_staging_dir, i.e., ::
|
||||
|
||||
s3://... -> s3%3A//...
|
||||
|
||||
|
||||
Caching
|
||||
-------
|
||||
@@ -223,9 +305,11 @@ complies with the Flask-Cache specifications.
|
||||
|
||||
Flask-Cache supports multiple caching backends (Redis, Memcached,
|
||||
SimpleCache (in-memory), or the local filesystem). If you are going to use
|
||||
Memcached please use the pylibmc client library as python-memcached does
|
||||
Memcached please use the `pylibmc` client library as `python-memcached` does
|
||||
not handle storing binary data correctly. If you use Redis, please install
|
||||
`python-redis <https://pypi.python.org/pypi/redis>`.
|
||||
the `redis <https://pypi.python.org/pypi/redis>`_ Python package: ::
|
||||
|
||||
pip install redis
|
||||
|
||||
For setting your timeouts, this is done in the Superset metadata and goes
|
||||
up the "timeout searchpath", from your slice configuration, to your
|
||||
@@ -259,6 +343,24 @@ on top of the **database**. For Superset to connect to a specific schema,
|
||||
there's a **schema** parameter you can set in the table form.
|
||||
|
||||
|
||||
External Password store for SQLAlchemy connections
|
||||
--------------------------------------------------
|
||||
It is possible to use an external store for you database passwords. This is
|
||||
useful if you a running a custom secret distribution framework and do not wish
|
||||
to store secrets in Superset's meta database.
|
||||
|
||||
Example:
|
||||
Write a function that takes a single argument of type ``sqla.engine.url`` and returns
|
||||
the password for the given connection string. Then set ``SQLALCHEMY_CUSTOM_PASSWORD_STORE``
|
||||
in your config file to point to that function. ::
|
||||
|
||||
def example_lookup_password(url):
|
||||
secret = <<get password from external framework>>
|
||||
return 'secret'
|
||||
|
||||
SQLALCHEMY_CUSTOM_PASSWORD_STORE = example_lookup_password
|
||||
|
||||
|
||||
SSL Access to databases
|
||||
-----------------------
|
||||
This example worked with a MySQL database that requires SSL. The configuration
|
||||
@@ -280,10 +382,10 @@ Druid
|
||||
-----
|
||||
|
||||
* From the UI, enter the information about your clusters in the
|
||||
``Admin->Clusters`` menu by hitting the + sign.
|
||||
`Sources -> Druid Clusters` menu by hitting the + sign.
|
||||
|
||||
* Once the Druid cluster connection information is entered, hit the
|
||||
``Admin->Refresh Metadata`` menu item to populate
|
||||
`Sources -> Refresh Druid Metadata` menu item to populate
|
||||
|
||||
* Navigate to your datasources
|
||||
|
||||
@@ -341,28 +443,74 @@ Upgrading should be as straightforward as running::
|
||||
SQL Lab
|
||||
-------
|
||||
SQL Lab is a powerful SQL IDE that works with all SQLAlchemy compatible
|
||||
databases out there. By default, queries are run in a web request, and
|
||||
databases. By default, queries are executed in the scope of a web
|
||||
request so they
|
||||
may eventually timeout as queries exceed the maximum duration of a web
|
||||
request in your environment, whether it'd be a reverse proxy or the Superset
|
||||
server itself.
|
||||
|
||||
In the modern analytics world, it's not uncommon to run large queries that
|
||||
run for minutes or hours.
|
||||
On large analytic databases, it's common to run queries that
|
||||
execute for minutes or hours.
|
||||
To enable support for long running queries that
|
||||
execute beyond the typical web request's timeout (30-60 seconds), it is
|
||||
necessary to deploy an asynchronous backend, which consist of one or many
|
||||
Superset worker, which is implemented as a Celery worker, and a Celery
|
||||
broker for which we recommend using Redis or RabbitMQ.
|
||||
necessary to configure an asynchronous backend for Superset which consist of:
|
||||
|
||||
It's also preferable to setup an async result backend as a key value store
|
||||
that can hold the long-running query results for a period of time. More
|
||||
details to come as to how to set this up here soon.
|
||||
* one or many Superset worker (which is implemented as a Celery worker), and
|
||||
can be started with the ``superset worker`` command, run
|
||||
``superset worker --help`` to view the related options
|
||||
* a celery broker (message queue) for which we recommend using Redis
|
||||
or RabbitMQ
|
||||
* a results backend that defines where the worker will persist the query
|
||||
results
|
||||
|
||||
SQL Lab supports templating in queries, and it's possible to override
|
||||
Configuring Celery requires defining a ``CELERY_CONFIG`` in your
|
||||
``superset_config.py``. Both the worker and web server processes should
|
||||
have the same configuration.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class CeleryConfig(object):
|
||||
BROKER_URL = 'redis://localhost:6379/0'
|
||||
CELERY_IMPORTS = ('superset.sql_lab', )
|
||||
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
|
||||
CELERY_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}
|
||||
|
||||
CELERY_CONFIG = CeleryConfig
|
||||
|
||||
To setup a result backend, you need to pass an instance of a derivative
|
||||
of ``werkzeug.contrib.cache.BaseCache`` to the ``RESULTS_BACKEND``
|
||||
configuration key in your ``superset_config.py``. It's possible to use
|
||||
Memcached, Redis, S3 (https://pypi.python.org/pypi/s3werkzeugcache),
|
||||
memory or the file system (in a single server-type setup or for testing),
|
||||
or to write your own caching interface. Your ``superset_config.py`` may
|
||||
look something like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# On S3
|
||||
from s3cache.s3cache import S3Cache
|
||||
S3_CACHE_BUCKET = 'foobar-superset'
|
||||
S3_CACHE_KEY_PREFIX = 'sql_lab_result'
|
||||
RESULTS_BACKEND = S3Cache(S3_CACHE_BUCKET, S3_CACHE_KEY_PREFIX)
|
||||
|
||||
# On Redis
|
||||
from werkzeug.contrib.cache import RedisCache
|
||||
RESULTS_BACKEND = RedisCache(
|
||||
host='localhost', port=6379, key_prefix='superset_results')
|
||||
|
||||
|
||||
Also note that SQL Lab supports Jinja templating in queries, and that it's
|
||||
possible to overload
|
||||
the default Jinja context in your environment by defining the
|
||||
``JINJA_CONTEXT_ADDONS`` in your superset configuration. Objects referenced
|
||||
in this dictionary are made available for users to use in their SQL.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
JINJA_CONTEXT_ADDONS = {
|
||||
'my_crazy_macro': lambda x: x*2,
|
||||
}
|
||||
|
||||
|
||||
Making your own build
|
||||
---------------------
|
||||
@@ -373,7 +521,49 @@ your environment.::
|
||||
|
||||
# assuming $SUPERSET_HOME as the root of the repo
|
||||
cd $SUPERSET_HOME/superset/assets
|
||||
npm install
|
||||
npm run build
|
||||
yarn
|
||||
yarn run build
|
||||
cd $SUPERSET_HOME
|
||||
python setup.py install
|
||||
|
||||
|
||||
Blueprints
|
||||
----------
|
||||
|
||||
`Blueprints are Flask's reusable apps <http://flask.pocoo.org/docs/0.12/blueprints/>`_.
|
||||
Superset allows you to specify an array of Blueprints
|
||||
in your ``superset_config`` module. Here's
|
||||
an example on how this can work with a simple Blueprint. By doing
|
||||
so, you can expect Superset to serve a page that says "OK"
|
||||
at the ``/simple_page`` url. This can allow you to run other things such
|
||||
as custom data visualization applications alongside Superset, on the
|
||||
same server.
|
||||
|
||||
..code ::
|
||||
|
||||
from flask import Blueprint
|
||||
simple_page = Blueprint('simple_page', __name__,
|
||||
template_folder='templates')
|
||||
@simple_page.route('/', defaults={'page': 'index'})
|
||||
@simple_page.route('/<page>')
|
||||
def show(page):
|
||||
return "Ok"
|
||||
|
||||
BLUEPRINTS = [simple_page]
|
||||
|
||||
StatsD logging
|
||||
--------------
|
||||
|
||||
Superset is instrumented to log events to StatsD if desired. Most endpoints hit
|
||||
are logged as well as key events like query start and end in SQL Lab.
|
||||
|
||||
To setup StatsD logging, it's a matter of configuring the logger in your
|
||||
``superset_config.py``.
|
||||
|
||||
..code ::
|
||||
|
||||
from superset.stats_logger import StatsdStatsLogger
|
||||
STATS_LOGGER = StatsdStatsLogger(host='localhost', port=8125, prefix='superset')
|
||||
|
||||
Note that it's also possible to implement you own logger by deriving
|
||||
``superset.stats_logger.BaseStatsLogger``.
|
||||
|
||||
@@ -3,7 +3,8 @@ Security
|
||||
Security in Superset is handled by Flask AppBuilder (FAB). FAB is a
|
||||
"Simple and rapid application development framework, built on top of Flask.".
|
||||
FAB provides authentication, user management, permissions and roles.
|
||||
|
||||
Please read its `Security documentation
|
||||
<http://flask-appbuilder.readthedocs.io/en/latest/security.html>`_.
|
||||
|
||||
Provided Roles
|
||||
--------------
|
||||
@@ -35,7 +36,7 @@ own. Alpha users can add and alter data sources.
|
||||
Gamma
|
||||
"""""
|
||||
Gamma have limited access. They can only consume data coming from data sources
|
||||
they have been giving access to through another complementary role.
|
||||
they have been given access to through another complementary role.
|
||||
They only have access to view the slices and
|
||||
dashboards made from data sources that they have access to. Currently Gamma
|
||||
users are not able to alter or add data sources. We assume that they are
|
||||
@@ -50,6 +51,17 @@ The ``sql_lab`` role grants access to SQL Lab. Note that while ``Admin``
|
||||
users have access to all databases by default, both ``Alpha`` and ``Gamma``
|
||||
users need to be given access on a per database basis.
|
||||
|
||||
Public
|
||||
""""""
|
||||
It's possible to allow logged out users to access some Superset features.
|
||||
|
||||
By setting ``PUBLIC_ROLE_LIKE_GAMMA = True`` in your ``superset_config.py``,
|
||||
you grant public role the same set of permissions as for the GAMMA role.
|
||||
This is useful if one wants to enable anonymous users to view
|
||||
dashboards. Explicit grant on specific datasets is still required, meaning
|
||||
that you need to edit the ``Public`` role and add the Public data sources
|
||||
to the role manually.
|
||||
|
||||
|
||||
Managing Gamma per data source access
|
||||
-------------------------------------
|
||||
|
||||
@@ -13,9 +13,11 @@ Feature Overview
|
||||
visualization capabilities
|
||||
- Browse database metadata: tables, columns, indexes, partitions
|
||||
- Support for long-running queries
|
||||
|
||||
- uses the `Celery distributed queue <http://www.python.org/>`_
|
||||
to dispatch query handling to workers
|
||||
- supports defining a "results backend" to persist query results
|
||||
|
||||
- A search engine to find queries executed in the past
|
||||
- Supports templating using the
|
||||
`Jinja templating language <http://jinja.pocoo.org/docs/dev/>`_
|
||||
@@ -58,3 +60,5 @@ Superset's Jinja context:
|
||||
|
||||
.. autoclass:: superset.jinja_context.PrestoTemplateProcessor
|
||||
:members:
|
||||
|
||||
.. autofunction:: superset.jinja_context.url_param
|
||||
|
||||
1765
docs/visualization.rst
Normal file
7
gen_changelog.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
# requires github-changes, run
|
||||
# `npm install -g github-changes`
|
||||
# requires $GITHUB_TOKEN to be set
|
||||
|
||||
# usage: ./github-changes 0.20.0 0.20.1
|
||||
# will overwrites the local CHANGELOG.md, somehow you need to merge it in
|
||||
github-changes -o apache -r incubator-superset --token $GITHUB_TOKEN --between-tags $1...$2
|
||||
2
pylint-errors.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
pylint superset --errors-only
|
||||
@@ -9,4 +9,6 @@ set -e
|
||||
superset/bin/superset db upgrade
|
||||
superset/bin/superset version -v
|
||||
python setup.py nosetests
|
||||
coveralls
|
||||
if [ "$CI" = "true" ] ; then
|
||||
coveralls
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from superset import sm
|
||||
from collections import defaultdict
|
||||
|
||||
from superset import sm
|
||||
|
||||
|
||||
def cleanup_permissions():
|
||||
# 1. Clean up duplicates.
|
||||
|
||||
@@ -23,6 +23,3 @@ detailed-errors=1
|
||||
with-coverage=1
|
||||
nocapture=1
|
||||
cover-package=superset
|
||||
|
||||
[pycodestyle]
|
||||
max-line-length=90
|
||||
|
||||
60
setup.py
@@ -1,10 +1,11 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import json
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
PACKAGE_DIR = os.path.join(BASE_DIR, 'superset', 'static', 'assets')
|
||||
PACKAGE_DIR = os.path.join(BASE_DIR, 'superset', 'assets')
|
||||
PACKAGE_FILE = os.path.join(PACKAGE_DIR, 'package.json')
|
||||
with open(PACKAGE_FILE) as package_file:
|
||||
version_string = json.load(package_file)['version']
|
||||
@@ -14,18 +15,19 @@ def get_git_sha():
|
||||
try:
|
||||
s = str(subprocess.check_output(['git', 'rev-parse', 'HEAD']))
|
||||
return s.strip()
|
||||
except:
|
||||
return ""
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
|
||||
GIT_SHA = get_git_sha()
|
||||
version_info = {
|
||||
'GIT_SHA': GIT_SHA,
|
||||
'version': version_string,
|
||||
}
|
||||
print("-==-" * 15)
|
||||
print("VERSION: " + version_string)
|
||||
print("GIT SHA: " + GIT_SHA)
|
||||
print("-==-" * 15)
|
||||
print('-==-' * 15)
|
||||
print('VERSION: ' + version_string)
|
||||
print('GIT SHA: ' + GIT_SHA)
|
||||
print('-==-' * 15)
|
||||
|
||||
with open(os.path.join(PACKAGE_DIR, 'version_info.json'), 'w') as version_file:
|
||||
json.dump(version_info, version_file)
|
||||
@@ -34,40 +36,45 @@ with open(os.path.join(PACKAGE_DIR, 'version_info.json'), 'w') as version_file:
|
||||
setup(
|
||||
name='superset',
|
||||
description=(
|
||||
"A interactive data visualization platform build on SqlAlchemy "
|
||||
"and druid.io"),
|
||||
'A interactive data visualization platform build on SqlAlchemy '
|
||||
'and druid.io'),
|
||||
version=version_string,
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
scripts=['superset/bin/superset'],
|
||||
install_requires=[
|
||||
'boto3==1.4.4',
|
||||
'celery==3.1.23',
|
||||
'cryptography==1.7.2',
|
||||
'flask-appbuilder==1.8.1',
|
||||
'boto3>=1.4.6',
|
||||
'celery==4.1.0',
|
||||
'colorama==0.3.9',
|
||||
'cryptography==1.9',
|
||||
'flask==0.12.2',
|
||||
'flask-appbuilder==1.9.4',
|
||||
'flask-cache==0.13.1',
|
||||
'flask-migrate==1.5.1',
|
||||
'flask-migrate==2.0.3',
|
||||
'flask-script==2.0.5',
|
||||
'flask-sqlalchemy==2.0',
|
||||
'flask-testing==0.6.1',
|
||||
'flask-sqlalchemy==2.1',
|
||||
'flask-testing==0.6.2',
|
||||
'flask-wtf==0.14.2',
|
||||
'flower==0.9.1',
|
||||
'future>=0.16.0, <0.17',
|
||||
'humanize==0.5.1',
|
||||
'gunicorn==19.6.0',
|
||||
'gunicorn==19.7.1',
|
||||
'idna==2.5',
|
||||
'markdown==2.6.8',
|
||||
'pandas==0.18.1',
|
||||
'pandas==0.20.3',
|
||||
'parsedatetime==2.0.0',
|
||||
'pydruid==0.3.1',
|
||||
'PyHive>=0.2.1',
|
||||
'PyHive>=0.4.0',
|
||||
'python-dateutil==2.6.0',
|
||||
'requests==2.13.0',
|
||||
'requests==2.17.3',
|
||||
'simplejson==3.10.0',
|
||||
'six==1.10.0',
|
||||
'sqlalchemy==1.1.5',
|
||||
'sqlalchemy-utils==0.32.12',
|
||||
'sqlparse==0.1.19',
|
||||
'sqlalchemy==1.1.9',
|
||||
'sqlalchemy-utils==0.32.16',
|
||||
'sqlparse==0.2.3',
|
||||
'thrift>=0.9.3',
|
||||
'thrift-sasl>=0.2.1',
|
||||
'werkzeug==0.11.15',
|
||||
],
|
||||
extras_require={
|
||||
'cors': ['Flask-Cors>=2.0.0'],
|
||||
@@ -77,6 +84,7 @@ setup(
|
||||
'coverage',
|
||||
'mock',
|
||||
'nose',
|
||||
'redis',
|
||||
],
|
||||
author='Maxime Beauchemin',
|
||||
author_email='maximebeauchemin@gmail.com',
|
||||
|
||||
@@ -4,19 +4,20 @@ from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
import os
|
||||
|
||||
from flask import Flask, redirect
|
||||
from flask_appbuilder import SQLA, AppBuilder, IndexView
|
||||
from flask_appbuilder import AppBuilder, IndexView, SQLA
|
||||
from flask_appbuilder.baseviews import expose
|
||||
from flask_migrate import Migrate
|
||||
from superset.source_registry import SourceRegistry
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
from werkzeug.contrib.fixers import ProxyFix
|
||||
from superset import utils
|
||||
|
||||
from superset.connectors.connector_registry import ConnectorRegistry
|
||||
from superset import utils, config # noqa
|
||||
|
||||
APP_DIR = os.path.dirname(__file__)
|
||||
CONFIG_MODULE = os.environ.get('SUPERSET_CONFIG', 'superset.config')
|
||||
@@ -24,11 +25,50 @@ CONFIG_MODULE = os.environ.get('SUPERSET_CONFIG', 'superset.config')
|
||||
with open(APP_DIR + '/static/assets/backendSync.json', 'r') as f:
|
||||
frontend_config = json.load(f)
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(CONFIG_MODULE)
|
||||
conf = app.config
|
||||
|
||||
#################################################################
|
||||
# Handling manifest file logic at app start
|
||||
#################################################################
|
||||
MANIFEST_FILE = APP_DIR + '/static/assets/dist/manifest.json'
|
||||
manifest = {}
|
||||
|
||||
|
||||
def parse_manifest_json():
|
||||
global manifest
|
||||
try:
|
||||
with open(MANIFEST_FILE, 'r') as f:
|
||||
manifest = json.load(f)
|
||||
except Exception:
|
||||
print('no manifest file found at ' + MANIFEST_FILE)
|
||||
|
||||
|
||||
def get_manifest_file(filename):
|
||||
if app.debug:
|
||||
parse_manifest_json()
|
||||
return '/static/assets/dist/' + manifest.get(filename, '')
|
||||
|
||||
|
||||
parse_manifest_json()
|
||||
|
||||
|
||||
@app.context_processor
|
||||
def get_js_manifest():
|
||||
return dict(js_manifest=get_manifest_file)
|
||||
|
||||
|
||||
#################################################################
|
||||
|
||||
for bp in conf.get('BLUEPRINTS'):
|
||||
try:
|
||||
print("Registering blueprint: '{}'".format(bp.name))
|
||||
app.register_blueprint(bp)
|
||||
except Exception as e:
|
||||
print('blueprint registration failed')
|
||||
logging.exception(e)
|
||||
|
||||
if conf.get('SILENCE_FAB'):
|
||||
logging.getLogger('flask_appbuilder').setLevel(logging.ERROR)
|
||||
|
||||
@@ -40,13 +80,18 @@ logging.getLogger('pyhive.presto').setLevel(logging.INFO)
|
||||
|
||||
db = SQLA(app)
|
||||
|
||||
if conf.get('WTF_CSRF_ENABLED'):
|
||||
csrf = CSRFProtect(app)
|
||||
csrf_exempt_list = conf.get('WTF_CSRF_EXEMPT_LIST', [])
|
||||
for ex in csrf_exempt_list:
|
||||
csrf.exempt(ex)
|
||||
|
||||
utils.pessimistic_connection_handling(db.engine.pool)
|
||||
utils.pessimistic_connection_handling(db.engine)
|
||||
|
||||
cache = utils.setup_cache(app, conf.get('CACHE_CONFIG'))
|
||||
tables_cache = utils.setup_cache(app, conf.get('TABLE_NAMES_CACHE_CONFIG'))
|
||||
|
||||
migrate = Migrate(app, db, directory=APP_DIR + "/migrations")
|
||||
migrate = Migrate(app, db, directory=APP_DIR + '/migrations')
|
||||
|
||||
# Logging configuration
|
||||
logging.basicConfig(format=app.config.get('LOG_FORMAT'))
|
||||
@@ -54,10 +99,11 @@ logging.getLogger().setLevel(app.config.get('LOG_LEVEL'))
|
||||
|
||||
if app.config.get('ENABLE_TIME_ROTATE'):
|
||||
logging.getLogger().setLevel(app.config.get('TIME_ROTATE_LOG_LEVEL'))
|
||||
handler = TimedRotatingFileHandler(app.config.get('FILENAME'),
|
||||
when=app.config.get('ROLLOVER'),
|
||||
interval=app.config.get('INTERVAL'),
|
||||
backupCount=app.config.get('BACKUP_COUNT'))
|
||||
handler = TimedRotatingFileHandler(
|
||||
app.config.get('FILENAME'),
|
||||
when=app.config.get('ROLLOVER'),
|
||||
interval=app.config.get('INTERVAL'),
|
||||
backupCount=app.config.get('BACKUP_COUNT'))
|
||||
logging.getLogger().addHandler(handler)
|
||||
|
||||
if app.config.get('ENABLE_CORS'):
|
||||
@@ -67,6 +113,21 @@ if app.config.get('ENABLE_CORS'):
|
||||
if app.config.get('ENABLE_PROXY_FIX'):
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app)
|
||||
|
||||
if app.config.get('ENABLE_CHUNK_ENCODING'):
|
||||
|
||||
class ChunkedEncodingFix(object):
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
# Setting wsgi.input_terminated tells werkzeug.wsgi to ignore
|
||||
# content-length and read the stream till the end.
|
||||
if environ.get('HTTP_TRANSFER_ENCODING', '').lower() == u'chunked':
|
||||
environ['wsgi.input_terminated'] = True
|
||||
return self.app(environ, start_response)
|
||||
|
||||
app.wsgi_app = ChunkedEncodingFix(app.wsgi_app)
|
||||
|
||||
if app.config.get('UPLOAD_FOLDER'):
|
||||
try:
|
||||
os.makedirs(app.config.get('UPLOAD_FOLDER'))
|
||||
@@ -82,20 +143,21 @@ class MyIndexView(IndexView):
|
||||
def index(self):
|
||||
return redirect('/superset/welcome')
|
||||
|
||||
|
||||
appbuilder = AppBuilder(
|
||||
app, db.session,
|
||||
app,
|
||||
db.session,
|
||||
base_template='superset/base.html',
|
||||
indexview=MyIndexView,
|
||||
security_manager_class=app.config.get("CUSTOM_SECURITY_MANAGER"))
|
||||
security_manager_class=app.config.get('CUSTOM_SECURITY_MANAGER'))
|
||||
|
||||
sm = appbuilder.sm
|
||||
|
||||
get_session = appbuilder.get_session
|
||||
results_backend = app.config.get("RESULTS_BACKEND")
|
||||
results_backend = app.config.get('RESULTS_BACKEND')
|
||||
|
||||
# Registering sources
|
||||
module_datasource_map = app.config.get("DEFAULT_MODULE_DS_MAP")
|
||||
module_datasource_map.update(app.config.get("ADDITIONAL_MODULE_DS_MAP"))
|
||||
SourceRegistry.register_sources(module_datasource_map)
|
||||
module_datasource_map = app.config.get('DEFAULT_MODULE_DS_MAP')
|
||||
module_datasource_map.update(app.config.get('ADDITIONAL_MODULE_DS_MAP'))
|
||||
ConnectorRegistry.register_sources(module_datasource_map)
|
||||
|
||||
from superset import views, config # noqa
|
||||
from superset import views # noqa
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"presets" : ["airbnb", "es2015", "react"],
|
||||
"presets" : ["airbnb"],
|
||||
}
|
||||
|
||||
@@ -7,3 +7,4 @@ node_modules/*
|
||||
node_modules*/*
|
||||
stylesheets/*
|
||||
vendor/*
|
||||
docs/*
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
"experimentalObjectRestSpread": true
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"document": true,
|
||||
},
|
||||
"rules": {
|
||||
"prefer-template": 0,
|
||||
"new-cap": 0,
|
||||
@@ -14,5 +17,26 @@
|
||||
"func-names": 0,
|
||||
"react/jsx-no-bind": 0,
|
||||
"no-confusing-arrow": 0,
|
||||
|
||||
"jsx-a11y/no-static-element-interactions": 0,
|
||||
"jsx-a11y/anchor-has-content": 0,
|
||||
"react/require-default-props": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-mixed-operators": 0,
|
||||
"no-continue": 0,
|
||||
"no-bitwise": 0,
|
||||
"no-undef": 0,
|
||||
"no-multi-assign": 0,
|
||||
"react/no-array-index-key": 0,
|
||||
"no-restricted-properties": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"jsx-a11y/href-no-hash": 0,
|
||||
"react/forbid-prop-types": 0,
|
||||
"class-methods-use-this": 0,
|
||||
"import/no-named-as-default": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"react/no-unescaped-entities": 0,
|
||||
"react/no-unused-prop-types": 0,
|
||||
"react/no-string-refs": 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"fields": {
|
||||
"controls": {
|
||||
"datasource": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Datasource",
|
||||
"isLoading": true,
|
||||
"clearable": false,
|
||||
@@ -9,7 +9,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"viz_type": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Visualization Type",
|
||||
"clearable": false,
|
||||
"default": "table",
|
||||
@@ -129,6 +129,11 @@
|
||||
"Directed Force Layout",
|
||||
"/static/assets/images/viz_thumbnails/directed_force.png"
|
||||
],
|
||||
[
|
||||
"country_map",
|
||||
"Country Map",
|
||||
"/static/assets/images/viz_thumbnails/country_map.png"
|
||||
],
|
||||
[
|
||||
"world_map",
|
||||
"World Map",
|
||||
@@ -168,7 +173,7 @@
|
||||
"description": "The type of visualization to display"
|
||||
},
|
||||
"metrics": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"multi": true,
|
||||
"label": "Metrics",
|
||||
"validators": [
|
||||
@@ -177,27 +182,27 @@
|
||||
"description": "One or many metrics to display"
|
||||
},
|
||||
"order_by_cols": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"multi": true,
|
||||
"label": "Ordering",
|
||||
"default": [],
|
||||
"description": "One or many metrics to display"
|
||||
},
|
||||
"metric": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Metric",
|
||||
"clearable": false,
|
||||
"description": "Choose the metric"
|
||||
},
|
||||
"metric_2": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Right Axis Metric",
|
||||
"choices": [],
|
||||
"default": [],
|
||||
"description": "Choose a metric for right axis"
|
||||
},
|
||||
"stacked_style": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Stacked Style",
|
||||
"choices": [
|
||||
[
|
||||
@@ -217,7 +222,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"linear_color_scheme": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Linear Color Scheme",
|
||||
"choices": [
|
||||
[
|
||||
@@ -241,7 +246,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"normalize_across": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Normalize Across",
|
||||
"choices": [
|
||||
[
|
||||
@@ -261,7 +266,7 @@
|
||||
"description": "Color will be rendered based on a ratio of the cell against the sum of across this criteria"
|
||||
},
|
||||
"horizon_color_scale": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Horizon Color Scale",
|
||||
"choices": [
|
||||
[
|
||||
@@ -281,7 +286,7 @@
|
||||
"description": "Defines how the color are attributed."
|
||||
},
|
||||
"canvas_image_rendering": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Rendering",
|
||||
"choices": [
|
||||
[
|
||||
@@ -297,7 +302,7 @@
|
||||
"description": "image-rendering CSS attribute of the canvas object that defines how the browser scales up the image"
|
||||
},
|
||||
"xscale_interval": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "XScale Interval",
|
||||
"choices": [
|
||||
[
|
||||
@@ -505,7 +510,7 @@
|
||||
"description": "Number of steps to take between ticks when displaying the X scale"
|
||||
},
|
||||
"yscale_interval": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "YScale Interval",
|
||||
"choices": [
|
||||
[
|
||||
@@ -712,62 +717,142 @@
|
||||
"default": null,
|
||||
"description": "Number of steps to take between ticks when displaying the Y scale"
|
||||
},
|
||||
"include_time": {
|
||||
"type": "CheckboxControl",
|
||||
"label": "Include Time",
|
||||
"description": "Whether to include the time granularity as defined in the time section",
|
||||
"default": false
|
||||
},
|
||||
"bar_stacked": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Stacked Bars",
|
||||
"renderTrigger": true,
|
||||
"default": false,
|
||||
"description": null
|
||||
},
|
||||
"show_markers": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Show Markers",
|
||||
"renderTrigger": true,
|
||||
"default": false,
|
||||
"description": "Show data points as circle markers on the lines"
|
||||
},
|
||||
"show_bar_value": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Bar Values",
|
||||
"default": false,
|
||||
"renderTrigger": true,
|
||||
"description": "Show the value on top of the bar"
|
||||
},
|
||||
"order_bars": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Sort Bars",
|
||||
"default": false,
|
||||
"description": "Sort bars by x labels."
|
||||
},
|
||||
"combine_metric": {
|
||||
"type": "CheckboxControl",
|
||||
"label": "Combine Metrics",
|
||||
"default": false,
|
||||
"description": "Display metrics side by side within each column, as opposed to each column being displayed side by side for each metric."
|
||||
},
|
||||
"show_controls": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Extra Controls",
|
||||
"renderTrigger": true,
|
||||
"default": false,
|
||||
"description": "Whether to show extra controls or not. Extra controls include things like making mulitBar charts stacked or side by side."
|
||||
},
|
||||
"reduce_x_ticks": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Reduce X ticks",
|
||||
"renderTrigger": true,
|
||||
"default": false,
|
||||
"description": "Reduces the number of X axis ticks to be rendered. If true, the x axis wont overflow and labels may be missing. If false, a minimum width will be applied to columns and the width may overflow into an horizontal scroll."
|
||||
},
|
||||
"include_series": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Include Series",
|
||||
"renderTrigger": true,
|
||||
"default": false,
|
||||
"description": "Include series name as an axis"
|
||||
},
|
||||
"secondary_metric": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Color Metric",
|
||||
"default": null,
|
||||
"description": "A metric to use for color"
|
||||
},
|
||||
"select_country": {
|
||||
"type": "SelectControl",
|
||||
"label": "Country Name Type",
|
||||
"default": "France",
|
||||
"choices": [
|
||||
[
|
||||
"Algeria",
|
||||
"Algeria"
|
||||
],
|
||||
[
|
||||
"Belgium",
|
||||
"Belgium"
|
||||
],
|
||||
[
|
||||
"Brasil",
|
||||
"Brasil"
|
||||
],
|
||||
[
|
||||
"China",
|
||||
"China"
|
||||
],
|
||||
[
|
||||
"Germany",
|
||||
"Germany"
|
||||
],
|
||||
[
|
||||
"Egypt",
|
||||
"Egypt"
|
||||
],
|
||||
[
|
||||
"France",
|
||||
"France"
|
||||
],
|
||||
[
|
||||
"Italy",
|
||||
"Italy"
|
||||
],
|
||||
[
|
||||
"Morocco",
|
||||
"Morocco"
|
||||
],
|
||||
[
|
||||
"Nederlanden",
|
||||
"Nederlanden"
|
||||
],
|
||||
[
|
||||
"Russia",
|
||||
"Russia"
|
||||
],
|
||||
[
|
||||
"Singapore",
|
||||
"Singapore"
|
||||
],
|
||||
[
|
||||
"Spain",
|
||||
"Spain"
|
||||
],
|
||||
[
|
||||
"Uk",
|
||||
"Uk"
|
||||
],
|
||||
[
|
||||
"Usa",
|
||||
"Usa"
|
||||
]
|
||||
],
|
||||
"description": "The name of country that Superset should display"
|
||||
},
|
||||
"country_fieldtype": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Country Field Type",
|
||||
"default": "cca2",
|
||||
"choices": [
|
||||
@@ -791,40 +876,40 @@
|
||||
"description": "The country code standard that Superset should expect to find in the [country] column"
|
||||
},
|
||||
"groupby": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"multi": true,
|
||||
"label": "Group by",
|
||||
"default": [],
|
||||
"description": "One or many fields to group by"
|
||||
"description": "One or many controls to group by"
|
||||
},
|
||||
"columns": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"multi": true,
|
||||
"label": "Columns",
|
||||
"default": [],
|
||||
"description": "One or many fields to pivot as columns"
|
||||
"description": "One or many controls to pivot as columns"
|
||||
},
|
||||
"all_columns": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"multi": true,
|
||||
"label": "Columns",
|
||||
"default": [],
|
||||
"description": "Columns to display"
|
||||
},
|
||||
"all_columns_x": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "X",
|
||||
"default": null,
|
||||
"description": "Columns to display"
|
||||
},
|
||||
"all_columns_y": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Y",
|
||||
"default": null,
|
||||
"description": "Columns to display"
|
||||
},
|
||||
"druid_time_origin": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Origin",
|
||||
"choices": [
|
||||
@@ -841,7 +926,7 @@
|
||||
"description": "Defines the origin where time buckets start, accepts natural dates as in `now`, `sunday` or `1970-01-01`"
|
||||
},
|
||||
"bottom_margin": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Bottom Margin",
|
||||
"choices": [
|
||||
@@ -878,7 +963,7 @@
|
||||
"description": "Bottom marging, in pixels, allowing for more room for axis labels"
|
||||
},
|
||||
"granularity": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Time Granularity",
|
||||
"default": "one day",
|
||||
@@ -939,7 +1024,7 @@
|
||||
"description": "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`, `1 day` or `56 weeks`"
|
||||
},
|
||||
"domain_granularity": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Domain",
|
||||
"default": "month",
|
||||
"choices": [
|
||||
@@ -967,7 +1052,7 @@
|
||||
"description": "The time unit used for the grouping of blocks"
|
||||
},
|
||||
"subdomain_granularity": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Subdomain",
|
||||
"default": "day",
|
||||
"choices": [
|
||||
@@ -995,7 +1080,7 @@
|
||||
"description": "The time unit for each block. Should be a smaller unit than domain_granularity. Should be larger or equal to Time Grain"
|
||||
},
|
||||
"link_length": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Link Length",
|
||||
"default": "200",
|
||||
@@ -1036,7 +1121,7 @@
|
||||
"description": "Link length in the force layout"
|
||||
},
|
||||
"charge": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Charge",
|
||||
"default": "-500",
|
||||
@@ -1085,17 +1170,17 @@
|
||||
"description": "Charge in the force layout"
|
||||
},
|
||||
"granularity_sqla": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Time Column",
|
||||
"description": "The time column for the visualization. Note that you can define arbitrary expression that return a DATETIME column in the table or. Also note that the filter below is applied against this column or expression"
|
||||
},
|
||||
"time_grain_sqla": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Time Grain",
|
||||
"description": "The time granularity for the visualization. This applies a date transformation to alter your time column and defines a new time granularity. The options here are defined on a per database engine basis in the Superset source code."
|
||||
},
|
||||
"resample_rule": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Resample Rule",
|
||||
"default": null,
|
||||
@@ -1132,7 +1217,7 @@
|
||||
"description": "Pandas resample rule"
|
||||
},
|
||||
"resample_how": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Resample How",
|
||||
"default": null,
|
||||
@@ -1157,7 +1242,7 @@
|
||||
"description": "Pandas resample how"
|
||||
},
|
||||
"resample_fillmethod": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Resample Fill Method",
|
||||
"default": null,
|
||||
@@ -1178,7 +1263,7 @@
|
||||
"description": "Pandas resample fill method"
|
||||
},
|
||||
"since": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Since",
|
||||
"default": "7 days ago",
|
||||
@@ -1219,7 +1304,7 @@
|
||||
"description": "Timestamp from filter. This supports free form typing and natural language as in `1 day ago`, `28 days` or `3 years`"
|
||||
},
|
||||
"until": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Until",
|
||||
"default": "now",
|
||||
@@ -1251,7 +1336,7 @@
|
||||
]
|
||||
},
|
||||
"max_bubble_size": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Max Bubble Size",
|
||||
"default": "25",
|
||||
@@ -1287,7 +1372,7 @@
|
||||
]
|
||||
},
|
||||
"whisker_options": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Whisker/outlier options",
|
||||
"default": "Tukey",
|
||||
@@ -1312,20 +1397,18 @@
|
||||
]
|
||||
},
|
||||
"treemap_ratio": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Ratio",
|
||||
"isFloat": true,
|
||||
"default": 1.618033988749895,
|
||||
"description": "Target aspect ratio for treemap tiles."
|
||||
},
|
||||
"number_format": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Number format",
|
||||
"default": [
|
||||
".3s",
|
||||
".3s | 12.3k"
|
||||
],
|
||||
"renderTrigger": true,
|
||||
"default": ".3s",
|
||||
"choices": [
|
||||
[
|
||||
".3s",
|
||||
@@ -1355,7 +1438,7 @@
|
||||
"description": "D3 format syntax: https://github.com/d3/d3-format"
|
||||
},
|
||||
"row_limit": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Row limit",
|
||||
"default": null,
|
||||
@@ -1399,7 +1482,7 @@
|
||||
]
|
||||
},
|
||||
"limit": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Series limit",
|
||||
"choices": [
|
||||
@@ -1436,13 +1519,13 @@
|
||||
"description": "Limits the number of time series that get displayed"
|
||||
},
|
||||
"timeseries_limit_metric": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Sort By",
|
||||
"default": null,
|
||||
"description": "Metric used to define the top series"
|
||||
},
|
||||
"rolling_type": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Rolling",
|
||||
"default": "None",
|
||||
"choices": [
|
||||
@@ -1470,83 +1553,83 @@
|
||||
"description": "Defines a rolling window function to apply, works along with the [Periods] text box"
|
||||
},
|
||||
"rolling_periods": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Periods",
|
||||
"isInt": true,
|
||||
"description": "Defines the size of the rolling window function, relative to the time granularity selected"
|
||||
},
|
||||
"series": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Series",
|
||||
"default": null,
|
||||
"description": "Defines the grouping of entities. Each series is shown as a specific color on the chart and has a legend toggle"
|
||||
},
|
||||
"entity": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Entity",
|
||||
"default": null,
|
||||
"description": "This define the element to be plotted on the chart"
|
||||
},
|
||||
"x": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "X Axis",
|
||||
"default": null,
|
||||
"description": "Metric assigned to the [X] axis"
|
||||
},
|
||||
"y": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Y Axis",
|
||||
"default": null,
|
||||
"description": "Metric assigned to the [Y] axis"
|
||||
},
|
||||
"size": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Bubble Size",
|
||||
"default": null
|
||||
},
|
||||
"url": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "URL",
|
||||
"description": "The URL, this field is templated, so you can integrate {{ width }} and/or {{ height }} in your URL string.",
|
||||
"default": "https: //www.youtube.com/embed/JkI5rg_VcQ4"
|
||||
"description": "The URL, this control is templated, so you can integrate {{ width }} and/or {{ height }} in your URL string.",
|
||||
"default": "https://www.youtube.com/embed/AdSZJzb-aX8"
|
||||
},
|
||||
"x_axis_label": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "X Axis Label",
|
||||
"renderTrigger": true,
|
||||
"default": ""
|
||||
},
|
||||
"y_axis_label": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Y Axis Label",
|
||||
"renderTrigger": true,
|
||||
"default": ""
|
||||
},
|
||||
"where": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Custom WHERE clause",
|
||||
"default": "",
|
||||
"description": "The text in this box gets included in your query's WHERE clause, as an AND to other criteria. You can include complex expression, parenthesis and anything else supported by the backend it is directed towards."
|
||||
},
|
||||
"having": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Custom HAVING clause",
|
||||
"default": "",
|
||||
"description": "The text in this box gets included in your query's HAVING clause, as an AND to other criteria. You can include complex expression, parenthesis and anything else supported by the backend it is directed towards."
|
||||
},
|
||||
"compare_lag": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Comparison Period Lag",
|
||||
"isInt": true,
|
||||
"description": "Based on granularity, number of time periods to compare against"
|
||||
},
|
||||
"compare_suffix": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Comparison suffix",
|
||||
"description": "Suffix to apply after the percentage display"
|
||||
},
|
||||
"table_timestamp_format": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Table Timestamp Format",
|
||||
"default": "smart_date",
|
||||
@@ -1575,7 +1658,7 @@
|
||||
"description": "Timestamp Format"
|
||||
},
|
||||
"series_height": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Series Height",
|
||||
"default": "25",
|
||||
@@ -1616,7 +1699,7 @@
|
||||
"description": "Pixel height of each series"
|
||||
},
|
||||
"page_length": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Page Length",
|
||||
"default": 0,
|
||||
@@ -1661,7 +1744,7 @@
|
||||
"description": "Rows per page, 0 means no pagination"
|
||||
},
|
||||
"x_axis_format": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "X axis format",
|
||||
"renderTrigger": true,
|
||||
@@ -1691,7 +1774,7 @@
|
||||
"description": "D3 format syntax: https://github.com/d3/d3-format"
|
||||
},
|
||||
"y_axis_format": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Y axis format",
|
||||
"renderTrigger": true,
|
||||
@@ -1725,7 +1808,7 @@
|
||||
"description": "D3 format syntax: https://github.com/d3/d3-format"
|
||||
},
|
||||
"y_axis_2_format": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Right axis format",
|
||||
"default": ".3s",
|
||||
@@ -1758,7 +1841,7 @@
|
||||
"description": "D3 format syntax: https://github.com/d3/d3-format"
|
||||
},
|
||||
"markup_type": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Markup Type",
|
||||
"choices": [
|
||||
[
|
||||
@@ -1774,7 +1857,7 @@
|
||||
"description": "Pick your favorite markup language"
|
||||
},
|
||||
"rotation": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Rotation",
|
||||
"choices": [
|
||||
[
|
||||
@@ -1794,7 +1877,7 @@
|
||||
"description": "Rotation to apply to words in the cloud"
|
||||
},
|
||||
"line_interpolation": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Line Style",
|
||||
"renderTrigger": true,
|
||||
"choices": [
|
||||
@@ -1827,7 +1910,7 @@
|
||||
"description": "Line interpolation as defined by d3.js"
|
||||
},
|
||||
"pie_label_type": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Label Type",
|
||||
"default": "key",
|
||||
"choices": [
|
||||
@@ -1847,13 +1930,13 @@
|
||||
"description": "What should be shown on the label?"
|
||||
},
|
||||
"code": {
|
||||
"type": "TextAreaField",
|
||||
"type": "TextAreaControl",
|
||||
"label": "Code",
|
||||
"description": "Put your code here",
|
||||
"default": ""
|
||||
},
|
||||
"pandas_aggfunc": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Aggregation function",
|
||||
"clearable": false,
|
||||
"choices": [
|
||||
@@ -1890,127 +1973,134 @@
|
||||
"description": "Aggregate function to apply when pivoting and computing the total rows and columns"
|
||||
},
|
||||
"size_from": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"isInt": true,
|
||||
"label": "Font Size From",
|
||||
"default": "20",
|
||||
"description": "Font size for the smallest value in the list"
|
||||
},
|
||||
"size_to": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"isInt": true,
|
||||
"label": "Font Size To",
|
||||
"default": "150",
|
||||
"description": "Font size for the biggest value in the list"
|
||||
},
|
||||
"instant_filtering": {
|
||||
"type": "CheckboxControl",
|
||||
"label": "Instant Filtering",
|
||||
"renderTrigger": true,
|
||||
"default": true,
|
||||
"description": "Whether to apply filters as they change, or wait forusers to hit an [Apply] button"
|
||||
},
|
||||
"show_brush": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Range Filter",
|
||||
"renderTrigger": true,
|
||||
"default": false,
|
||||
"description": "Whether to display the time range interactive selector"
|
||||
},
|
||||
"date_filter": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Date Filter",
|
||||
"default": false,
|
||||
"description": "Whether to include a time filter"
|
||||
},
|
||||
"show_datatable": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Data Table",
|
||||
"default": false,
|
||||
"description": "Whether to display the interactive data table"
|
||||
},
|
||||
"include_search": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Search Box",
|
||||
"renderTrigger": true,
|
||||
"default": false,
|
||||
"description": "Whether to include a client side search box"
|
||||
},
|
||||
"table_filter": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Table Filter",
|
||||
"default": false,
|
||||
"description": "Whether to apply filter when table cell is clicked"
|
||||
},
|
||||
"show_bubbles": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Show Bubbles",
|
||||
"default": false,
|
||||
"renderTrigger": true,
|
||||
"description": "Whether to display bubbles on top of countries"
|
||||
},
|
||||
"show_legend": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Legend",
|
||||
"renderTrigger": true,
|
||||
"default": true,
|
||||
"description": "Whether to display the legend (toggles)"
|
||||
},
|
||||
"x_axis_showminmax": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "X bounds",
|
||||
"renderTrigger": true,
|
||||
"default": true,
|
||||
"description": "Whether to display the min and max values of the X axis"
|
||||
},
|
||||
"rich_tooltip": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Rich Tooltip",
|
||||
"renderTrigger": true,
|
||||
"default": true,
|
||||
"description": "The rich tooltip shows a list of all series for that point in time"
|
||||
},
|
||||
"y_axis_zero": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Y Axis Zero",
|
||||
"default": false,
|
||||
"renderTrigger": true,
|
||||
"description": "Force the Y axis to start at 0 instead of the minimum value"
|
||||
},
|
||||
"y_log_scale": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Y Log Scale",
|
||||
"default": false,
|
||||
"renderTrigger": true,
|
||||
"description": "Use a log scale for the Y axis"
|
||||
},
|
||||
"x_log_scale": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "X Log Scale",
|
||||
"default": false,
|
||||
"renderTrigger": true,
|
||||
"description": "Use a log scale for the X axis"
|
||||
},
|
||||
"donut": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Donut",
|
||||
"default": false,
|
||||
"description": "Do you want a donut or a pie?"
|
||||
},
|
||||
"labels_outside": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Put labels outside",
|
||||
"default": true,
|
||||
"description": "Put the labels outside the pie?"
|
||||
},
|
||||
"contribution": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Contribution",
|
||||
"default": false,
|
||||
"description": "Compute the contribution to the total"
|
||||
},
|
||||
"num_period_compare": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Period Ratio",
|
||||
"default": "",
|
||||
"isInt": true,
|
||||
"description": "[integer] Number of period to compare against, this is relative to the granularity selected"
|
||||
},
|
||||
"period_ratio_type": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Period Ratio Type",
|
||||
"default": "growth",
|
||||
"choices": [
|
||||
@@ -2030,25 +2120,25 @@
|
||||
"description": "`factor` means (new/previous), `growth` is ((new/previous) - 1), `value` is (new-previous)"
|
||||
},
|
||||
"time_compare": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Time Shift",
|
||||
"default": null,
|
||||
"description": "Overlay a timeseries from a relative time period. Expects relative time delta in natural language (example: 24 hours, 7 days, 56 weeks, 365 days"
|
||||
"description": "Overlay a timeseries from a relative time period. Expects relative time delta in natural language (example: 24 hours, 7 days, 56 weeks, 365 days)"
|
||||
},
|
||||
"subheader": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Subheader",
|
||||
"description": "Description text that shows up below your Big Number"
|
||||
},
|
||||
"mapbox_label": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"multi": true,
|
||||
"label": "label",
|
||||
"default": [],
|
||||
"description": "`count` is COUNT(*) if a group by is used. Numerical columns will be aggregated with the aggregator. Non-numerical columns will be used to label points. Leave empty to get a count of points in each cluster."
|
||||
},
|
||||
"mapbox_style": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Map Style",
|
||||
"choices": [
|
||||
[
|
||||
@@ -2080,7 +2170,7 @@
|
||||
"description": "Base layer map style"
|
||||
},
|
||||
"clustering_radius": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "Clustering Radius",
|
||||
"default": "60",
|
||||
@@ -2125,13 +2215,13 @@
|
||||
"description": "The radius (in pixels) the algorithm uses to define a cluster. Choose 0 to turn off clustering, but beware that a large number of points (>1000) will cause lag."
|
||||
},
|
||||
"point_radius": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Point Radius",
|
||||
"default": "Auto",
|
||||
"description": "The radius of individual points (ones that are not in a cluster). Either a numerical column or `Auto`, which scales the point based on the largest cluster"
|
||||
},
|
||||
"point_radius_unit": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"label": "Point Radius Unit",
|
||||
"default": "Pixels",
|
||||
"choices": [
|
||||
@@ -2151,14 +2241,14 @@
|
||||
"description": "The unit of measure for the specified point radius"
|
||||
},
|
||||
"global_opacity": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Opacity",
|
||||
"default": 1,
|
||||
"isFloat": true,
|
||||
"description": "Opacity of all clusters, points, and labels. Between 0 and 1."
|
||||
},
|
||||
"viewport_zoom": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Zoom",
|
||||
"isFloat": true,
|
||||
"default": 11,
|
||||
@@ -2166,7 +2256,7 @@
|
||||
"places": 8
|
||||
},
|
||||
"viewport_latitude": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Default latitude",
|
||||
"default": 37.772123,
|
||||
"isFloat": true,
|
||||
@@ -2174,7 +2264,7 @@
|
||||
"places": 8
|
||||
},
|
||||
"viewport_longitude": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Default longitude",
|
||||
"default": -122.405293,
|
||||
"isFloat": true,
|
||||
@@ -2182,13 +2272,13 @@
|
||||
"places": 8
|
||||
},
|
||||
"render_while_dragging": {
|
||||
"type": "CheckboxField",
|
||||
"type": "CheckboxControl",
|
||||
"label": "Live render",
|
||||
"default": true,
|
||||
"description": "Points and clusters will update as viewport is being changed"
|
||||
},
|
||||
"mapbox_color": {
|
||||
"type": "SelectField",
|
||||
"type": "SelectControl",
|
||||
"freeForm": true,
|
||||
"label": "RGB Color",
|
||||
"default": "rgb(0, 122, 135)",
|
||||
@@ -2221,58 +2311,64 @@
|
||||
"description": "The color for points and clusters in RGB"
|
||||
},
|
||||
"ranges": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Ranges",
|
||||
"default": "",
|
||||
"description": "Ranges to highlight with shading"
|
||||
},
|
||||
"range_labels": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Range labels",
|
||||
"default": "",
|
||||
"description": "Labels for the ranges"
|
||||
},
|
||||
"markers": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Markers",
|
||||
"default": "",
|
||||
"description": "List of values to mark with triangles"
|
||||
},
|
||||
"marker_labels": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Marker labels",
|
||||
"default": "",
|
||||
"description": "Labels for the markers"
|
||||
},
|
||||
"marker_lines": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Marker lines",
|
||||
"default": "",
|
||||
"description": "List of values to mark with lines"
|
||||
},
|
||||
"marker_line_labels": {
|
||||
"type": "TextField",
|
||||
"type": "TextControl",
|
||||
"label": "Marker line labels",
|
||||
"default": "",
|
||||
"description": "Labels for the marker lines"
|
||||
},
|
||||
"filters": {
|
||||
"type": "FilterField",
|
||||
"type": "FilterControl",
|
||||
"label": "",
|
||||
"default": [],
|
||||
"description": ""
|
||||
},
|
||||
"having_filters": {
|
||||
"type": "FilterField",
|
||||
"type": "FilterControl",
|
||||
"label": "",
|
||||
"default": [],
|
||||
"description": ""
|
||||
},
|
||||
"slice_id": {
|
||||
"type": "HiddenField",
|
||||
"type": "HiddenControl",
|
||||
"label": "Slice ID",
|
||||
"hidden": true,
|
||||
"description": "The id of the active slice"
|
||||
},
|
||||
"cache_timeout": {
|
||||
"type": "HiddenControl",
|
||||
"label": "Cache Timeout (seconds)",
|
||||
"hidden": true,
|
||||
"description": "The number of seconds before expiring the cache"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
1
superset/assets/docs
Symbolic link
@@ -0,0 +1 @@
|
||||
../../docs/_build/html/
|
||||
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 6.8 KiB |
BIN
superset/assets/images/s.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
superset/assets/images/tutorial/add_db.png
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
superset/assets/images/viz_thumbnails/chord.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
BIN
superset/assets/images/viz_thumbnails/country_map.png
Normal file
|
After Width: | Height: | Size: 296 KiB |
BIN
superset/assets/images/viz_thumbnails/deck_grid.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
superset/assets/images/viz_thumbnails/deck_hex.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
superset/assets/images/viz_thumbnails/deck_scatter.png
Normal file
|
After Width: | Height: | Size: 777 KiB |
BIN
superset/assets/images/viz_thumbnails/deck_screengrid.png
Normal file
|
After Width: | Height: | Size: 578 KiB |
BIN
superset/assets/images/viz_thumbnails/dual_line.png
Normal file → Executable file
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 162 KiB |
BIN
superset/assets/images/viz_thumbnails/event_flow.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 161 KiB |
BIN
superset/assets/images/viz_thumbnails/paired_ttest.png
Normal file
|
After Width: | Height: | Size: 230 KiB |
BIN
superset/assets/images/viz_thumbnails/partition.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
superset/assets/images/viz_thumbnails/time_table.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
@@ -1,5 +1,8 @@
|
||||
/* global notify */
|
||||
import shortid from 'shortid';
|
||||
import { now } from '../modules/dates';
|
||||
import { t } from '../locales';
|
||||
|
||||
const $ = require('jquery');
|
||||
|
||||
export const RESET_STATE = 'RESET_STATE';
|
||||
@@ -18,13 +21,14 @@ export const QUERY_EDITOR_SET_TITLE = 'QUERY_EDITOR_SET_TITLE';
|
||||
export const QUERY_EDITOR_SET_AUTORUN = 'QUERY_EDITOR_SET_AUTORUN';
|
||||
export const QUERY_EDITOR_SET_SQL = 'QUERY_EDITOR_SET_SQL';
|
||||
export const QUERY_EDITOR_SET_SELECTED_TEXT = 'QUERY_EDITOR_SET_SELECTED_TEXT';
|
||||
export const QUERY_EDITOR_PERSIST_HEIGHT = 'QUERY_EDITOR_PERSIST_HEIGHT';
|
||||
|
||||
export const SET_DATABASES = 'SET_DATABASES';
|
||||
export const SET_ACTIVE_QUERY_EDITOR = 'SET_ACTIVE_QUERY_EDITOR';
|
||||
export const SET_ACTIVE_SOUTHPANE_TAB = 'SET_ACTIVE_SOUTHPANE_TAB';
|
||||
export const ADD_ALERT = 'ADD_ALERT';
|
||||
export const REMOVE_ALERT = 'REMOVE_ALERT';
|
||||
export const REFRESH_QUERIES = 'REFRESH_QUERIES';
|
||||
export const SET_NETWORK_STATUS = 'SET_NETWORK_STATUS';
|
||||
export const RUN_QUERY = 'RUN_QUERY';
|
||||
export const START_QUERY = 'START_QUERY';
|
||||
export const STOP_QUERY = 'STOP_QUERY';
|
||||
@@ -34,11 +38,29 @@ export const QUERY_FAILED = 'QUERY_FAILED';
|
||||
export const CLEAR_QUERY_RESULTS = 'CLEAR_QUERY_RESULTS';
|
||||
export const REMOVE_DATA_PREVIEW = 'REMOVE_DATA_PREVIEW';
|
||||
export const CHANGE_DATA_PREVIEW_ID = 'CHANGE_DATA_PREVIEW_ID';
|
||||
export const SAVE_QUERY = 'SAVE_QUERY';
|
||||
|
||||
export const CREATE_DATASOURCE_STARTED = 'CREATE_DATASOURCE_STARTED';
|
||||
export const CREATE_DATASOURCE_SUCCESS = 'CREATE_DATASOURCE_SUCCESS';
|
||||
export const CREATE_DATASOURCE_FAILED = 'CREATE_DATASOURCE_FAILED';
|
||||
|
||||
export function resetState() {
|
||||
return { type: RESET_STATE };
|
||||
}
|
||||
|
||||
export function saveQuery(query) {
|
||||
const url = '/savedqueryviewapi/api/create';
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url,
|
||||
data: query,
|
||||
success: () => notify.success(t('Your query was saved')),
|
||||
error: () => notify.error(t('Your query could not be saved')),
|
||||
dataType: 'json',
|
||||
});
|
||||
return { type: SAVE_QUERY };
|
||||
}
|
||||
|
||||
export function startQuery(query) {
|
||||
Object.assign(query, {
|
||||
id: query.id ? query.id : shortid.generate(),
|
||||
@@ -86,7 +108,7 @@ export function fetchQueryResults(query) {
|
||||
dispatch(querySuccess(query, results));
|
||||
},
|
||||
error(err) {
|
||||
let msg = 'Failed at retrieving results from the results backend';
|
||||
let msg = t('Failed at retrieving results from the results backend');
|
||||
if (err.responseJSON && err.responseJSON.error) {
|
||||
msg = err.responseJSON.error;
|
||||
}
|
||||
@@ -99,7 +121,6 @@ export function fetchQueryResults(query) {
|
||||
export function runQuery(query) {
|
||||
return function (dispatch) {
|
||||
dispatch(startQuery(query));
|
||||
const sqlJsonUrl = '/superset/sql_json/';
|
||||
const sqlJsonRequest = {
|
||||
client_id: query.id,
|
||||
database_id: query.dbId,
|
||||
@@ -112,6 +133,7 @@ export function runQuery(query) {
|
||||
tmp_table_name: query.tempTableName,
|
||||
select_as_cta: query.ctas,
|
||||
};
|
||||
const sqlJsonUrl = '/superset/sql_json/' + location.search;
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
@@ -131,10 +153,15 @@ export function runQuery(query) {
|
||||
msg = err.responseText;
|
||||
}
|
||||
}
|
||||
if (textStatus === 'error' && errorThrown === '') {
|
||||
msg = 'Could not connect to server';
|
||||
} else if (msg === null) {
|
||||
msg = `[${textStatus}] ${errorThrown}`;
|
||||
if (msg === null) {
|
||||
if (errorThrown) {
|
||||
msg = `[${textStatus}] ${errorThrown}`;
|
||||
} else {
|
||||
msg = t('Unknown error');
|
||||
}
|
||||
}
|
||||
if (msg.indexOf('CSRF token') > 0) {
|
||||
msg = t('Your session timed out, please refresh your page and try again.');
|
||||
}
|
||||
dispatch(queryFailed(query, msg));
|
||||
},
|
||||
@@ -142,6 +169,26 @@ export function runQuery(query) {
|
||||
};
|
||||
}
|
||||
|
||||
export function postStopQuery(query) {
|
||||
return function (dispatch) {
|
||||
const stopQueryUrl = '/superset/stop_query/';
|
||||
const stopQueryRequestData = { client_id: query.id };
|
||||
dispatch(stopQuery(query));
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: stopQueryUrl,
|
||||
data: stopQueryRequestData,
|
||||
success() {
|
||||
notify.success(t('Query was stopped.'));
|
||||
},
|
||||
error() {
|
||||
notify.error(t('Failed at stopping query.'));
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function setDatabases(databases) {
|
||||
return { type: SET_DATABASES, databases };
|
||||
}
|
||||
@@ -155,10 +202,6 @@ export function cloneQueryToNewTab(query) {
|
||||
return { type: CLONE_QUERY_TO_NEW_TAB, query };
|
||||
}
|
||||
|
||||
export function setNetworkStatus(networkOn) {
|
||||
return { type: SET_NETWORK_STATUS, networkOn };
|
||||
}
|
||||
|
||||
export function addAlert(alert) {
|
||||
const o = Object.assign({}, alert);
|
||||
o.id = shortid.generate();
|
||||
@@ -215,6 +258,18 @@ export function mergeTable(table, query) {
|
||||
|
||||
export function addTable(query, tableName, schemaName) {
|
||||
return function (dispatch) {
|
||||
let table = {
|
||||
dbId: query.dbId,
|
||||
queryEditorId: query.id,
|
||||
schema: schemaName,
|
||||
name: tableName,
|
||||
};
|
||||
dispatch(mergeTable(Object.assign({}, table, {
|
||||
isMetadataLoading: true,
|
||||
isExtraMetadataLoading: true,
|
||||
expanded: false,
|
||||
})));
|
||||
|
||||
let url = `/superset/table/${query.dbId}/${tableName}/${schemaName}/`;
|
||||
$.get(url, (data) => {
|
||||
const dataPreviewQuery = {
|
||||
@@ -228,36 +283,33 @@ export function addTable(query, tableName, schemaName) {
|
||||
ctas: false,
|
||||
};
|
||||
// Merge table to tables in state
|
||||
dispatch(mergeTable(
|
||||
Object.assign(data, {
|
||||
dbId: query.dbId,
|
||||
queryEditorId: query.id,
|
||||
schema: schemaName,
|
||||
expanded: true,
|
||||
}), dataPreviewQuery)
|
||||
);
|
||||
const newTable = Object.assign({}, table, data, {
|
||||
expanded: true,
|
||||
isMetadataLoading: false,
|
||||
});
|
||||
dispatch(mergeTable(newTable, dataPreviewQuery));
|
||||
// Run query to get preview data for table
|
||||
dispatch(runQuery(dataPreviewQuery));
|
||||
})
|
||||
.fail(() => {
|
||||
dispatch(
|
||||
addAlert({
|
||||
msg: 'Error occurred while fetching metadata',
|
||||
bsStyle: 'danger',
|
||||
})
|
||||
);
|
||||
const newTable = Object.assign({}, table, {
|
||||
isMetadataLoading: false,
|
||||
});
|
||||
dispatch(mergeTable(newTable));
|
||||
notify.error(t('Error occurred while fetching table metadata'));
|
||||
});
|
||||
|
||||
url = `/superset/extra_table_metadata/${query.dbId}/${tableName}/${schemaName}/`;
|
||||
$.get(url, (data) => {
|
||||
const table = {
|
||||
dbId: query.dbId,
|
||||
queryEditorId: query.id,
|
||||
schema: schemaName,
|
||||
name: tableName,
|
||||
};
|
||||
Object.assign(table, data);
|
||||
table = Object.assign({}, table, data, { isExtraMetadataLoading: false });
|
||||
dispatch(mergeTable(table));
|
||||
})
|
||||
.fail(() => {
|
||||
const newTable = Object.assign({}, table, {
|
||||
isExtraMetadataLoading: false,
|
||||
});
|
||||
dispatch(mergeTable(newTable));
|
||||
notify.error(t('Error occurred while fetching table metadata'));
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -299,6 +351,10 @@ export function refreshQueries(alteredQueries) {
|
||||
return { type: REFRESH_QUERIES, alteredQueries };
|
||||
}
|
||||
|
||||
export function persistEditorHeight(queryEditor, currentHeight) {
|
||||
return { type: QUERY_EDITOR_PERSIST_HEIGHT, queryEditor, currentHeight };
|
||||
}
|
||||
|
||||
export function popStoredQuery(urlId) {
|
||||
return function (dispatch) {
|
||||
$.ajax({
|
||||
@@ -307,7 +363,7 @@ export function popStoredQuery(urlId) {
|
||||
success: (data) => {
|
||||
const newQuery = JSON.parse(data);
|
||||
const queryEditorProps = {
|
||||
title: newQuery.title ? newQuery.title : 'shared query',
|
||||
title: newQuery.title ? newQuery.title : t('shared query'),
|
||||
dbId: newQuery.dbId ? parseInt(newQuery.dbId, 10) : null,
|
||||
schema: newQuery.schema ? newQuery.schema : null,
|
||||
autorun: newQuery.autorun ? newQuery.autorun : false,
|
||||
@@ -315,6 +371,62 @@ export function popStoredQuery(urlId) {
|
||||
};
|
||||
dispatch(addQueryEditor(queryEditorProps));
|
||||
},
|
||||
error: () => notify.error(t('The query couldn\'t be loaded')),
|
||||
});
|
||||
};
|
||||
}
|
||||
export function popSavedQuery(saveQueryId) {
|
||||
return function (dispatch) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: `/savedqueryviewapi/api/get/${saveQueryId}`,
|
||||
success: (data) => {
|
||||
const sq = data.result;
|
||||
const queryEditorProps = {
|
||||
title: sq.label,
|
||||
dbId: sq.db_id ? parseInt(sq.db_id, 10) : null,
|
||||
schema: sq.schema,
|
||||
autorun: false,
|
||||
sql: sq.sql,
|
||||
};
|
||||
dispatch(addQueryEditor(queryEditorProps));
|
||||
},
|
||||
error: () => notify.error(t('The query couldn\'t be loaded')),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function createDatasourceStarted() {
|
||||
return { type: CREATE_DATASOURCE_STARTED };
|
||||
}
|
||||
export function createDatasourceSuccess(response) {
|
||||
const data = JSON.parse(response);
|
||||
const datasource = `${data.table_id}__table`;
|
||||
return { type: CREATE_DATASOURCE_SUCCESS, datasource };
|
||||
}
|
||||
export function createDatasourceFailed(err) {
|
||||
return { type: CREATE_DATASOURCE_FAILED, err };
|
||||
}
|
||||
|
||||
export function createDatasource(vizOptions, context) {
|
||||
return (dispatch) => {
|
||||
dispatch(createDatasourceStarted());
|
||||
|
||||
return $.ajax({
|
||||
type: 'POST',
|
||||
url: '/superset/sqllab_viz/',
|
||||
async: false,
|
||||
data: {
|
||||
data: JSON.stringify(vizOptions),
|
||||
},
|
||||
context,
|
||||
dataType: 'json',
|
||||
success: (resp) => {
|
||||
dispatch(createDatasourceSuccess(resp));
|
||||
},
|
||||
error: () => {
|
||||
dispatch(createDatasourceFailed(t('An error occurred while creating the data source')));
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import AceEditor from 'react-ace';
|
||||
import 'brace/mode/sql';
|
||||
import 'brace/theme/github';
|
||||
@@ -8,13 +9,30 @@ import { areArraysShallowEqual } from '../../reduxUtils';
|
||||
|
||||
const langTools = ace.acequire('ace/ext/language_tools');
|
||||
|
||||
const keywords = (
|
||||
'SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|AND|OR|GROUP|BY|ORDER|LIMIT|OFFSET|HAVING|AS|CASE|' +
|
||||
'WHEN|ELSE|END|TYPE|LEFT|RIGHT|JOIN|ON|OUTER|DESC|ASC|UNION|CREATE|TABLE|PRIMARY|KEY|IF|' +
|
||||
'FOREIGN|NOT|REFERENCES|DEFAULT|NULL|INNER|CROSS|NATURAL|DATABASE|DROP|GRANT'
|
||||
);
|
||||
|
||||
const dataTypes = (
|
||||
'INT|NUMERIC|DECIMAL|DATE|VARCHAR|CHAR|BIGINT|FLOAT|DOUBLE|BIT|BINARY|TEXT|SET|TIMESTAMP|' +
|
||||
'MONEY|REAL|NUMBER|INTEGER'
|
||||
);
|
||||
|
||||
const sqlKeywords = [].concat(keywords.split('|'), dataTypes.split('|'));
|
||||
const sqlWords = sqlKeywords.map(s => ({
|
||||
name: s, value: s, score: 60, meta: 'sql',
|
||||
}));
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
onBlur: React.PropTypes.func,
|
||||
onAltEnter: React.PropTypes.func,
|
||||
sql: React.PropTypes.string.isRequired,
|
||||
tables: React.PropTypes.array,
|
||||
queryEditor: React.PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
onBlur: PropTypes.func,
|
||||
onAltEnter: PropTypes.func,
|
||||
sql: PropTypes.string.isRequired,
|
||||
tables: PropTypes.array,
|
||||
queryEditor: PropTypes.object.isRequired,
|
||||
height: PropTypes.string,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@@ -28,6 +46,7 @@ class AceEditorWrapper extends React.PureComponent {
|
||||
super(props);
|
||||
this.state = {
|
||||
sql: props.sql,
|
||||
selectedText: '',
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
@@ -43,54 +62,63 @@ class AceEditorWrapper extends React.PureComponent {
|
||||
this.setState({ sql: nextProps.sql });
|
||||
}
|
||||
}
|
||||
textChange(text) {
|
||||
this.setState({ sql: text });
|
||||
}
|
||||
onBlur() {
|
||||
this.props.onBlur(this.state.sql);
|
||||
}
|
||||
getCompletions(aceEditor, session, pos, prefix, callback) {
|
||||
callback(null, this.state.words);
|
||||
onAltEnter() {
|
||||
this.props.onBlur(this.state.sql);
|
||||
this.props.onAltEnter();
|
||||
}
|
||||
onEditorLoad(editor) {
|
||||
editor.commands.addCommand({
|
||||
name: 'runQuery',
|
||||
bindKey: { win: 'Alt-enter', mac: 'Alt-enter' },
|
||||
exec: () => {
|
||||
this.props.onAltEnter();
|
||||
this.onAltEnter();
|
||||
},
|
||||
});
|
||||
editor.$blockScrolling = Infinity; // eslint-disable-line no-param-reassign
|
||||
editor.selection.on('changeSelection', () => {
|
||||
this.props.actions.queryEditorSetSelectedText(
|
||||
this.props.queryEditor, editor.getSelectedText());
|
||||
const selectedText = editor.getSelectedText();
|
||||
// Backspace trigger 1 character selection, ignoring
|
||||
if (selectedText !== this.state.selectedText && selectedText.length !== 1) {
|
||||
this.setState({ selectedText });
|
||||
this.props.actions.queryEditorSetSelectedText(
|
||||
this.props.queryEditor, selectedText);
|
||||
}
|
||||
});
|
||||
}
|
||||
getCompletions(aceEditor, session, pos, prefix, callback) {
|
||||
callback(null, this.state.words);
|
||||
}
|
||||
setAutoCompleter(props) {
|
||||
// Loading table and column names as auto-completable words
|
||||
let words = [];
|
||||
const columns = {};
|
||||
const tables = props.tables || [];
|
||||
tables.forEach(t => {
|
||||
tables.forEach((t) => {
|
||||
words.push({ name: t.name, value: t.name, score: 55, meta: 'table' });
|
||||
const cols = t.columns || [];
|
||||
cols.forEach(col => {
|
||||
cols.forEach((col) => {
|
||||
columns[col.name] = null; // using an object as a unique set
|
||||
});
|
||||
});
|
||||
words = words.concat(Object.keys(columns).map(col => (
|
||||
{ name: col, value: col, score: 50, meta: 'column' }
|
||||
)));
|
||||
)), sqlWords);
|
||||
|
||||
this.setState({ words }, () => {
|
||||
const completer = {
|
||||
getCompletions: this.getCompletions.bind(this),
|
||||
};
|
||||
if (langTools) {
|
||||
langTools.setCompleters([completer, langTools.keyWordCompleter]);
|
||||
langTools.setCompleters([completer]);
|
||||
}
|
||||
});
|
||||
}
|
||||
textChange(text) {
|
||||
this.setState({ sql: text });
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<AceEditor
|
||||
@@ -98,10 +126,8 @@ class AceEditorWrapper extends React.PureComponent {
|
||||
theme="github"
|
||||
onLoad={this.onEditorLoad.bind(this)}
|
||||
onBlur={this.onBlur.bind(this)}
|
||||
minLines={8}
|
||||
maxLines={30}
|
||||
height={this.props.height}
|
||||
onChange={this.textChange.bind(this)}
|
||||
height="200px"
|
||||
width="100%"
|
||||
editorProps={{ $blockScrolling: true }}
|
||||
enableLiveAutocompletion
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Alert } from 'react-bootstrap';
|
||||
|
||||
class Alerts extends React.PureComponent {
|
||||
removeAlert(alert) {
|
||||
this.props.actions.removeAlert(alert);
|
||||
}
|
||||
render() {
|
||||
const alerts = this.props.alerts.map((alert) =>
|
||||
<Alert
|
||||
key={alert.id}
|
||||
bsStyle={alert.bsStyle}
|
||||
style={{ width: '500px', textAlign: 'midddle', margin: '10px auto' }}
|
||||
>
|
||||
{alert.msg}
|
||||
<i
|
||||
className="fa fa-close pull-right"
|
||||
onClick={this.removeAlert.bind(this, alert)}
|
||||
style={{ cursor: 'pointer' }}
|
||||
/>
|
||||
</Alert>
|
||||
);
|
||||
return (
|
||||
<div>{alerts}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Alerts.propTypes = {
|
||||
alerts: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
};
|
||||
|
||||
export default Alerts;
|
||||
@@ -1,21 +1,22 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
import * as Actions from '../actions';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import TabbedSqlEditors from './TabbedSqlEditors';
|
||||
import QueryAutoRefresh from './QueryAutoRefresh';
|
||||
import QuerySearch from './QuerySearch';
|
||||
import Alerts from './Alerts';
|
||||
import AlertsWrapper from '../../components/AlertsWrapper';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
const $ = window.$ = require('jquery');
|
||||
|
||||
class App extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hash: window.location.hash,
|
||||
contentHeight: this.getHeight(),
|
||||
contentHeight: '0px',
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
@@ -28,20 +29,25 @@ class App extends React.PureComponent {
|
||||
window.removeEventListener('hashchange', this.onHashChanged.bind(this));
|
||||
window.removeEventListener('resize', this.handleResize.bind(this));
|
||||
}
|
||||
onHashChanged() {
|
||||
this.setState({ hash: window.location.hash });
|
||||
}
|
||||
getHeight() {
|
||||
const navHeight = 90;
|
||||
const headerHeight = $('.nav-tabs').outerHeight() ?
|
||||
$('.nav-tabs').outerHeight() : $('#search-header').outerHeight();
|
||||
const warningHeight = $('#navbar-warning').outerHeight();
|
||||
const alertHeight = $('#sqllab-alerts').outerHeight();
|
||||
const warningEl = $('#navbar-warning');
|
||||
const navTabsEl = $('.nav-tabs');
|
||||
const searchHeaderEl = $('#search-header');
|
||||
const alertEl = $('#sqllab-alerts');
|
||||
const headerNavEl = $('header .navbar');
|
||||
const navHeight = headerNavEl.outerHeight() + parseInt(headerNavEl.css('marginBottom'), 10);
|
||||
const searchHeaderHeight = searchHeaderEl.outerHeight() + parseInt(searchHeaderEl.css('marginBottom'), 10);
|
||||
const headerHeight = navTabsEl.outerHeight() ? navTabsEl.outerHeight() : searchHeaderHeight;
|
||||
const warningHeight = warningEl.length > 0 ? warningEl.outerHeight() : 0;
|
||||
const alertHeight = alertEl.length > 0 ? alertEl.outerHeight() : 0;
|
||||
return `${window.innerHeight - navHeight - headerHeight - warningHeight - alertHeight}px`;
|
||||
}
|
||||
handleResize() {
|
||||
this.setState({ contentHeight: this.getHeight() });
|
||||
}
|
||||
onHashChanged() {
|
||||
this.setState({ hash: window.location.hash });
|
||||
}
|
||||
render() {
|
||||
let content;
|
||||
if (this.state.hash) {
|
||||
@@ -64,7 +70,7 @@ class App extends React.PureComponent {
|
||||
}
|
||||
return (
|
||||
<div className="App SqlLab">
|
||||
<Alerts id="sqllab-alerts" alerts={this.props.alerts} actions={this.props.actions} />
|
||||
<AlertsWrapper initMessages={this.props.initMessages} />
|
||||
<div className="container-fluid">
|
||||
{content}
|
||||
</div>
|
||||
@@ -74,13 +80,15 @@ class App extends React.PureComponent {
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
alerts: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
alerts: PropTypes.array,
|
||||
actions: PropTypes.object,
|
||||
initMessages: PropTypes.array,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
alerts: state.alerts,
|
||||
initMessages: state.flash_messages,
|
||||
};
|
||||
}
|
||||
function mapDispatchToProps(dispatch) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||
|
||||
const propTypes = {
|
||||
column: React.PropTypes.object.isRequired,
|
||||
column: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const iconMap = {
|
||||
@@ -17,43 +18,39 @@ const tooltipTitleMap = {
|
||||
index: 'Index',
|
||||
};
|
||||
|
||||
class ColumnElement extends React.PureComponent {
|
||||
render() {
|
||||
const col = this.props.column;
|
||||
let name = col.name;
|
||||
let icons;
|
||||
if (col.keys && col.keys.length > 0) {
|
||||
name = <strong>{col.name}</strong>;
|
||||
icons = col.keys.map((key, i) => (
|
||||
<span key={i} className="ColumnElement">
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
overlay={
|
||||
<Tooltip id="idx-json" bsSize="lg">
|
||||
<strong>{tooltipTitleMap[key.type]}</strong>
|
||||
<hr />
|
||||
<pre className="text-small">
|
||||
{JSON.stringify(key, null, ' ')}
|
||||
</pre>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<i className={`fa text-muted m-l-2 ${iconMap[key.type]}`} />
|
||||
</OverlayTrigger>
|
||||
</span>
|
||||
));
|
||||
}
|
||||
return (
|
||||
<div className="clearfix table-column">
|
||||
<div className="pull-left m-l-10 col-name">
|
||||
{name}{icons}
|
||||
</div>
|
||||
<div className="pull-right text-muted">
|
||||
<small> {col.type}</small>
|
||||
</div>
|
||||
</div>);
|
||||
export default function ColumnElement(props) {
|
||||
const col = props.column;
|
||||
let name = col.name;
|
||||
let icons;
|
||||
if (col.keys && col.keys.length > 0) {
|
||||
name = <strong>{col.name}</strong>;
|
||||
icons = col.keys.map((key, i) => (
|
||||
<span key={i} className="ColumnElement">
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
overlay={
|
||||
<Tooltip id="idx-json" bsSize="lg">
|
||||
<strong>{tooltipTitleMap[key.type]}</strong>
|
||||
<hr />
|
||||
<pre className="text-small">
|
||||
{JSON.stringify(key, null, ' ')}
|
||||
</pre>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<i className={`fa text-muted m-l-2 ${iconMap[key.type]}`} />
|
||||
</OverlayTrigger>
|
||||
</span>
|
||||
));
|
||||
}
|
||||
return (
|
||||
<div className="clearfix table-column">
|
||||
<div className="pull-left m-l-10 col-name">
|
||||
{name}{icons}
|
||||
</div>
|
||||
<div className="pull-right text-muted">
|
||||
<small> {col.type}</small>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
ColumnElement.propTypes = propTypes;
|
||||
|
||||
export default ColumnElement;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CopyToClipboard from '../../components/CopyToClipboard';
|
||||
import { storeQuery } from '../../../utils/common';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
queryEditor: React.PropTypes.object.isRequired,
|
||||
queryEditor: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default class CopyQueryTabUrl extends React.PureComponent {
|
||||
@@ -25,10 +27,10 @@ export default class CopyQueryTabUrl extends React.PureComponent {
|
||||
inMenu
|
||||
copyNode={(
|
||||
<div>
|
||||
<i className="fa fa-clipboard" /> <span>share query</span>
|
||||
<i className="fa fa-clipboard" /> <span>{t('share query')}</span>
|
||||
</div>
|
||||
)}
|
||||
tooltipText="copy URL to clipboard"
|
||||
tooltipText={t('copy URL to clipboard')}
|
||||
shouldShowText={false}
|
||||
getText={this.getUrl.bind(this)}
|
||||
/>
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import * as Actions from '../actions';
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Modal } from 'react-bootstrap';
|
||||
|
||||
import ResultSet from './ResultSet';
|
||||
|
||||
const propTypes = {
|
||||
queries: React.PropTypes.object,
|
||||
actions: React.PropTypes.object,
|
||||
showDataPreviewModal: React.PropTypes.bool,
|
||||
dataPreviewQueryId: React.PropTypes.string,
|
||||
};
|
||||
|
||||
class DataPreviewModal extends React.PureComponent {
|
||||
hide() {
|
||||
this.props.actions.hideDataPreview();
|
||||
}
|
||||
render() {
|
||||
if (this.props.showDataPreviewModal && this.props.dataPreviewQueryId) {
|
||||
const query = this.props.queries[this.props.dataPreviewQueryId];
|
||||
return (
|
||||
<Modal
|
||||
show={this.props.showDataPreviewModal}
|
||||
onHide={this.hide.bind(this)}
|
||||
bsStyle="lg"
|
||||
>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>
|
||||
Data preview for <strong>{query.tableName}</strong>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<ResultSet query={query} visualize={false} csv={false} actions={this.props.actions} />
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
DataPreviewModal.propTypes = propTypes;
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
queries: state.queries,
|
||||
showDataPreviewModal: state.showDataPreviewModal,
|
||||
dataPreviewQueryId: state.dataPreviewQueryId,
|
||||
};
|
||||
}
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DataPreviewModal);
|
||||
@@ -1,7 +1,14 @@
|
||||
import React from 'react';
|
||||
import SyntaxHighlighter from 'react-syntax-highlighter';
|
||||
import { github } from 'react-syntax-highlighter/dist/styles';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import SyntaxHighlighter, { registerLanguage } from 'react-syntax-highlighter/dist/light';
|
||||
import sql from 'react-syntax-highlighter/dist/languages/sql';
|
||||
import github from 'react-syntax-highlighter/dist/styles/github';
|
||||
|
||||
import ModalTrigger from '../../components/ModalTrigger';
|
||||
import { t } from '../../locales';
|
||||
|
||||
registerLanguage('sql', sql);
|
||||
|
||||
const defaultProps = {
|
||||
maxWidth: 50,
|
||||
@@ -10,11 +17,11 @@ const defaultProps = {
|
||||
};
|
||||
|
||||
const propTypes = {
|
||||
sql: React.PropTypes.string.isRequired,
|
||||
rawSql: React.PropTypes.string,
|
||||
maxWidth: React.PropTypes.number,
|
||||
maxLines: React.PropTypes.number,
|
||||
shrink: React.PropTypes.bool,
|
||||
sql: PropTypes.string.isRequired,
|
||||
rawSql: PropTypes.string,
|
||||
maxWidth: PropTypes.number,
|
||||
maxLines: PropTypes.number,
|
||||
shrink: PropTypes.bool,
|
||||
};
|
||||
|
||||
class HighlightedSql extends React.Component {
|
||||
@@ -25,38 +32,35 @@ class HighlightedSql extends React.Component {
|
||||
};
|
||||
}
|
||||
shrinkSql() {
|
||||
const props = this.props;
|
||||
const sql = props.sql || '';
|
||||
let lines = sql.split('\n');
|
||||
if (lines.length >= props.maxLines) {
|
||||
lines = lines.slice(0, props.maxLines);
|
||||
const ssql = this.props.sql || '';
|
||||
let lines = ssql.split('\n');
|
||||
if (lines.length >= this.props.maxLines) {
|
||||
lines = lines.slice(0, this.props.maxLines);
|
||||
lines.push('{...}');
|
||||
}
|
||||
return lines.map((line) => {
|
||||
if (line.length > props.maxWidth) {
|
||||
return line.slice(0, props.maxWidth) + '{...}';
|
||||
if (line.length > this.props.maxWidth) {
|
||||
return line.slice(0, this.props.maxWidth) + '{...}';
|
||||
}
|
||||
return line;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
triggerNode() {
|
||||
const props = this.props;
|
||||
let shownSql = props.shrink ? this.shrinkSql(props.sql) : props.sql;
|
||||
const shownSql = this.props.shrink ? this.shrinkSql(this.props.sql) : this.props.sql;
|
||||
return (
|
||||
<SyntaxHighlighter language="sql" style={github}>
|
||||
{shownSql}
|
||||
</SyntaxHighlighter>);
|
||||
}
|
||||
generateModal() {
|
||||
const props = this.props;
|
||||
let rawSql;
|
||||
if (props.rawSql && props.rawSql !== this.props.sql) {
|
||||
if (this.props.rawSql && this.props.rawSql !== this.props.sql) {
|
||||
rawSql = (
|
||||
<div>
|
||||
<h4>Raw SQL</h4>
|
||||
<h4>{t('Raw SQL')}</h4>
|
||||
<SyntaxHighlighter language="sql" style={github}>
|
||||
{props.rawSql}
|
||||
{this.props.rawSql}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
);
|
||||
@@ -64,7 +68,7 @@ class HighlightedSql extends React.Component {
|
||||
this.setState({
|
||||
modalBody: (
|
||||
<div>
|
||||
<h4>Source SQL</h4>
|
||||
<h4>{t('Source SQL')}</h4>
|
||||
<SyntaxHighlighter language="sql" style={github}>
|
||||
{this.props.sql}
|
||||
</SyntaxHighlighter>
|
||||
@@ -76,7 +80,7 @@ class HighlightedSql extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ModalTrigger
|
||||
modalTitle="SQL"
|
||||
modalTitle={t('SQL')}
|
||||
triggerNode={this.triggerNode()}
|
||||
modalBody={this.state.modalBody}
|
||||
beforeOpen={this.generateModal.bind(this)}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||
|
||||
const propTypes = {
|
||||
children: React.PropTypes.node,
|
||||
className: React.PropTypes.string,
|
||||
href: React.PropTypes.string,
|
||||
onClick: React.PropTypes.func,
|
||||
placement: React.PropTypes.string,
|
||||
style: React.PropTypes.object,
|
||||
tooltip: React.PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
href: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
placement: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
tooltip: PropTypes.string,
|
||||
};
|
||||
const defaultProps = {
|
||||
className: '',
|
||||
@@ -22,7 +23,7 @@ const defaultProps = {
|
||||
|
||||
class Link extends React.PureComponent {
|
||||
render() {
|
||||
let tooltip = (
|
||||
const tooltip = (
|
||||
<Tooltip id="tooltip">
|
||||
{this.props.tooltip}
|
||||
</Tooltip>
|
||||
@@ -34,7 +35,7 @@ class Link extends React.PureComponent {
|
||||
style={this.props.style}
|
||||
className={'Link ' + this.props.className}
|
||||
>
|
||||
{this.props.children}
|
||||
{this.props.children}
|
||||
</a>
|
||||
);
|
||||
if (this.props.tooltip) {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
const $ = require('jquery');
|
||||
const QUERY_UPDATE_FREQ = 1000;
|
||||
|
||||
const QUERY_UPDATE_FREQ = 2000;
|
||||
const QUERY_UPDATE_BUFFER_MS = 5000;
|
||||
|
||||
class QueryAutoRefresh extends React.PureComponent {
|
||||
@@ -14,6 +16,14 @@ class QueryAutoRefresh extends React.PureComponent {
|
||||
componentWillUnmount() {
|
||||
this.stopTimer();
|
||||
}
|
||||
shouldCheckForQueries() {
|
||||
// if there are started or running queries, this method should return true
|
||||
const { queries } = this.props;
|
||||
const queryKeys = Object.keys(queries);
|
||||
const queriesAsArray = queryKeys.map(key => queries[key]);
|
||||
return queriesAsArray.some(q =>
|
||||
['running', 'started', 'pending', 'fetching'].indexOf(q.state) >= 0);
|
||||
}
|
||||
startTimer() {
|
||||
if (!(this.timer)) {
|
||||
this.timer = setInterval(this.stopwatch.bind(this), QUERY_UPDATE_FREQ);
|
||||
@@ -24,32 +34,29 @@ class QueryAutoRefresh extends React.PureComponent {
|
||||
this.timer = null;
|
||||
}
|
||||
stopwatch() {
|
||||
const url = '/superset/queries/' + (this.props.queriesLastUpdate - QUERY_UPDATE_BUFFER_MS);
|
||||
// No updates in case of failure.
|
||||
$.getJSON(url, (data) => {
|
||||
if (Object.keys(data).length > 0) {
|
||||
this.props.actions.refreshQueries(data);
|
||||
}
|
||||
this.props.actions.setNetworkStatus(true);
|
||||
})
|
||||
.fail(() => {
|
||||
this.props.actions.setNetworkStatus(false);
|
||||
});
|
||||
// only poll /superset/queries/ if there are started or running queries
|
||||
if (this.shouldCheckForQueries()) {
|
||||
const url = `/superset/queries/${this.props.queriesLastUpdate - QUERY_UPDATE_BUFFER_MS}`;
|
||||
$.getJSON(url, (data) => {
|
||||
if (Object.keys(data).length > 0) {
|
||||
this.props.actions.refreshQueries(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
QueryAutoRefresh.propTypes = {
|
||||
actions: React.PropTypes.object,
|
||||
queriesLastUpdate: React.PropTypes.number,
|
||||
};
|
||||
QueryAutoRefresh.defaultProps = {
|
||||
// queries: null,
|
||||
queries: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
queriesLastUpdate: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
queries: state.queries,
|
||||
queriesLastUpdate: state.queriesLastUpdate,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
import QueryTable from './QueryTable';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Alert } from 'react-bootstrap';
|
||||
|
||||
import QueryTable from './QueryTable';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
queries: React.PropTypes.array.isRequired,
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
queries: PropTypes.array.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const QueryHistory = (props) => {
|
||||
@@ -23,7 +25,7 @@ const QueryHistory = (props) => {
|
||||
}
|
||||
return (
|
||||
<Alert bsStyle="info">
|
||||
No query history yet...
|
||||
{t('No query history yet...')}
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import Select from 'react-select';
|
||||
import QueryTable from './QueryTable';
|
||||
@@ -7,9 +7,13 @@ import { now, epochTimeXHoursAgo,
|
||||
epochTimeXDaysAgo, epochTimeXYearsAgo } from '../../modules/dates';
|
||||
import { STATUS_OPTIONS, TIME_OPTIONS } from '../constants';
|
||||
import AsyncSelect from '../../components/AsyncSelect';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const $ = window.$ = require('jquery');
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
class QuerySearch extends React.PureComponent {
|
||||
@@ -75,7 +79,7 @@ class QuerySearch extends React.PureComponent {
|
||||
}
|
||||
insertParams(baseUrl, params) {
|
||||
const validParams = params.filter(
|
||||
function (p) { return p !== ''; }
|
||||
function (p) { return p !== ''; },
|
||||
);
|
||||
return baseUrl + '?' + validParams.join('&');
|
||||
}
|
||||
@@ -94,12 +98,12 @@ class QuerySearch extends React.PureComponent {
|
||||
return options;
|
||||
}
|
||||
dbMutator(data) {
|
||||
const options = data.result.map((db) => ({ value: db.id, label: db.database_name }));
|
||||
const options = data.result.map(db => ({ value: db.id, label: db.database_name }));
|
||||
this.props.actions.setDatabases(data.result);
|
||||
if (data.result.length === 0) {
|
||||
this.props.actions.addAlert({
|
||||
bsStyle: 'danger',
|
||||
msg: "It seems you don't have access to any database",
|
||||
msg: t('It seems you don\'t have access to any database'),
|
||||
});
|
||||
}
|
||||
return options;
|
||||
@@ -147,66 +151,65 @@ class QuerySearch extends React.PureComponent {
|
||||
type="text"
|
||||
onChange={this.changeSearch.bind(this)}
|
||||
className="form-control input-sm"
|
||||
placeholder="Search Results"
|
||||
placeholder={t('Search Results')}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-sm-1">
|
||||
<div className="col-sm-4 search-date-filter-container">
|
||||
<Select
|
||||
name="select-from"
|
||||
placeholder="[From]-"
|
||||
options={TIME_OPTIONS.
|
||||
slice(1, TIME_OPTIONS.length).map((t) => ({ value: t, label: t }))}
|
||||
placeholder={t('[From]-')}
|
||||
options={TIME_OPTIONS
|
||||
.slice(1, TIME_OPTIONS.length).map(xt => ({ value: xt, label: xt }))}
|
||||
value={this.state.from}
|
||||
autosize={false}
|
||||
onChange={this.changeFrom.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-sm-1">
|
||||
|
||||
<Select
|
||||
name="select-to"
|
||||
placeholder="[To]-"
|
||||
options={TIME_OPTIONS.map((t) => ({ value: t, label: t }))}
|
||||
placeholder={t('[To]-')}
|
||||
options={TIME_OPTIONS.map(xt => ({ value: xt, label: xt }))}
|
||||
value={this.state.to}
|
||||
autosize={false}
|
||||
onChange={this.changeTo.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-sm-1">
|
||||
|
||||
<Select
|
||||
name="select-status"
|
||||
placeholder="[Query Status]"
|
||||
options={STATUS_OPTIONS.map((s) => ({ value: s, label: s }))}
|
||||
placeholder={t('[Query Status]')}
|
||||
options={STATUS_OPTIONS.map(s => ({ value: s, label: s }))}
|
||||
value={this.state.status}
|
||||
isLoading={false}
|
||||
autosize={false}
|
||||
onChange={this.changeStatus.bind(this)}
|
||||
/>
|
||||
|
||||
<Button bsSize="small" bsStyle="success" onClick={this.refreshQueries.bind(this)}>
|
||||
{t('Search')}
|
||||
</Button>
|
||||
</div>
|
||||
<Button bsSize="small" bsStyle="success" onClick={this.refreshQueries.bind(this)}>
|
||||
Search
|
||||
</Button>
|
||||
</div>
|
||||
{this.state.queriesLoading ?
|
||||
(<img className="loading" alt="Loading..." src="/static/assets/images/loading.gif" />)
|
||||
:
|
||||
(
|
||||
<div
|
||||
style={{ height: this.props.height }}
|
||||
className="scrollbar-container"
|
||||
>
|
||||
<div className="scrollbar-content">
|
||||
<QueryTable
|
||||
columns={[
|
||||
'state', 'db', 'user', 'time',
|
||||
'progress', 'rows', 'sql', 'querylink',
|
||||
]}
|
||||
onUserClicked={this.onUserClicked.bind(this)}
|
||||
onDbClicked={this.onDbClicked.bind(this)}
|
||||
queries={this.state.queriesArray}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
<div className="scrollbar-container">
|
||||
<div
|
||||
className="scrollbar-content"
|
||||
style={{ height: this.props.height }}
|
||||
>
|
||||
<QueryTable
|
||||
columns={[
|
||||
'state', 'db', 'user', 'time',
|
||||
'progress', 'rows', 'sql', 'querylink',
|
||||
]}
|
||||
onUserClicked={this.onUserClicked.bind(this)}
|
||||
onDbClicked={this.onDbClicked.bind(this)}
|
||||
queries={this.state.queriesArray}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Label } from 'react-bootstrap';
|
||||
|
||||
import { STATE_BSSTYLE_MAP } from '../constants';
|
||||
|
||||
const propTypes = {
|
||||
query: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default function QueryStateLabel({ query }) {
|
||||
const bsStyle = STATE_BSSTYLE_MAP[query.state];
|
||||
return (
|
||||
<Label className="m-r-3" bsStyle={bsStyle}>
|
||||
{query.state}
|
||||
</Label>
|
||||
);
|
||||
}
|
||||
QueryStateLabel.propTypes = propTypes;
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import moment from 'moment';
|
||||
import { Table } from 'reactable';
|
||||
@@ -8,16 +9,17 @@ import VisualizeModal from './VisualizeModal';
|
||||
import ResultSet from './ResultSet';
|
||||
import ModalTrigger from '../../components/ModalTrigger';
|
||||
import HighlightedSql from './HighlightedSql';
|
||||
import { STATE_BSSTYLE_MAP } from '../constants';
|
||||
import { fDuration } from '../../modules/dates';
|
||||
import { storeQuery } from '../../../utils/common';
|
||||
import QueryStateLabel from './QueryStateLabel';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
columns: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
queries: React.PropTypes.array,
|
||||
onUserClicked: React.PropTypes.func,
|
||||
onDbClicked: React.PropTypes.func,
|
||||
columns: PropTypes.array,
|
||||
actions: PropTypes.object,
|
||||
queries: PropTypes.array,
|
||||
onUserClicked: PropTypes.func,
|
||||
onDbClicked: PropTypes.func,
|
||||
};
|
||||
const defaultProps = {
|
||||
columns: ['started', 'duration', 'rows'],
|
||||
@@ -44,7 +46,7 @@ class QueryTable extends React.PureComponent {
|
||||
openQuery(dbId, schema, sql) {
|
||||
const newQuery = {
|
||||
dbId,
|
||||
title: 'Untitled Query',
|
||||
title: t('Untitled Query'),
|
||||
schema,
|
||||
sql,
|
||||
};
|
||||
@@ -109,7 +111,7 @@ class QueryTable extends React.PureComponent {
|
||||
className="btn btn-link btn-xs"
|
||||
onClick={this.openQuery.bind(this, q.dbId, q.schema, q.sql)}
|
||||
>
|
||||
<i className="fa fa-external-link" />Open in SQL Editor
|
||||
<i className="fa fa-external-link" />{t('Open in SQL Editor')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
@@ -128,20 +130,22 @@ class QueryTable extends React.PureComponent {
|
||||
bsStyle="info"
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
view results
|
||||
{t('view results')}
|
||||
</Label>
|
||||
)}
|
||||
modalTitle={'Data preview'}
|
||||
modalTitle={t('Data preview')}
|
||||
beforeOpen={this.openAsyncResults.bind(this, query)}
|
||||
onExit={this.clearQueryResults.bind(this, query)}
|
||||
modalBody={<ResultSet showSql query={query} actions={this.props.actions} />}
|
||||
modalBody={
|
||||
<ResultSet showSql query={query} actions={this.props.actions} height={400} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// if query was run using ctas and force_ctas_schema was set
|
||||
// tempTable will have the schema
|
||||
const schemaUsed = q.ctas && q.tempTable && q.tempTable.includes('.') ? '' : q.schema;
|
||||
q.output = [schemaUsed, q.tempTable].filter((v) => (v)).join('.');
|
||||
q.output = [schemaUsed, q.tempTable].filter(v => (v)).join('.');
|
||||
}
|
||||
q.progress = (
|
||||
<ProgressBar
|
||||
@@ -161,9 +165,7 @@ class QueryTable extends React.PureComponent {
|
||||
}
|
||||
q.state = (
|
||||
<div>
|
||||
<span className={'m-r-3 label label-' + STATE_BSSTYLE_MAP[q.state]}>
|
||||
{q.state}
|
||||
</span>
|
||||
<QueryStateLabel query={query} />
|
||||
{errorTooltip}
|
||||
</div>
|
||||
);
|
||||
@@ -171,24 +173,24 @@ class QueryTable extends React.PureComponent {
|
||||
<div style={{ width: '75px' }}>
|
||||
<Link
|
||||
className="fa fa-line-chart m-r-3"
|
||||
tooltip="Visualize the data out of this query"
|
||||
tooltip={t('Visualize the data out of this query')}
|
||||
onClick={this.showVisualizeModal.bind(this, query)}
|
||||
/>
|
||||
<Link
|
||||
className="fa fa-pencil m-r-3"
|
||||
onClick={this.restoreSql.bind(this, query)}
|
||||
tooltip="Overwrite text in editor with a query on this table"
|
||||
tooltip={t('Overwrite text in editor with a query on this table')}
|
||||
placement="top"
|
||||
/>
|
||||
<Link
|
||||
className="fa fa-plus-circle m-r-3"
|
||||
onClick={this.openQueryInNewTab.bind(this, query)}
|
||||
tooltip="Run query in a new tab"
|
||||
tooltip={t('Run query in a new tab')}
|
||||
placement="top"
|
||||
/>
|
||||
<Link
|
||||
className="fa fa-trash m-r-3"
|
||||
tooltip="Remove query from log"
|
||||
tooltip={t('Remove query from log')}
|
||||
onClick={this.removeQuery.bind(this, query)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,41 +1,48 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
|
||||
import { Table } from 'reactable';
|
||||
import shortid from 'shortid';
|
||||
|
||||
import VisualizeModal from './VisualizeModal';
|
||||
import HighlightedSql from './HighlightedSql';
|
||||
import FilterableTable from '../../components/FilterableTable/FilterableTable';
|
||||
import QueryStateLabel from './QueryStateLabel';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object,
|
||||
csv: React.PropTypes.bool,
|
||||
query: React.PropTypes.object,
|
||||
search: React.PropTypes.bool,
|
||||
searchText: React.PropTypes.string,
|
||||
showSql: React.PropTypes.bool,
|
||||
visualize: React.PropTypes.bool,
|
||||
cache: React.PropTypes.bool,
|
||||
actions: PropTypes.object,
|
||||
csv: PropTypes.bool,
|
||||
query: PropTypes.object,
|
||||
search: PropTypes.bool,
|
||||
showSql: PropTypes.bool,
|
||||
visualize: PropTypes.bool,
|
||||
cache: PropTypes.bool,
|
||||
height: PropTypes.number.isRequired,
|
||||
};
|
||||
const defaultProps = {
|
||||
search: true,
|
||||
visualize: true,
|
||||
showSql: false,
|
||||
csv: true,
|
||||
searchText: '',
|
||||
actions: {},
|
||||
cache: false,
|
||||
};
|
||||
|
||||
const SEARCH_HEIGHT = 46;
|
||||
|
||||
class ResultSet extends React.PureComponent {
|
||||
export default class ResultSet extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
searchText: '',
|
||||
showModal: false,
|
||||
data: [],
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
// only do this the first time the component is rendered/mounted
|
||||
this.reRunQueryIfSessionTimeoutErrorOnMount();
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// when new results comes in, save them locally and clear in store
|
||||
if (this.props.cache && (!nextProps.query.cached)
|
||||
@@ -43,7 +50,7 @@ class ResultSet extends React.PureComponent {
|
||||
&& nextProps.query.results.data.length > 0) {
|
||||
this.setState(
|
||||
{ data: nextProps.query.results.data },
|
||||
this.clearQueryResults(nextProps.query)
|
||||
this.clearQueryResults(nextProps.query),
|
||||
);
|
||||
}
|
||||
if (nextProps.query.resultsKey
|
||||
@@ -57,7 +64,7 @@ class ResultSet extends React.PureComponent {
|
||||
if (this.props.csv) {
|
||||
csvButton = (
|
||||
<Button bsSize="small" href={'/superset/csv/' + this.props.query.id}>
|
||||
<i className="fa fa-file-text-o" /> .CSV
|
||||
<i className="fa fa-file-text-o" /> {t('.CSV')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -68,7 +75,7 @@ class ResultSet extends React.PureComponent {
|
||||
bsSize="small"
|
||||
onClick={this.showModal.bind(this)}
|
||||
>
|
||||
<i className="fa fa-line-chart m-l-1" /> Visualize
|
||||
<i className="fa fa-line-chart m-l-1" /> {t('Visualize')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -79,7 +86,7 @@ class ResultSet extends React.PureComponent {
|
||||
type="text"
|
||||
onChange={this.changeSearch.bind(this)}
|
||||
className="form-control input-sm"
|
||||
placeholder="Search Results"
|
||||
placeholder={t('Search Results')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -129,60 +136,49 @@ class ResultSet extends React.PureComponent {
|
||||
reFetchQueryResults(query) {
|
||||
this.props.actions.reFetchQueryResults(query);
|
||||
}
|
||||
reRunQueryIfSessionTimeoutErrorOnMount() {
|
||||
const { query } = this.props;
|
||||
if (query.errorMessage && query.errorMessage.indexOf('session timed out') > 0) {
|
||||
this.props.actions.runQuery(query, true);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const query = this.props.query;
|
||||
const results = query.results;
|
||||
let data;
|
||||
if (this.props.cache && query.cached) {
|
||||
data = this.state.data;
|
||||
} else {
|
||||
data = results ? results.data : [];
|
||||
}
|
||||
|
||||
const height = this.props.search ? this.props.height - SEARCH_HEIGHT : this.props.height;
|
||||
let sql;
|
||||
|
||||
if (query.state === 'stopped') {
|
||||
return <Alert bsStyle="warning">Query was stopped</Alert>;
|
||||
}
|
||||
|
||||
if (this.props.showSql) {
|
||||
sql = <HighlightedSql sql={query.sql} />;
|
||||
}
|
||||
if (['running', 'pending', 'fetching'].indexOf(query.state) > -1) {
|
||||
let progressBar;
|
||||
if (query.progress > 0 && query.state === 'running') {
|
||||
progressBar = (
|
||||
<ProgressBar
|
||||
striped
|
||||
now={query.progress}
|
||||
label={`${query.progress}%`}
|
||||
/>);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<img className="loading" alt="Loading..." src="/static/assets/images/loading.gif" />
|
||||
{progressBar}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (query.state === 'stopped') {
|
||||
return <Alert bsStyle="warning">Query was stopped</Alert>;
|
||||
} else if (query.state === 'failed') {
|
||||
return <Alert bsStyle="danger">{query.errorMessage}</Alert>;
|
||||
} else if (query.state === 'success' && query.ctas) {
|
||||
return (
|
||||
<div>
|
||||
<Alert bsStyle="info">
|
||||
Table [<strong>{query.tempTable}</strong>] was
|
||||
created
|
||||
{t('Table')} [<strong>{query.tempTable}</strong>] {t('was ' +
|
||||
'created')}
|
||||
<Button
|
||||
bsSize="small"
|
||||
className="m-r-5"
|
||||
onClick={this.popSelectStar.bind(this)}
|
||||
>
|
||||
Query in a new tab
|
||||
{t('Query in a new tab')}
|
||||
</Button>
|
||||
</Alert>
|
||||
</div>);
|
||||
} else if (query.state === 'success') {
|
||||
if (results && data && data.length > 0) {
|
||||
const results = query.results;
|
||||
let data;
|
||||
if (this.props.cache && query.cached) {
|
||||
data = this.state.data;
|
||||
} else if (results && results.data) {
|
||||
data = results.data;
|
||||
}
|
||||
if (data && data.length > 0) {
|
||||
return (
|
||||
<div>
|
||||
<VisualizeModal
|
||||
@@ -192,30 +188,16 @@ class ResultSet extends React.PureComponent {
|
||||
/>
|
||||
{this.getControls.bind(this)()}
|
||||
{sql}
|
||||
<div className="ResultSet">
|
||||
<Table
|
||||
data={data.map(function (row) {
|
||||
const newRow = {};
|
||||
for (const k in row) {
|
||||
const val = row[k];
|
||||
if (typeof(val) === 'string') {
|
||||
newRow[k] = val;
|
||||
} else {
|
||||
newRow[k] = JSON.stringify(val);
|
||||
}
|
||||
}
|
||||
return newRow;
|
||||
})}
|
||||
columns={results.columns.map((col) => col.name)}
|
||||
sortable
|
||||
className="table table-condensed table-bordered"
|
||||
filterBy={this.state.searchText}
|
||||
filterable={results.columns.map((c) => c.name)}
|
||||
hideFilterInput
|
||||
/>
|
||||
</div>
|
||||
<FilterableTable
|
||||
data={data}
|
||||
orderedColumnKeys={results.columns.map(col => col.name)}
|
||||
height={height}
|
||||
filterText={this.state.searchText}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (data && data.length === 0) {
|
||||
return <Alert bsStyle="warning">The query returned no data</Alert>;
|
||||
}
|
||||
}
|
||||
if (query.cached) {
|
||||
@@ -225,14 +207,41 @@ class ResultSet extends React.PureComponent {
|
||||
bsStyle="primary"
|
||||
onClick={this.reFetchQueryResults.bind(this, query)}
|
||||
>
|
||||
Fetch data preview
|
||||
{t('Fetch data preview')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return <Alert bsStyle="warning">The query returned no data</Alert>;
|
||||
let progressBar;
|
||||
let trackingUrl;
|
||||
if (query.progress > 0 && query.state === 'running') {
|
||||
progressBar = (
|
||||
<ProgressBar
|
||||
striped
|
||||
now={query.progress}
|
||||
label={`${query.progress}%`}
|
||||
/>);
|
||||
}
|
||||
if (query.trackingUrl) {
|
||||
trackingUrl = (
|
||||
<Button
|
||||
bsSize="small"
|
||||
onClick={() => { window.open(query.trackingUrl); }}
|
||||
>
|
||||
{t('Track Job')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<img className="loading" alt={t('Loading...')} src="/static/assets/images/loading.gif" />
|
||||
<QueryStateLabel query={query} />
|
||||
{progressBar}
|
||||
<div>
|
||||
{trackingUrl}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
ResultSet.propTypes = propTypes;
|
||||
ResultSet.defaultProps = defaultProps;
|
||||
|
||||
export default ResultSet;
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Button from '../../components/Button';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
allowAsync: PropTypes.bool.isRequired,
|
||||
dbId: PropTypes.number.isRequired,
|
||||
queryState: PropTypes.string.isRequired,
|
||||
dbId: PropTypes.number,
|
||||
queryState: PropTypes.string,
|
||||
runQuery: PropTypes.func.isRequired,
|
||||
selectedText: PropTypes.string,
|
||||
stopQuery: PropTypes.func.isRequired,
|
||||
};
|
||||
const defaultProps = {
|
||||
allowAsync: false,
|
||||
};
|
||||
|
||||
export default function RunQueryActionButton(props) {
|
||||
const runBtnText = props.selectedText ? 'Run Selected Query' : 'Run Query';
|
||||
const runBtnText = props.selectedText ? t('Run Selected Query') : t('Run Query');
|
||||
const btnStyle = props.selectedText ? 'warning' : 'primary';
|
||||
const shouldShowStopBtn = ['running', 'pending'].indexOf(props.queryState) > -1;
|
||||
const asyncToolTip = 'Run query asynchronously';
|
||||
|
||||
const commonBtnProps = {
|
||||
bsSize: 'small',
|
||||
@@ -27,8 +31,9 @@ export default function RunQueryActionButton(props) {
|
||||
{...commonBtnProps}
|
||||
onClick={() => props.runQuery(false)}
|
||||
key="run-btn"
|
||||
tooltip={t('Run query synchronously')}
|
||||
>
|
||||
<i className="fa fa-table" /> {runBtnText}
|
||||
<i className="fa fa-refresh" /> {runBtnText}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -37,7 +42,7 @@ export default function RunQueryActionButton(props) {
|
||||
{...commonBtnProps}
|
||||
onClick={() => props.runQuery(true)}
|
||||
key="run-async-btn"
|
||||
tooltip={asyncToolTip}
|
||||
tooltip={t('Run query asynchronously')}
|
||||
>
|
||||
<i className="fa fa-table" /> {runBtnText}
|
||||
</Button>
|
||||
@@ -48,7 +53,7 @@ export default function RunQueryActionButton(props) {
|
||||
{...commonBtnProps}
|
||||
onClick={props.stopQuery}
|
||||
>
|
||||
<i className="fa fa-stop" /> Stop
|
||||
<i className="fa fa-stop" /> {t('Stop')}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -60,12 +65,8 @@ export default function RunQueryActionButton(props) {
|
||||
} else {
|
||||
button = syncBtn;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="inline m-r-5 pull-left">
|
||||
{button}
|
||||
</div>
|
||||
);
|
||||
return button;
|
||||
}
|
||||
|
||||
RunQueryActionButton.propTypes = propTypes;
|
||||
RunQueryActionButton.defaultProps = defaultProps;
|
||||
|
||||
131
superset/assets/javascripts/SqlLab/components/SaveQuery.jsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormControl, FormGroup, Overlay, Popover, Row, Col } from 'react-bootstrap';
|
||||
import Button from '../../components/Button';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
defaultLabel: PropTypes.string,
|
||||
sql: PropTypes.string,
|
||||
schema: PropTypes.string,
|
||||
dbId: PropTypes.number,
|
||||
animation: PropTypes.bool,
|
||||
onSave: PropTypes.func,
|
||||
};
|
||||
const defaultProps = {
|
||||
defaultLabel: t('Undefined'),
|
||||
animation: true,
|
||||
onSave: () => {},
|
||||
};
|
||||
|
||||
class SaveQuery extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
description: '',
|
||||
label: props.defaultLabel,
|
||||
showSave: false,
|
||||
};
|
||||
this.toggleSave = this.toggleSave.bind(this);
|
||||
this.onSave = this.onSave.bind(this);
|
||||
this.onCancel = this.onCancel.bind(this);
|
||||
this.onLabelChange = this.onLabelChange.bind(this);
|
||||
this.onDescriptionChange = this.onDescriptionChange.bind(this);
|
||||
}
|
||||
onSave() {
|
||||
const query = {
|
||||
label: this.state.label,
|
||||
description: this.state.description,
|
||||
db_id: this.props.dbId,
|
||||
schema: this.props.schema,
|
||||
sql: this.props.sql,
|
||||
};
|
||||
this.props.onSave(query);
|
||||
this.setState({ showSave: false });
|
||||
}
|
||||
onCancel() {
|
||||
this.setState({ showSave: false });
|
||||
}
|
||||
onLabelChange(e) {
|
||||
this.setState({ label: e.target.value });
|
||||
}
|
||||
onDescriptionChange(e) {
|
||||
this.setState({ description: e.target.value });
|
||||
}
|
||||
toggleSave(e) {
|
||||
this.setState({ target: e.target, showSave: !this.state.showSave });
|
||||
}
|
||||
renderPopover() {
|
||||
return (
|
||||
<Popover id="embed-code-popover">
|
||||
<FormGroup bsSize="small" style={{ width: '350px' }}>
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>
|
||||
<label className="control-label" htmlFor="embed-height">
|
||||
{t('Label')}
|
||||
</label>
|
||||
</small>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder={t('Label for your query')}
|
||||
value={this.state.label}
|
||||
onChange={this.onLabelChange}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>
|
||||
<label className="control-label" htmlFor="embed-height">{t('Description')}</label>
|
||||
</small>
|
||||
<FormControl
|
||||
componentClass="textarea"
|
||||
placeholder={t('Write a description for your query')}
|
||||
value={this.state.description}
|
||||
onChange={this.onDescriptionChange}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<Button
|
||||
bsStyle="primary"
|
||||
onClick={this.onSave}
|
||||
className="m-r-3"
|
||||
>
|
||||
{t('Save')}
|
||||
</Button>
|
||||
<Button onClick={this.onCancel} className="cancelQuery">
|
||||
{t('Cancel')}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormGroup>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<span className="SaveQuery">
|
||||
<Overlay
|
||||
trigger="click"
|
||||
show={this.state.showSave}
|
||||
placement="bottom"
|
||||
animation={this.props.animation}
|
||||
>
|
||||
{this.renderPopover()}
|
||||
</Overlay>
|
||||
<Button bsSize="small" className="toggleSave" onClick={this.toggleSave}>
|
||||
<i className="fa fa-save" /> {t('Save Query')}
|
||||
</Button>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
SaveQuery.propTypes = propTypes;
|
||||
SaveQuery.defaultProps = defaultProps;
|
||||
|
||||
export default SaveQuery;
|
||||
@@ -1,22 +1,25 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import shortid from 'shortid';
|
||||
import { Alert, Tab, Tabs } from 'react-bootstrap';
|
||||
import QueryHistory from './QueryHistory';
|
||||
import ResultSet from './ResultSet';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
import React from 'react';
|
||||
|
||||
import shortid from 'shortid';
|
||||
import * as Actions from '../actions';
|
||||
import QueryHistory from './QueryHistory';
|
||||
import ResultSet from './ResultSet';
|
||||
import { t } from '../../locales';
|
||||
|
||||
/*
|
||||
editorQueries are queries executed by users passed from SqlEditor component
|
||||
dataPrebiewQueries are all queries executed for preview of table data (from SqlEditorLeft)
|
||||
*/
|
||||
const propTypes = {
|
||||
editorQueries: React.PropTypes.array.isRequired,
|
||||
dataPreviewQueries: React.PropTypes.array.isRequired,
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
activeSouthPaneTab: React.PropTypes.string,
|
||||
editorQueries: PropTypes.array.isRequired,
|
||||
dataPreviewQueries: PropTypes.array.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
activeSouthPaneTab: PropTypes.string,
|
||||
height: PropTypes.number,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@@ -28,6 +31,7 @@ class SouthPane extends React.PureComponent {
|
||||
this.props.actions.setActiveSouthPaneTab(id);
|
||||
}
|
||||
render() {
|
||||
const innerTabHeight = this.props.height - 55;
|
||||
let latestQuery;
|
||||
const props = this.props;
|
||||
if (props.editorQueries.length > 0) {
|
||||
@@ -36,19 +40,32 @@ class SouthPane extends React.PureComponent {
|
||||
let results;
|
||||
if (latestQuery) {
|
||||
results = (
|
||||
<ResultSet showControls search query={latestQuery} actions={props.actions} />
|
||||
<ResultSet
|
||||
showControls
|
||||
search
|
||||
query={latestQuery}
|
||||
actions={props.actions}
|
||||
height={innerTabHeight}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
results = <Alert bsStyle="info">Run a query to display results here</Alert>;
|
||||
results = <Alert bsStyle="info">{t('Run a query to display results here')}</Alert>;
|
||||
}
|
||||
|
||||
const dataPreviewTabs = props.dataPreviewQueries.map((query) => (
|
||||
const dataPreviewTabs = props.dataPreviewQueries.map(query => (
|
||||
<Tab
|
||||
title={`Preview for ${query.tableName}`}
|
||||
title={t('Preview for %s', query.tableName)}
|
||||
eventKey={query.id}
|
||||
key={query.id}
|
||||
>
|
||||
<ResultSet query={query} visualize={false} csv={false} actions={props.actions} cache />
|
||||
<ResultSet
|
||||
query={query}
|
||||
visualize={false}
|
||||
csv={false}
|
||||
actions={props.actions}
|
||||
cache
|
||||
height={innerTabHeight}
|
||||
/>
|
||||
</Tab>
|
||||
));
|
||||
|
||||
@@ -61,18 +78,18 @@ class SouthPane extends React.PureComponent {
|
||||
onSelect={this.switchTab.bind(this)}
|
||||
>
|
||||
<Tab
|
||||
title="Results"
|
||||
title={t('Results')}
|
||||
eventKey="Results"
|
||||
>
|
||||
<div style={{ overflow: 'auto' }}>
|
||||
{results}
|
||||
</div>
|
||||
{results}
|
||||
</Tab>
|
||||
<Tab
|
||||
title="Query History"
|
||||
title={t('Query History')}
|
||||
eventKey="History"
|
||||
>
|
||||
<QueryHistory queries={props.editorQueries} actions={props.actions} />
|
||||
<div style={{ height: `${innerTabHeight}px`, overflow: 'scroll' }}>
|
||||
<QueryHistory queries={props.editorQueries} actions={props.actions} />
|
||||
</div>
|
||||
</Tab>
|
||||
{dataPreviewTabs}
|
||||
</Tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Col,
|
||||
FormGroup,
|
||||
@@ -11,31 +12,31 @@ import {
|
||||
Tooltip,
|
||||
Collapse,
|
||||
} from 'react-bootstrap';
|
||||
import SplitPane from 'react-split-pane';
|
||||
|
||||
import Button from '../../components/Button';
|
||||
|
||||
import SouthPane from './SouthPane';
|
||||
import SaveQuery from './SaveQuery';
|
||||
import Timer from '../../components/Timer';
|
||||
import SqlEditorLeftBar from './SqlEditorLeftBar';
|
||||
import AceEditorWrapper from './AceEditorWrapper';
|
||||
import { STATE_BSSTYLE_MAP } from '../constants.js';
|
||||
import { STATE_BSSTYLE_MAP } from '../constants';
|
||||
import RunQueryActionButton from './RunQueryActionButton';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
height: React.PropTypes.string.isRequired,
|
||||
database: React.PropTypes.object,
|
||||
latestQuery: React.PropTypes.object,
|
||||
networkOn: React.PropTypes.bool,
|
||||
tables: React.PropTypes.array.isRequired,
|
||||
editorQueries: React.PropTypes.array.isRequired,
|
||||
dataPreviewQueries: React.PropTypes.array.isRequired,
|
||||
queryEditor: React.PropTypes.object.isRequired,
|
||||
hideLeftBar: React.PropTypes.bool,
|
||||
actions: PropTypes.object.isRequired,
|
||||
height: PropTypes.string.isRequired,
|
||||
database: PropTypes.object,
|
||||
latestQuery: PropTypes.object,
|
||||
tables: PropTypes.array.isRequired,
|
||||
editorQueries: PropTypes.array.isRequired,
|
||||
dataPreviewQueries: PropTypes.array.isRequired,
|
||||
queryEditor: PropTypes.object.isRequired,
|
||||
hideLeftBar: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
networkOn: true,
|
||||
database: null,
|
||||
latestQuery: null,
|
||||
hideLeftBar: false,
|
||||
@@ -50,17 +51,35 @@ class SqlEditor extends React.PureComponent {
|
||||
ctas: '',
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
this.onMount();
|
||||
}
|
||||
onMount() {
|
||||
componentWillMount() {
|
||||
if (this.state.autorun) {
|
||||
this.setState({ autorun: false });
|
||||
this.props.actions.queryEditorSetAutorun(this.props.queryEditor, false);
|
||||
this.startQuery();
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.onResize();
|
||||
}
|
||||
onResize() {
|
||||
const height = this.sqlEditorHeight();
|
||||
this.setState({
|
||||
editorPaneHeight: this.refs.ace.clientHeight,
|
||||
southPaneHeight: height - this.refs.ace.clientHeight,
|
||||
height,
|
||||
});
|
||||
|
||||
if (this.refs.ace.clientHeight) {
|
||||
this.props.actions.persistEditorHeight(this.props.queryEditor, this.refs.ace.clientHeight);
|
||||
}
|
||||
}
|
||||
setQueryEditorSql(sql) {
|
||||
this.props.actions.queryEditorSetSql(this.props.queryEditor, sql);
|
||||
}
|
||||
runQuery(runAsync = false) {
|
||||
if (!this.props.queryEditor.sql) {
|
||||
return;
|
||||
}
|
||||
let effectiveRunAsync = runAsync;
|
||||
if (!this.props.database.allow_run_sync) {
|
||||
effectiveRunAsync = true;
|
||||
@@ -83,14 +102,11 @@ class SqlEditor extends React.PureComponent {
|
||||
this.props.actions.setActiveSouthPaneTab('Results');
|
||||
}
|
||||
stopQuery() {
|
||||
this.props.actions.stopQuery(this.props.latestQuery);
|
||||
this.props.actions.postStopQuery(this.props.latestQuery);
|
||||
}
|
||||
createTableAs() {
|
||||
this.startQuery(true, true);
|
||||
}
|
||||
setQueryEditorSql(sql) {
|
||||
this.props.actions.queryEditorSetSql(this.props.queryEditor, sql);
|
||||
}
|
||||
ctasChanged(event) {
|
||||
this.setState({ ctas: event.target.value });
|
||||
}
|
||||
@@ -101,26 +117,10 @@ class SqlEditor extends React.PureComponent {
|
||||
const mysteryVerticalHeight = 50;
|
||||
return window.innerHeight - tabNavHeight - navBarHeight - mysteryVerticalHeight;
|
||||
}
|
||||
|
||||
render() {
|
||||
let limitWarning = null;
|
||||
if (this.props.latestQuery && this.props.latestQuery.limit_reached) {
|
||||
const tooltip = (
|
||||
<Tooltip id="tooltip">
|
||||
It appears that the number of rows in the query results displayed
|
||||
was limited on the server side to
|
||||
the {this.props.latestQuery.rows} limit.
|
||||
</Tooltip>
|
||||
);
|
||||
limitWarning = (
|
||||
<OverlayTrigger placement="left" overlay={tooltip}>
|
||||
<Label bsStyle="warning" className="m-r-5">LIMIT</Label>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
}
|
||||
renderEditorBottomBar() {
|
||||
let ctasControls;
|
||||
if (this.props.database && this.props.database.allow_ctas) {
|
||||
const ctasToolTip = 'Create table as with query results';
|
||||
const ctasToolTip = t('Create table as with query results');
|
||||
ctasControls = (
|
||||
<FormGroup>
|
||||
<InputGroup>
|
||||
@@ -128,7 +128,7 @@ class SqlEditor extends React.PureComponent {
|
||||
type="text"
|
||||
bsSize="small"
|
||||
className="input-sm"
|
||||
placeholder="new table name"
|
||||
placeholder={t('new table name')}
|
||||
onChange={this.ctasChanged.bind(this)}
|
||||
/>
|
||||
<InputGroup.Button>
|
||||
@@ -145,18 +145,46 @@ class SqlEditor extends React.PureComponent {
|
||||
</FormGroup>
|
||||
);
|
||||
}
|
||||
const editorBottomBar = (
|
||||
<div className="sql-toolbar clearfix">
|
||||
const qe = this.props.queryEditor;
|
||||
let limitWarning = null;
|
||||
if (this.props.latestQuery && this.props.latestQuery.limit_reached) {
|
||||
const tooltip = (
|
||||
<Tooltip id="tooltip">
|
||||
It appears that the number of rows in the query results displayed
|
||||
was limited on the server side to
|
||||
the {this.props.latestQuery.rows} limit.
|
||||
</Tooltip>
|
||||
);
|
||||
limitWarning = (
|
||||
<OverlayTrigger placement="left" overlay={tooltip}>
|
||||
<Label bsStyle="warning" className="m-r-5">LIMIT</Label>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="sql-toolbar clearfix" id="js-sql-toolbar">
|
||||
<div className="pull-left">
|
||||
<Form inline>
|
||||
<RunQueryActionButton
|
||||
allowAsync={this.props.database && this.props.database.allow_run_async}
|
||||
dbId={this.props.queryEditor.dbId}
|
||||
queryState={this.props.latestQuery && this.props.latestQuery.state}
|
||||
runQuery={this.runQuery.bind(this)}
|
||||
selectedText={this.props.queryEditor.selectedText}
|
||||
stopQuery={this.stopQuery.bind(this)}
|
||||
/>
|
||||
<span className="m-r-5">
|
||||
<RunQueryActionButton
|
||||
allowAsync={this.props.database ? this.props.database.allow_run_async : false}
|
||||
dbId={qe.dbId}
|
||||
queryState={this.props.latestQuery && this.props.latestQuery.state}
|
||||
runQuery={this.runQuery.bind(this)}
|
||||
selectedText={qe.selectedText}
|
||||
stopQuery={this.stopQuery.bind(this)}
|
||||
/>
|
||||
</span>
|
||||
<span className="m-r-5">
|
||||
<SaveQuery
|
||||
defaultLabel={qe.title}
|
||||
sql={qe.sql}
|
||||
className="m-r-5"
|
||||
onSave={this.props.actions.saveQuery}
|
||||
schema={qe.schema}
|
||||
dbId={qe.dbId}
|
||||
/>
|
||||
</span>
|
||||
{ctasControls}
|
||||
</Form>
|
||||
</div>
|
||||
@@ -173,11 +201,15 @@ class SqlEditor extends React.PureComponent {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
const height = this.sqlEditorHeight();
|
||||
const defaultNorthHeight = this.props.queryEditor.height || 200;
|
||||
return (
|
||||
<div
|
||||
className="SqlEditor"
|
||||
style={{
|
||||
minHeight: this.sqlEditorHeight(),
|
||||
minHeight: height,
|
||||
height: this.props.height,
|
||||
}}
|
||||
>
|
||||
@@ -185,36 +217,56 @@ class SqlEditor extends React.PureComponent {
|
||||
<Collapse
|
||||
in={!this.props.hideLeftBar}
|
||||
>
|
||||
<Col md={3}>
|
||||
<Col
|
||||
xs={6}
|
||||
sm={5}
|
||||
md={4}
|
||||
lg={3}
|
||||
>
|
||||
<SqlEditorLeftBar
|
||||
style={{ height: this.props.height }}
|
||||
height={height}
|
||||
queryEditor={this.props.queryEditor}
|
||||
tables={this.props.tables}
|
||||
networkOn={this.props.networkOn}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
</Col>
|
||||
</Collapse>
|
||||
<Col md={this.props.hideLeftBar ? 12 : 9}>
|
||||
<div className="scrollbar-container">
|
||||
<div className="scrollbar-content">
|
||||
<AceEditorWrapper
|
||||
actions={this.props.actions}
|
||||
onBlur={this.setQueryEditorSql.bind(this)}
|
||||
queryEditor={this.props.queryEditor}
|
||||
onAltEnter={this.runQuery.bind(this)}
|
||||
sql={this.props.queryEditor.sql}
|
||||
tables={this.props.tables}
|
||||
/>
|
||||
{editorBottomBar}
|
||||
<br />
|
||||
<Col
|
||||
xs={this.props.hideLeftBar ? 12 : 6}
|
||||
sm={this.props.hideLeftBar ? 12 : 7}
|
||||
md={this.props.hideLeftBar ? 12 : 8}
|
||||
lg={this.props.hideLeftBar ? 12 : 9}
|
||||
style={{ height: this.state.height }}
|
||||
>
|
||||
<SplitPane
|
||||
split="horizontal"
|
||||
defaultSize={defaultNorthHeight}
|
||||
minSize={100}
|
||||
onChange={this.onResize.bind(this)}
|
||||
>
|
||||
<div ref="ace" style={{ width: '100%' }}>
|
||||
<div>
|
||||
<AceEditorWrapper
|
||||
actions={this.props.actions}
|
||||
onBlur={this.setQueryEditorSql.bind(this)}
|
||||
queryEditor={this.props.queryEditor}
|
||||
onAltEnter={this.runQuery.bind(this)}
|
||||
sql={this.props.queryEditor.sql}
|
||||
tables={this.props.tables}
|
||||
height={((this.state.editorPaneHeight || defaultNorthHeight) - 50).toString()}
|
||||
/>
|
||||
{this.renderEditorBottomBar()}
|
||||
</div>
|
||||
</div>
|
||||
<div ref="south">
|
||||
<SouthPane
|
||||
editorQueries={this.props.editorQueries}
|
||||
dataPreviewQueries={this.props.dataPreviewQueries}
|
||||
actions={this.props.actions}
|
||||
height={this.state.southPaneHeight}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SplitPane>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
/* global notify */
|
||||
import React from 'react';
|
||||
import Select from 'react-select';
|
||||
import { Label, Button } from 'react-bootstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import Select from 'react-virtualized-select';
|
||||
import createFilterOptions from 'react-select-fast-filter-options';
|
||||
|
||||
import TableElement from './TableElement';
|
||||
import AsyncSelect from '../../components/AsyncSelect';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const $ = window.$ = require('jquery');
|
||||
|
||||
const propTypes = {
|
||||
queryEditor: React.PropTypes.object.isRequired,
|
||||
tables: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
networkOn: React.PropTypes.bool,
|
||||
queryEditor: PropTypes.object.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
tables: PropTypes.array,
|
||||
actions: PropTypes.object,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
tables: [],
|
||||
networkOn: true,
|
||||
actions: {},
|
||||
};
|
||||
|
||||
@@ -26,16 +31,16 @@ class SqlEditorLeftBar extends React.PureComponent {
|
||||
schemaOptions: [],
|
||||
tableLoading: false,
|
||||
tableOptions: [],
|
||||
networkOn: true,
|
||||
};
|
||||
}
|
||||
componentWillMount() {
|
||||
this.fetchSchemas(this.props.queryEditor.dbId);
|
||||
this.fetchTables(this.props.queryEditor.dbId, this.props.queryEditor.schema);
|
||||
}
|
||||
onChange(db) {
|
||||
const val = (db) ? db.value : null;
|
||||
onDatabaseChange(db) {
|
||||
const val = db ? db.value : null;
|
||||
this.setState({ schemaOptions: [] });
|
||||
this.props.actions.queryEditorSetSchema(this.props.queryEditor, null);
|
||||
this.props.actions.queryEditorSetDb(this.props.queryEditor, val);
|
||||
if (!(db)) {
|
||||
this.setState({ tableOptions: [] });
|
||||
@@ -44,13 +49,21 @@ class SqlEditorLeftBar extends React.PureComponent {
|
||||
this.fetchSchemas(val);
|
||||
}
|
||||
}
|
||||
getTableNamesBySubStr(input) {
|
||||
if (!this.props.queryEditor.dbId || !input) {
|
||||
return Promise.resolve({ options: [] });
|
||||
}
|
||||
const url = `/superset/tables/${this.props.queryEditor.dbId}/` +
|
||||
`${this.props.queryEditor.schema}/${input}`;
|
||||
return $.get(url).then(data => ({ options: data.options }));
|
||||
}
|
||||
dbMutator(data) {
|
||||
const options = data.result.map((db) => ({ value: db.id, label: db.database_name }));
|
||||
const options = data.result.map(db => ({ value: db.id, label: db.database_name }));
|
||||
this.props.actions.setDatabases(data.result);
|
||||
if (data.result.length === 0) {
|
||||
this.props.actions.addAlert({
|
||||
bsStyle: 'danger',
|
||||
msg: "It seems you don't have access to any database",
|
||||
msg: t('It seems you don\'t have access to any database'),
|
||||
});
|
||||
}
|
||||
return options;
|
||||
@@ -58,26 +71,26 @@ class SqlEditorLeftBar extends React.PureComponent {
|
||||
resetState() {
|
||||
this.props.actions.resetState();
|
||||
}
|
||||
getTableNamesBySubStr(input) {
|
||||
if (!this.props.queryEditor.dbId || !input) {
|
||||
return Promise.resolve({ options: [] });
|
||||
}
|
||||
const url = `/superset/tables/${this.props.queryEditor.dbId}/\
|
||||
${this.props.queryEditor.schema}/${input}`;
|
||||
return $.get(url).then((data) => ({ options: data.options }));
|
||||
}
|
||||
// TODO: move fetching methods to the actions.
|
||||
fetchTables(dbId, schema, substr) {
|
||||
if (dbId) {
|
||||
// This can be large so it shouldn't be put in the Redux store
|
||||
if (dbId && schema) {
|
||||
this.setState({ tableLoading: true, tableOptions: [] });
|
||||
const url = `/superset/tables/${dbId}/${schema}/${substr}/`;
|
||||
$.get(url, (data) => {
|
||||
$.get(url).done((data) => {
|
||||
const filterOptions = createFilterOptions({ options: data.options });
|
||||
this.setState({
|
||||
filterOptions,
|
||||
tableLoading: false,
|
||||
tableOptions: data.options,
|
||||
tableLength: data.tableLength,
|
||||
});
|
||||
})
|
||||
.fail(() => {
|
||||
this.setState({ tableLoading: false, tableOptions: [], tableLength: 0 });
|
||||
notify.error(t('Error while fetching table list'));
|
||||
});
|
||||
} else {
|
||||
this.setState({ tableLoading: false, tableOptions: [], filterOptions: null });
|
||||
}
|
||||
}
|
||||
changeTable(tableOpt) {
|
||||
@@ -97,11 +110,7 @@ ${this.props.queryEditor.schema}/${input}`;
|
||||
this.props.actions.queryEditorSetSchema(this.props.queryEditor, schemaName);
|
||||
this.fetchTables(this.props.queryEditor.dbId, schemaName);
|
||||
}
|
||||
this.setState({ tableLoading: true });
|
||||
// TODO: handle setting the tableLoading state depending on success or
|
||||
// failure of the addTable async call in the action.
|
||||
this.props.actions.addTable(this.props.queryEditor, tableName, schemaName);
|
||||
this.setState({ tableLoading: false });
|
||||
}
|
||||
changeSchema(schemaOpt) {
|
||||
const schema = (schemaOpt) ? schemaOpt.value : null;
|
||||
@@ -113,97 +122,110 @@ ${this.props.queryEditor.schema}/${input}`;
|
||||
if (actualDbId) {
|
||||
this.setState({ schemaLoading: true });
|
||||
const url = `/superset/schemas/${actualDbId}/`;
|
||||
$.get(url, (data) => {
|
||||
const schemaOptions = data.schemas.map((s) => ({ value: s, label: s }));
|
||||
this.setState({ schemaOptions });
|
||||
this.setState({ schemaLoading: false });
|
||||
$.get(url).done((data) => {
|
||||
const schemaOptions = data.schemas.map(s => ({ value: s, label: s }));
|
||||
this.setState({ schemaOptions, schemaLoading: false });
|
||||
})
|
||||
.fail(() => {
|
||||
this.setState({ schemaLoading: false, schemaOptions: [] });
|
||||
notify.error(t('Error while fetching schema list'));
|
||||
});
|
||||
}
|
||||
}
|
||||
closePopover(ref) {
|
||||
this.refs[ref].hide();
|
||||
}
|
||||
|
||||
render() {
|
||||
let networkAlert = null;
|
||||
if (!this.props.networkOn) {
|
||||
networkAlert = <p><Label bsStyle="danger">OFFLINE</Label></p>;
|
||||
}
|
||||
const shouldShowReset = window.location.search === '?reset=1';
|
||||
const tableMetaDataHeight = this.props.height - 130; // 130 is the height of the selects above
|
||||
return (
|
||||
<div className="scrollbar-container">
|
||||
<div className="clearfix sql-toolbar scrollbar-content">
|
||||
{networkAlert}
|
||||
<div>
|
||||
<AsyncSelect
|
||||
dataEndpoint="/databaseasync/api/read?_flt_0_expose_in_sqllab=1"
|
||||
onChange={this.onChange.bind(this)}
|
||||
value={this.props.queryEditor.dbId}
|
||||
databaseId={this.props.queryEditor.dbId}
|
||||
actions={this.props.actions}
|
||||
valueRenderer={(o) => (
|
||||
<div>
|
||||
<span className="text-muted">Database:</span> {o.label}
|
||||
</div>
|
||||
)}
|
||||
mutator={this.dbMutator.bind(this)}
|
||||
placeholder="Select a database"
|
||||
/>
|
||||
<div className="clearfix sql-toolbar">
|
||||
<div>
|
||||
<AsyncSelect
|
||||
dataEndpoint={
|
||||
'/databaseasync/api/' +
|
||||
'read?_flt_0_expose_in_sqllab=1&' +
|
||||
'_oc_DatabaseAsync=database_name&' +
|
||||
'_od_DatabaseAsync=asc'
|
||||
}
|
||||
onChange={this.onDatabaseChange.bind(this)}
|
||||
onAsyncError={() => notify.error(t('Error while fetching database list'))}
|
||||
value={this.props.queryEditor.dbId}
|
||||
databaseId={this.props.queryEditor.dbId}
|
||||
actions={this.props.actions}
|
||||
valueRenderer={o => (
|
||||
<div>
|
||||
<span className="text-muted">{t('Database:')}</span> {o.label}
|
||||
</div>
|
||||
)}
|
||||
mutator={this.dbMutator.bind(this)}
|
||||
placeholder={t('Select a database')}
|
||||
autoSelect
|
||||
/>
|
||||
</div>
|
||||
<div className="m-t-5">
|
||||
<Select
|
||||
name="select-schema"
|
||||
placeholder={t('Select a schema (%s)', this.state.schemaOptions.length)}
|
||||
options={this.state.schemaOptions}
|
||||
value={this.props.queryEditor.schema}
|
||||
valueRenderer={o => (
|
||||
<div>
|
||||
<span className="text-muted">{t('Schema:')}</span> {o.label}
|
||||
</div>
|
||||
)}
|
||||
isLoading={this.state.schemaLoading}
|
||||
autosize={false}
|
||||
onChange={this.changeSchema.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-t-5">
|
||||
{this.props.queryEditor.schema &&
|
||||
<Select
|
||||
name="select-schema"
|
||||
placeholder={`Select a schema (${this.state.schemaOptions.length})`}
|
||||
options={this.state.schemaOptions}
|
||||
value={this.props.queryEditor.schema}
|
||||
valueRenderer={(o) => (
|
||||
<div>
|
||||
<span className="text-muted">Schema:</span> {o.label}
|
||||
</div>
|
||||
)}
|
||||
isLoading={this.state.schemaLoading}
|
||||
name="select-table"
|
||||
ref="selectTable"
|
||||
isLoading={this.state.tableLoading}
|
||||
value={this.state.tableName}
|
||||
placeholder={t('Add a table (%s)', this.state.tableOptions.length)}
|
||||
autosize={false}
|
||||
onChange={this.changeSchema.bind(this)}
|
||||
onChange={this.changeTable.bind(this)}
|
||||
filterOptions={this.state.filterOptions}
|
||||
options={this.state.tableOptions}
|
||||
/>
|
||||
}
|
||||
{!this.props.queryEditor.schema &&
|
||||
<Select
|
||||
async
|
||||
name="async-select-table"
|
||||
ref="selectTable"
|
||||
value={this.state.tableName}
|
||||
placeholder={t('Type to search ...')}
|
||||
autosize={false}
|
||||
onChange={this.changeTable.bind(this)}
|
||||
loadOptions={this.getTableNamesBySubStr.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-t-5">
|
||||
{this.props.queryEditor.schema &&
|
||||
<Select
|
||||
name="select-table"
|
||||
ref="selectTable"
|
||||
isLoading={this.state.tableLoading}
|
||||
value={this.state.tableName}
|
||||
placeholder={`Add a table (${this.state.tableOptions.length})`}
|
||||
autosize={false}
|
||||
onChange={this.changeTable.bind(this)}
|
||||
options={this.state.tableOptions}
|
||||
/>
|
||||
}
|
||||
{!this.props.queryEditor.schema &&
|
||||
<Select.Async
|
||||
name="async-select-table"
|
||||
ref="selectTable"
|
||||
value={this.state.tableName}
|
||||
placeholder={"Type to search ..."}
|
||||
autosize={false}
|
||||
onChange={this.changeTable.bind(this)}
|
||||
loadOptions={this.getTableNamesBySubStr.bind(this)}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<hr />
|
||||
<div className="m-t-5">
|
||||
{this.props.tables.map((table) => (
|
||||
<TableElement
|
||||
table={table}
|
||||
key={table.id}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{shouldShowReset &&
|
||||
<Button bsSize="small" bsStyle="danger" onClick={this.resetState.bind(this)}>
|
||||
<i className="fa fa-bomb" /> Reset State
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
<hr />
|
||||
<div className="m-t-5">
|
||||
<div className="scrollbar-container">
|
||||
<div className="scrollbar-content" style={{ height: tableMetaDataHeight }}>
|
||||
{this.props.tables.map(table => (
|
||||
<TableElement
|
||||
table={table}
|
||||
key={table.id}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{shouldShowReset &&
|
||||
<Button bsSize="small" bsStyle="danger" onClick={this.resetState.bind(this)}>
|
||||
<i className="fa fa-bomb" /> {t('Reset State')}
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { DropdownButton, MenuItem, Tab, Tabs } from 'react-bootstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import URI from 'urijs';
|
||||
|
||||
import * as Actions from '../actions';
|
||||
import SqlEditor from './SqlEditor';
|
||||
import CopyQueryTabUrl from './CopyQueryTabUrl';
|
||||
import { areArraysShallowEqual } from '../../reduxUtils';
|
||||
import { getParamFromQuery } from '../../../utils/common';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
databases: React.PropTypes.object.isRequired,
|
||||
queries: React.PropTypes.object.isRequired,
|
||||
queryEditors: React.PropTypes.array,
|
||||
tabHistory: React.PropTypes.array.isRequired,
|
||||
tables: React.PropTypes.array.isRequired,
|
||||
networkOn: React.PropTypes.bool,
|
||||
editorHeight: React.PropTypes.string.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
defaultDbId: PropTypes.number,
|
||||
databases: PropTypes.object.isRequired,
|
||||
queries: PropTypes.object.isRequired,
|
||||
queryEditors: PropTypes.array,
|
||||
tabHistory: PropTypes.array.isRequired,
|
||||
tables: PropTypes.array.isRequired,
|
||||
editorHeight: PropTypes.string.isRequired,
|
||||
};
|
||||
const defaultProps = {
|
||||
queryEditors: [],
|
||||
networkOn: true,
|
||||
};
|
||||
|
||||
let queryCount = 1;
|
||||
@@ -37,19 +39,19 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
const search = window.location.search;
|
||||
if (search) {
|
||||
const queryString = search.substring(1);
|
||||
const urlId = getParamFromQuery(queryString, 'id');
|
||||
if (urlId) {
|
||||
this.props.actions.popStoredQuery(urlId);
|
||||
} else {
|
||||
let dbId = getParamFromQuery(queryString, 'dbid');
|
||||
const query = URI(window.location).search(true);
|
||||
if (query.id || query.sql || query.savedQueryId) {
|
||||
if (query.id) {
|
||||
this.props.actions.popStoredQuery(query.id);
|
||||
} else if (query.savedQueryId) {
|
||||
this.props.actions.popSavedQuery(query.savedQueryId);
|
||||
} else if (query.sql) {
|
||||
let dbId = query.dbid;
|
||||
if (dbId) {
|
||||
dbId = parseInt(dbId, 10);
|
||||
} else {
|
||||
const databases = this.props.databases;
|
||||
const dbName = getParamFromQuery(queryString, 'dbname');
|
||||
const dbName = query.dbname;
|
||||
if (dbName) {
|
||||
Object.keys(databases).forEach((db) => {
|
||||
if (databases[db].database_name === dbName) {
|
||||
@@ -59,22 +61,17 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
const newQueryEditor = {
|
||||
title: getParamFromQuery(queryString, 'title'),
|
||||
title: query.title,
|
||||
dbId,
|
||||
schema: getParamFromQuery(queryString, 'schema'),
|
||||
autorun: getParamFromQuery(queryString, 'autorun'),
|
||||
sql: getParamFromQuery(queryString, 'sql'),
|
||||
schema: query.schema,
|
||||
autorun: query.autorun,
|
||||
sql: query.sql,
|
||||
};
|
||||
this.props.actions.addQueryEditor(newQueryEditor);
|
||||
}
|
||||
this.popNewTab();
|
||||
}
|
||||
}
|
||||
popNewTab() {
|
||||
queryCount++;
|
||||
// Clean the url in browser history
|
||||
window.history.replaceState({}, document.title, this.state.sqlLabUrl);
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const nextActiveQeId = nextProps.tabHistory[nextProps.tabHistory.length - 1];
|
||||
const queriesArray = [];
|
||||
@@ -98,9 +95,14 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||
this.setState({ dataPreviewQueries });
|
||||
}
|
||||
}
|
||||
popNewTab() {
|
||||
queryCount++;
|
||||
// Clean the url in browser history
|
||||
window.history.replaceState({}, document.title, this.state.sqlLabUrl);
|
||||
}
|
||||
renameTab(qe) {
|
||||
/* eslint no-alert: 0 */
|
||||
const newTitle = prompt('Enter a new title for the tab');
|
||||
const newTitle = prompt(t('Enter a new title for the tab'));
|
||||
if (newTitle) {
|
||||
this.props.actions.queryEditorSetTitle(qe, newTitle);
|
||||
}
|
||||
@@ -119,7 +121,7 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||
queryCount++;
|
||||
const activeQueryEditor = this.activeQueryEditor();
|
||||
const qe = {
|
||||
title: `Untitled Query ${queryCount}`,
|
||||
title: t('Untitled Query %s', queryCount),
|
||||
dbId: (activeQueryEditor && activeQueryEditor.dbId) ?
|
||||
activeQueryEditor.dbId :
|
||||
this.props.defaultDbId,
|
||||
@@ -165,10 +167,10 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||
title=""
|
||||
>
|
||||
<MenuItem eventKey="1" onClick={this.removeQueryEditor.bind(this, qe)}>
|
||||
<i className="fa fa-close" /> close tab
|
||||
<i className="fa fa-close" /> {t('close tab')}
|
||||
</MenuItem>
|
||||
<MenuItem eventKey="2" onClick={this.renameTab.bind(this, qe)}>
|
||||
<i className="fa fa-i-cursor" /> rename tab
|
||||
<i className="fa fa-i-cursor" /> {t('rename tab')}
|
||||
</MenuItem>
|
||||
{qe &&
|
||||
<CopyQueryTabUrl queryEditor={qe} />
|
||||
@@ -176,7 +178,7 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||
<MenuItem eventKey="4" onClick={this.toggleLeftBar.bind(this)}>
|
||||
<i className="fa fa-cogs" />
|
||||
|
||||
{this.state.hideLeftBar ? 'expand tool bar' : 'hide tool bar'}
|
||||
{this.state.hideLeftBar ? t('expand tool bar') : t('hide tool bar')}
|
||||
</MenuItem>
|
||||
</DropdownButton>
|
||||
</div>
|
||||
@@ -192,14 +194,13 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||
{isSelected &&
|
||||
<SqlEditor
|
||||
height={this.props.editorHeight}
|
||||
tables={this.props.tables.filter((t) => (t.queryEditorId === qe.id))}
|
||||
tables={this.props.tables.filter(xt => (xt.queryEditorId === qe.id))}
|
||||
queryEditor={qe}
|
||||
editorQueries={this.state.queriesArray}
|
||||
dataPreviewQueries={this.state.dataPreviewQueries}
|
||||
latestQuery={latestQuery}
|
||||
database={database}
|
||||
actions={this.props.actions}
|
||||
networkOn={this.props.networkOn}
|
||||
hideLeftBar={this.state.hideLeftBar}
|
||||
/>
|
||||
}
|
||||
@@ -235,7 +236,6 @@ function mapStateToProps(state) {
|
||||
queryEditors: state.queryEditors,
|
||||
queries: state.queries,
|
||||
tabHistory: state.tabHistory,
|
||||
networkOn: state.networkOn,
|
||||
tables: state.tables,
|
||||
defaultDbId: state.defaultDbId,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { ButtonGroup, Collapse, Well } from 'react-bootstrap';
|
||||
import shortid from 'shortid';
|
||||
@@ -7,11 +8,13 @@ import CopyToClipboard from '../../components/CopyToClipboard';
|
||||
import Link from './Link';
|
||||
import ColumnElement from './ColumnElement';
|
||||
import ModalTrigger from '../../components/ModalTrigger';
|
||||
import Loading from '../../components/Loading';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const propTypes = {
|
||||
table: React.PropTypes.object,
|
||||
actions: React.PropTypes.object,
|
||||
timeout: React.PropTypes.number, // used for tests
|
||||
table: PropTypes.object,
|
||||
actions: PropTypes.object,
|
||||
timeout: PropTypes.number, // used for tests
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@@ -57,7 +60,11 @@ class TableElement extends React.PureComponent {
|
||||
this.setState({ sortColumns: !this.state.sortColumns });
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
removeFromStore() {
|
||||
this.props.actions.removeTable(this.props.table);
|
||||
}
|
||||
|
||||
renderWell() {
|
||||
const table = this.props.table;
|
||||
let header;
|
||||
if (table.partitions) {
|
||||
@@ -65,7 +72,7 @@ class TableElement extends React.PureComponent {
|
||||
let partitionClipBoard;
|
||||
if (table.partitions.partitionQuery) {
|
||||
partitionQuery = table.partitions.partitionQuery;
|
||||
const tt = 'Copy partition query to clipboard';
|
||||
const tt = t('Copy partition query to clipboard');
|
||||
partitionClipBoard = (
|
||||
<CopyToClipboard
|
||||
text={partitionQuery}
|
||||
@@ -84,7 +91,7 @@ class TableElement extends React.PureComponent {
|
||||
<Well bsSize="small">
|
||||
<div>
|
||||
<small>
|
||||
latest partition: {latest}
|
||||
{t('latest partition:')} {latest}
|
||||
</small> {partitionClipBoard}
|
||||
</div>
|
||||
</Well>
|
||||
@@ -92,7 +99,89 @@ class TableElement extends React.PureComponent {
|
||||
}
|
||||
return header;
|
||||
}
|
||||
renderMetadata() {
|
||||
renderControls() {
|
||||
let keyLink;
|
||||
const table = this.props.table;
|
||||
if (table.indexes && table.indexes.length > 0) {
|
||||
keyLink = (
|
||||
<ModalTrigger
|
||||
modalTitle={
|
||||
<div>
|
||||
{t('Keys for table')} <strong>{table.name}</strong>
|
||||
</div>
|
||||
}
|
||||
modalBody={table.indexes.map((ix, i) => (
|
||||
<pre key={i}>{JSON.stringify(ix, null, ' ')}</pre>
|
||||
))}
|
||||
triggerNode={
|
||||
<Link
|
||||
className="fa fa-key pull-left m-l-2"
|
||||
tooltip={t('View keys & indexes (%s)', table.indexes.length)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ButtonGroup className="ws-el-controls pull-right">
|
||||
{keyLink}
|
||||
<Link
|
||||
className={
|
||||
`fa fa-sort-${!this.state.sortColumns ? 'alpha' : 'numeric'}-asc ` +
|
||||
'pull-left sort-cols m-l-2'}
|
||||
onClick={this.toggleSortColumns.bind(this)}
|
||||
tooltip={
|
||||
!this.state.sortColumns ?
|
||||
t('Sort columns alphabetically') :
|
||||
t('Original table column order')}
|
||||
href="#"
|
||||
/>
|
||||
{table.selectStar &&
|
||||
<CopyToClipboard
|
||||
copyNode={
|
||||
<a className="fa fa-clipboard pull-left m-l-2" />
|
||||
}
|
||||
text={table.selectStar}
|
||||
shouldShowText={false}
|
||||
tooltipText={t('Copy SELECT statement to clipboard')}
|
||||
/>
|
||||
}
|
||||
<Link
|
||||
className="fa fa-times table-remove pull-left m-l-2"
|
||||
onClick={this.removeTable.bind(this)}
|
||||
tooltip={t('Remove table preview')}
|
||||
href="#"
|
||||
/>
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
renderHeader() {
|
||||
const table = this.props.table;
|
||||
return (
|
||||
<div className="clearfix">
|
||||
<div className="pull-left">
|
||||
<a
|
||||
href="#"
|
||||
className="table-name"
|
||||
onClick={(e) => { this.toggleTable(e); }}
|
||||
>
|
||||
<strong>{table.name}</strong>
|
||||
<small className="m-l-5">
|
||||
<i className={`fa fa-${table.expanded ? 'minus' : 'plus'}-square-o`} />
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
<div className="pull-right">
|
||||
{table.isMetadataLoading || table.isExtraMetadataLoading ?
|
||||
<Loading size={20} />
|
||||
:
|
||||
this.renderControls()
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
renderBody() {
|
||||
const table = this.props.table;
|
||||
let cols;
|
||||
if (table.columns) {
|
||||
@@ -107,7 +196,7 @@ class TableElement extends React.PureComponent {
|
||||
timeout={this.props.timeout}
|
||||
>
|
||||
<div>
|
||||
{this.renderHeader()}
|
||||
{this.renderWell()}
|
||||
<div className="table-columns">
|
||||
{cols && cols.map(col => (
|
||||
<ColumnElement column={col} key={col.name} />
|
||||
@@ -119,33 +208,8 @@ class TableElement extends React.PureComponent {
|
||||
);
|
||||
return metadata;
|
||||
}
|
||||
removeFromStore() {
|
||||
this.props.actions.removeTable(this.props.table);
|
||||
}
|
||||
|
||||
render() {
|
||||
const table = this.props.table;
|
||||
let keyLink;
|
||||
if (table.indexes && table.indexes.length > 0) {
|
||||
keyLink = (
|
||||
<ModalTrigger
|
||||
modalTitle={
|
||||
<div>
|
||||
Keys for table <strong>{table.name}</strong>
|
||||
</div>
|
||||
}
|
||||
modalBody={table.indexes.map((ix, i) => (
|
||||
<pre key={i}>{JSON.stringify(ix, null, ' ')}</pre>
|
||||
))}
|
||||
triggerNode={
|
||||
<Link
|
||||
className="fa fa-key pull-left m-l-2"
|
||||
tooltip={`View keys & indexes (${table.indexes.length})`}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Collapse
|
||||
in={this.state.expanded}
|
||||
@@ -154,54 +218,9 @@ class TableElement extends React.PureComponent {
|
||||
onExited={this.removeFromStore.bind(this)}
|
||||
>
|
||||
<div className="TableElement">
|
||||
<div className="clearfix">
|
||||
<div className="pull-left">
|
||||
<a
|
||||
href="#"
|
||||
className="table-name"
|
||||
onClick={(e) => { this.toggleTable(e); }}
|
||||
>
|
||||
<strong>{table.name}</strong>
|
||||
<small className="m-l-5">
|
||||
<i className={`fa fa-${table.expanded ? 'minus' : 'plus'}-square-o`} />
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
<div className="pull-right">
|
||||
<ButtonGroup className="ws-el-controls pull-right">
|
||||
{keyLink}
|
||||
<Link
|
||||
className={
|
||||
`fa fa-sort-${!this.state.sortColumns ? 'alpha' : 'numeric'}-asc ` +
|
||||
'pull-left sort-cols m-l-2'}
|
||||
onClick={this.toggleSortColumns.bind(this)}
|
||||
tooltip={
|
||||
!this.state.sortColumns ?
|
||||
'Sort columns alphabetically' :
|
||||
'Original table column order'}
|
||||
href="#"
|
||||
/>
|
||||
{table.selectStar &&
|
||||
<CopyToClipboard
|
||||
copyNode={
|
||||
<a className="fa fa-clipboard pull-left m-l-2" />
|
||||
}
|
||||
text={table.selectStar}
|
||||
shouldShowText={false}
|
||||
tooltipText="Copy SELECT statement to clipboard"
|
||||
/>
|
||||
}
|
||||
<Link
|
||||
className="fa fa-trash table-remove pull-left m-l-2"
|
||||
onClick={this.removeTable.bind(this)}
|
||||
tooltip="Remove table preview"
|
||||
href="#"
|
||||
/>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
{this.renderHeader()}
|
||||
<div>
|
||||
{this.renderMetadata()}
|
||||
{this.renderBody()}
|
||||
</div>
|
||||
</div>
|
||||
</Collapse>
|
||||
|
||||
@@ -1,22 +1,39 @@
|
||||
/* global notify */
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Alert, Button, Col, Modal } from 'react-bootstrap';
|
||||
|
||||
import Select from 'react-select';
|
||||
import { Table } from 'reactable';
|
||||
import shortid from 'shortid';
|
||||
import $ from 'jquery';
|
||||
import { getExploreUrl } from '../../explore/exploreUtils';
|
||||
import * as actions from '../actions';
|
||||
import { VISUALIZE_VALIDATION_ERRORS } from '../constants';
|
||||
import visTypes from '../../explore/stores/visTypes';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const CHART_TYPES = [
|
||||
{ value: 'dist_bar', label: 'Distribution - Bar Chart', requiresTime: false },
|
||||
{ value: 'pie', label: 'Pie Chart', requiresTime: false },
|
||||
{ value: 'line', label: 'Time Series - Line Chart', requiresTime: true },
|
||||
{ value: 'bar', label: 'Time Series - Bar Chart', requiresTime: true },
|
||||
];
|
||||
const CHART_TYPES = Object.keys(visTypes)
|
||||
.filter(typeName => !!visTypes[typeName].showOnExplore)
|
||||
.map((typeName) => {
|
||||
const vis = visTypes[typeName];
|
||||
return {
|
||||
value: typeName,
|
||||
label: vis.label,
|
||||
requiresTime: !!vis.requiresTime,
|
||||
};
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
onHide: React.PropTypes.func,
|
||||
query: React.PropTypes.object,
|
||||
show: React.PropTypes.bool,
|
||||
actions: PropTypes.object.isRequired,
|
||||
onHide: PropTypes.func,
|
||||
query: PropTypes.object,
|
||||
show: PropTypes.bool,
|
||||
datasource: PropTypes.string,
|
||||
errorMessage: PropTypes.string,
|
||||
timeout: PropTypes.number,
|
||||
};
|
||||
const defaultProps = {
|
||||
show: false,
|
||||
@@ -30,28 +47,26 @@ class VisualizeModal extends React.PureComponent {
|
||||
this.state = {
|
||||
chartType: CHART_TYPES[0],
|
||||
datasourceName: this.datasourceName(),
|
||||
columns: {},
|
||||
columns: this.getColumnFromProps(),
|
||||
hints: [],
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
this.validate();
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setStateFromProps(nextProps);
|
||||
}
|
||||
setStateFromProps(props) {
|
||||
if (
|
||||
getColumnFromProps() {
|
||||
const props = this.props;
|
||||
if (!props ||
|
||||
!props.query ||
|
||||
!props.query.results ||
|
||||
!props.query.results.columns) {
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
const columns = {};
|
||||
props.query.results.columns.forEach((col) => {
|
||||
columns[col.name] = col;
|
||||
});
|
||||
this.setState({ columns });
|
||||
return columns;
|
||||
}
|
||||
datasourceName() {
|
||||
const { query } = this.props;
|
||||
@@ -72,14 +87,14 @@ class VisualizeModal extends React.PureComponent {
|
||||
if (!re.test(colName)) {
|
||||
hints.push(
|
||||
<div>
|
||||
"{colName}" is not right as a column name, please alias it
|
||||
(as in SELECT count(*) <strong>AS my_alias</strong>) using only
|
||||
alphanumeric characters and underscores
|
||||
{t('%s is not right as a column name, please alias it ' +
|
||||
'(as in SELECT count(*) ', colName)} <strong>{t('AS my_alias')}</strong>) {t('using only ' +
|
||||
'alphanumeric characters and underscores')}
|
||||
</div>);
|
||||
}
|
||||
});
|
||||
if (this.state.chartType === null) {
|
||||
hints.push('Pick a chart type!');
|
||||
hints.push(VISUALIZE_VALIDATION_ERRORS.REQUIRE_CHART_TYPE);
|
||||
} else if (this.state.chartType.requiresTime) {
|
||||
let hasTime = false;
|
||||
for (const colName in cols) {
|
||||
@@ -89,7 +104,7 @@ class VisualizeModal extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
if (!hasTime) {
|
||||
hints.push('To use this chart type you need at least one column flagged as a date');
|
||||
hints.push(VISUALIZE_VALIDATION_ERRORS.REQUIRE_TIME);
|
||||
}
|
||||
}
|
||||
this.setState({ hints });
|
||||
@@ -108,29 +123,57 @@ class VisualizeModal extends React.PureComponent {
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
visualize() {
|
||||
const vizOptions = {
|
||||
buildVizOptions() {
|
||||
return {
|
||||
chartType: this.state.chartType.value,
|
||||
datasourceName: this.state.datasourceName,
|
||||
columns: this.state.columns,
|
||||
sql: this.props.query.executedSql,
|
||||
sql: this.props.query.sql,
|
||||
dbId: this.props.query.dbId,
|
||||
};
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/superset/sqllab_viz/',
|
||||
async: false,
|
||||
data: {
|
||||
data: JSON.stringify(vizOptions),
|
||||
},
|
||||
success: (url) => {
|
||||
window.open(url);
|
||||
},
|
||||
});
|
||||
}
|
||||
buildVisualizeAdvise() {
|
||||
let advise;
|
||||
const timeout = this.props.timeout;
|
||||
const queryDuration = moment.duration(this.props.query.endDttm - this.props.query.startDttm);
|
||||
if (Math.round(queryDuration.asMilliseconds()) > timeout * 1000) {
|
||||
advise = (
|
||||
<Alert bsStyle="warning">
|
||||
This query took {Math.round(queryDuration.asSeconds())} seconds to run,
|
||||
and the explore view times out at {timeout} seconds,
|
||||
following this flow will most likely lead to your query timing out.
|
||||
We recommend your summarize your data further before following that flow.
|
||||
If activated you can use the <strong>CREATE TABLE AS</strong> feature
|
||||
to store a summarized data set that you can then explore.
|
||||
</Alert>);
|
||||
}
|
||||
return advise;
|
||||
}
|
||||
visualize() {
|
||||
this.props.actions.createDatasource(this.buildVizOptions(), this)
|
||||
.done((resp) => {
|
||||
const columns = Object.keys(this.state.columns).map(k => this.state.columns[k]);
|
||||
const data = JSON.parse(resp);
|
||||
const mainGroupBy = columns.filter(d => d.is_dim)[0];
|
||||
const formData = {
|
||||
datasource: `${data.table_id}__table`,
|
||||
viz_type: this.state.chartType.value,
|
||||
since: '100 years ago',
|
||||
limit: '0',
|
||||
};
|
||||
if (mainGroupBy) {
|
||||
formData.groupby = [mainGroupBy.name];
|
||||
}
|
||||
notify.info(t('Creating a data source and popping a new tab'));
|
||||
|
||||
window.open(getExploreUrl(formData));
|
||||
})
|
||||
.fail(() => {
|
||||
notify.error(this.props.errorMessage);
|
||||
});
|
||||
}
|
||||
changeDatasourceName(event) {
|
||||
this.setState({ datasourceName: event.target.value });
|
||||
this.validate();
|
||||
this.setState({ datasourceName: event.target.value }, this.validate);
|
||||
}
|
||||
changeCheckbox(attr, columnName, event) {
|
||||
let columns = this.mergedColumns();
|
||||
@@ -151,13 +194,13 @@ class VisualizeModal extends React.PureComponent {
|
||||
<div className="VisualizeModal">
|
||||
<Modal show={this.props.show} onHide={this.props.onHide}>
|
||||
<Modal.Body>
|
||||
No results available for this query
|
||||
{t('No results available for this query')}
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const tableData = this.props.query.results.columns.map((col) => ({
|
||||
const tableData = this.props.query.results.columns.map(col => ({
|
||||
column: col.name,
|
||||
is_dimension: (
|
||||
<input
|
||||
@@ -196,16 +239,17 @@ class VisualizeModal extends React.PureComponent {
|
||||
<div className="VisualizeModal">
|
||||
<Modal show={this.props.show} onHide={this.props.onHide}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Visualize</Modal.Title>
|
||||
<Modal.Title>{t('Visualize')}</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
{alerts}
|
||||
{this.buildVisualizeAdvise()}
|
||||
<div className="row">
|
||||
<Col md={6}>
|
||||
Chart Type
|
||||
{t('Chart Type')}
|
||||
<Select
|
||||
name="select-chart-type"
|
||||
placeholder="[Chart Type]"
|
||||
placeholder={t('[Chart Type]')}
|
||||
options={CHART_TYPES}
|
||||
value={(this.state.chartType) ? this.state.chartType.value : null}
|
||||
autosize={false}
|
||||
@@ -213,11 +257,11 @@ class VisualizeModal extends React.PureComponent {
|
||||
/>
|
||||
</Col>
|
||||
<Col md={6}>
|
||||
Datasource Name
|
||||
{t('Datasource Name')}
|
||||
<input
|
||||
type="text"
|
||||
className="form-control input-sm"
|
||||
placeholder="datasource name"
|
||||
placeholder={t('datasource name')}
|
||||
onChange={this.changeDatasourceName.bind(this)}
|
||||
value={this.state.datasourceName}
|
||||
/>
|
||||
@@ -234,7 +278,7 @@ class VisualizeModal extends React.PureComponent {
|
||||
bsStyle="primary"
|
||||
disabled={(this.state.hints.length > 0)}
|
||||
>
|
||||
Visualize
|
||||
{t('Visualize')}
|
||||
</Button>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
@@ -246,4 +290,19 @@ class VisualizeModal extends React.PureComponent {
|
||||
VisualizeModal.propTypes = propTypes;
|
||||
VisualizeModal.defaultProps = defaultProps;
|
||||
|
||||
export default VisualizeModal;
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
datasource: state.datasource,
|
||||
errorMessage: state.errorMessage,
|
||||
timeout: state.common ? state.common.SUPERSET_WEBSERVER_TIMEOUT : null,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export { VisualizeModal };
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(VisualizeModal);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { t } from '../locales';
|
||||
|
||||
export const STATE_BSSTYLE_MAP = {
|
||||
failed: 'danger',
|
||||
pending: 'info',
|
||||
@@ -11,6 +13,7 @@ export const STATUS_OPTIONS = [
|
||||
'success',
|
||||
'failed',
|
||||
'running',
|
||||
'pending',
|
||||
];
|
||||
|
||||
export const TIME_OPTIONS = [
|
||||
@@ -22,3 +25,10 @@ export const TIME_OPTIONS = [
|
||||
'90 days ago',
|
||||
'1 year ago',
|
||||
];
|
||||
|
||||
export const VISUALIZE_VALIDATION_ERRORS = {
|
||||
REQUIRE_CHART_TYPE: t('Pick a chart type!'),
|
||||
REQUIRE_TIME: t('To use this chart type you need at least one column flagged as a date'),
|
||||
REQUIRE_DIMENSION: t('To use this chart type you need at least one dimension'),
|
||||
REQUIRE_AGGREGATION_FUNCTION: t('To use this chart type you need at least one aggregation function'),
|
||||
};
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
const jQuery = window.jQuery = $; // eslint-disable-line
|
||||
require('bootstrap');
|
||||
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { getInitialState, sqlLabReducer } from './reducers';
|
||||
import { initEnhancer } from '../reduxUtils';
|
||||
import { createStore, compose, applyMiddleware } from 'redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
|
||||
import { getInitialState, sqlLabReducer } from './reducers';
|
||||
import { initEnhancer } from '../reduxUtils';
|
||||
import { initJQueryAjax } from '../modules/utils';
|
||||
import App from './components/App';
|
||||
import { appSetup } from '../common';
|
||||
|
||||
import './main.less';
|
||||
import '../../stylesheets/reactable-pagination.css';
|
||||
import '../components/FilterableTable/FilterableTableStyles.css';
|
||||
|
||||
require('./main.css');
|
||||
appSetup();
|
||||
initJQueryAjax();
|
||||
|
||||
const appContainer = document.getElementById('app');
|
||||
const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
|
||||
const state = Object.assign({}, getInitialState(bootstrapData.defaultDbId), bootstrapData);
|
||||
|
||||
let store = createStore(
|
||||
const store = createStore(
|
||||
sqlLabReducer, state, compose(applyMiddleware(thunkMiddleware), initEnhancer()));
|
||||
|
||||
// jquery hack to highlight the navbar menu
|
||||
@@ -29,5 +31,5 @@ render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
appContainer
|
||||
appContainer,
|
||||
);
|
||||
|
||||
@@ -130,9 +130,6 @@ div.Workspace {
|
||||
display: inline-block;
|
||||
background-color: #ccc;
|
||||
}
|
||||
.Pane2 {
|
||||
width: 0;
|
||||
}
|
||||
.running {
|
||||
background-color: lime;
|
||||
color: black;
|
||||
@@ -161,7 +158,6 @@ div.Workspace {
|
||||
margin: 0px;
|
||||
border: none;
|
||||
font-size: 12px;
|
||||
line-height: @line-height-base;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
@@ -237,7 +233,6 @@ div.tablePopover:hover {
|
||||
padding-bottom: 3px;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
.ace_editor {
|
||||
border: 1px solid #ccc;
|
||||
margin: 0px 0px 10px 0px;
|
||||
@@ -266,7 +261,7 @@ div.tablePopover:hover {
|
||||
}
|
||||
|
||||
.QueryTable .label {
|
||||
margin-top: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ResultsModal .modal-body {
|
||||
@@ -294,3 +289,13 @@ a.Link {
|
||||
.tooltip-inner {
|
||||
max-width: 500px;
|
||||
}
|
||||
.SouthPane {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.search-date-filter-container {
|
||||
display: flex;
|
||||
|
||||
.Select {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,13 @@ import shortid from 'shortid';
|
||||
import * as actions from './actions';
|
||||
import { now } from '../modules/dates';
|
||||
import { addToObject, alterInObject, alterInArr, removeFromArr, getFromArr, addToArr }
|
||||
from '../reduxUtils.js';
|
||||
from '../reduxUtils';
|
||||
import { t } from '../locales';
|
||||
|
||||
export function getInitialState(defaultDbId) {
|
||||
const defaultQueryEditor = {
|
||||
id: shortid.generate(),
|
||||
title: 'Untitled Query',
|
||||
title: t('Untitled Query'),
|
||||
sql: 'SELECT *\nFROM\nWHERE',
|
||||
selectedText: null,
|
||||
latestQueryId: null,
|
||||
@@ -17,7 +18,6 @@ export function getInitialState(defaultDbId) {
|
||||
|
||||
return {
|
||||
alerts: [],
|
||||
networkOn: true,
|
||||
queries: {},
|
||||
databases: {},
|
||||
queryEditors: [defaultQueryEditor],
|
||||
@@ -37,11 +37,11 @@ export const sqlLabReducer = function (state, action) {
|
||||
return addToArr(newState, 'queryEditors', action.queryEditor);
|
||||
},
|
||||
[actions.CLONE_QUERY_TO_NEW_TAB]() {
|
||||
const progenitor = state.queryEditors.find((qe) =>
|
||||
const progenitor = state.queryEditors.find(qe =>
|
||||
qe.id === state.tabHistory[state.tabHistory.length - 1]);
|
||||
const qe = {
|
||||
id: shortid.generate(),
|
||||
title: `Copy of ${progenitor.title}`,
|
||||
title: t('Copy of %s', progenitor.title),
|
||||
dbId: (action.query.dbId) ? action.query.dbId : null,
|
||||
schema: (action.query.schema) ? action.query.schema : null,
|
||||
autorun: true,
|
||||
@@ -53,7 +53,7 @@ export const sqlLabReducer = function (state, action) {
|
||||
[actions.REMOVE_QUERY_EDITOR]() {
|
||||
let newState = removeFromArr(state, 'queryEditors', action.queryEditor);
|
||||
// List of remaining queryEditor ids
|
||||
const qeIds = newState.queryEditors.map((qe) => qe.id);
|
||||
const qeIds = newState.queryEditors.map(qe => qe.id);
|
||||
const queries = {};
|
||||
Object.keys(state.queries).forEach((k) => {
|
||||
const query = state.queries[k];
|
||||
@@ -62,7 +62,7 @@ export const sqlLabReducer = function (state, action) {
|
||||
}
|
||||
});
|
||||
let tabHistory = state.tabHistory.slice();
|
||||
tabHistory = tabHistory.filter((id) => qeIds.indexOf(id) > -1);
|
||||
tabHistory = tabHistory.filter(id => qeIds.indexOf(id) > -1);
|
||||
newState = Object.assign({}, newState, { tabHistory, queries });
|
||||
return newState;
|
||||
},
|
||||
@@ -77,13 +77,13 @@ export const sqlLabReducer = function (state, action) {
|
||||
[actions.MERGE_TABLE]() {
|
||||
const at = Object.assign({}, action.table);
|
||||
let existingTable;
|
||||
state.tables.forEach((t) => {
|
||||
state.tables.forEach((xt) => {
|
||||
if (
|
||||
t.dbId === at.dbId &&
|
||||
t.queryEditorId === at.queryEditorId &&
|
||||
t.schema === at.schema &&
|
||||
t.name === at.name) {
|
||||
existingTable = t;
|
||||
xt.dbId === at.dbId &&
|
||||
xt.queryEditorId === at.queryEditorId &&
|
||||
xt.schema === at.schema &&
|
||||
xt.name === at.name) {
|
||||
existingTable = xt;
|
||||
}
|
||||
});
|
||||
if (existingTable) {
|
||||
@@ -116,11 +116,11 @@ export const sqlLabReducer = function (state, action) {
|
||||
delete queries[action.oldQueryId];
|
||||
|
||||
const newTables = [];
|
||||
state.tables.forEach((t) => {
|
||||
if (t.dataPreviewQueryId === action.oldQueryId) {
|
||||
newTables.push(Object.assign({}, t, { dataPreviewQueryId: action.newQuery.id }));
|
||||
state.tables.forEach((xt) => {
|
||||
if (xt.dataPreviewQueryId === action.oldQueryId) {
|
||||
newTables.push(Object.assign({}, xt, { dataPreviewQueryId: action.newQuery.id }));
|
||||
} else {
|
||||
newTables.push(t);
|
||||
newTables.push(xt);
|
||||
}
|
||||
});
|
||||
return Object.assign(
|
||||
@@ -188,7 +188,7 @@ export const sqlLabReducer = function (state, action) {
|
||||
return alterInObject(state, 'queries', action.query, alts);
|
||||
},
|
||||
[actions.SET_ACTIVE_QUERY_EDITOR]() {
|
||||
const qeIds = state.queryEditors.map((qe) => qe.id);
|
||||
const qeIds = state.queryEditors.map(qe => qe.id);
|
||||
if (qeIds.indexOf(action.queryEditor.id) > -1) {
|
||||
const tabHistory = state.tabHistory.slice();
|
||||
tabHistory.push(action.queryEditor.id);
|
||||
@@ -217,6 +217,9 @@ export const sqlLabReducer = function (state, action) {
|
||||
[actions.QUERY_EDITOR_SET_AUTORUN]() {
|
||||
return alterInArr(state, 'queryEditors', action.queryEditor, { autorun: action.autorun });
|
||||
},
|
||||
[actions.QUERY_EDITOR_PERSIST_HEIGHT]() {
|
||||
return alterInArr(state, 'queryEditors', action.queryEditor, { height: action.currentHeight });
|
||||
},
|
||||
[actions.ADD_ALERT]() {
|
||||
return addToArr(state, 'alerts', action.alert);
|
||||
},
|
||||
@@ -230,21 +233,18 @@ export const sqlLabReducer = function (state, action) {
|
||||
[actions.REMOVE_ALERT]() {
|
||||
return removeFromArr(state, 'alerts', action.alert);
|
||||
},
|
||||
[actions.SET_NETWORK_STATUS]() {
|
||||
if (state.networkOn !== action.networkOn) {
|
||||
return Object.assign({}, state, { networkOn: action.networkOn });
|
||||
}
|
||||
return state;
|
||||
},
|
||||
[actions.REFRESH_QUERIES]() {
|
||||
let newQueries = Object.assign({}, state.queries);
|
||||
// Fetch the updates to the queries present in the store.
|
||||
let change = false;
|
||||
let queriesLastUpdate = state.queriesLastUpdate;
|
||||
for (const id in action.alteredQueries) {
|
||||
const changedQuery = action.alteredQueries[id];
|
||||
if (!state.queries.hasOwnProperty(id) ||
|
||||
(state.queries[id].changedOn !== changedQuery.changedOn &&
|
||||
state.queries[id].state !== 'stopped')) {
|
||||
state.queries[id].state !== 'stopped') {
|
||||
if (changedQuery.changedOn > queriesLastUpdate) {
|
||||
queriesLastUpdate = changedQuery.changedOn;
|
||||
}
|
||||
newQueries[id] = Object.assign({}, state.queries[id], changedQuery);
|
||||
change = true;
|
||||
}
|
||||
@@ -252,9 +252,27 @@ export const sqlLabReducer = function (state, action) {
|
||||
if (!change) {
|
||||
newQueries = state.queries;
|
||||
}
|
||||
const queriesLastUpdate = now();
|
||||
return Object.assign({}, state, { queries: newQueries, queriesLastUpdate });
|
||||
},
|
||||
[actions.CREATE_DATASOURCE_STARTED]() {
|
||||
return Object.assign({}, state, {
|
||||
isDatasourceLoading: true,
|
||||
errorMessage: null,
|
||||
});
|
||||
},
|
||||
[actions.CREATE_DATASOURCE_SUCCESS]() {
|
||||
return Object.assign({}, state, {
|
||||
isDatasourceLoading: false,
|
||||
errorMessage: null,
|
||||
datasource: action.datasource,
|
||||
});
|
||||
},
|
||||
[actions.CREATE_DATASOURCE_FAILED]() {
|
||||
return Object.assign({}, state, {
|
||||
isDatasourceLoading: false,
|
||||
errorMessage: action.err,
|
||||
});
|
||||
},
|
||||
};
|
||||
if (action.type in actionHandlers) {
|
||||
return actionHandlers[action.type]();
|
||||
|
||||
99
superset/assets/javascripts/addSlice/AddSliceContainer.jsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Panel, Grid, Row, Col } from 'react-bootstrap';
|
||||
import Select from 'react-virtualized-select';
|
||||
import visTypes from '../explore/stores/visTypes';
|
||||
import { t } from '../locales';
|
||||
|
||||
const propTypes = {
|
||||
datasources: PropTypes.arrayOf(PropTypes.shape({
|
||||
label: PropTypes.string.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
};
|
||||
|
||||
export default class AddSliceContainer extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const visTypeKeys = Object.keys(visTypes);
|
||||
this.vizTypeOptions = visTypeKeys.map(vt => ({ label: visTypes[vt].label, value: vt }));
|
||||
this.state = {
|
||||
visType: 'table',
|
||||
};
|
||||
}
|
||||
|
||||
exploreUrl() {
|
||||
const baseUrl = `/superset/explore/${this.state.datasourceType}/${this.state.datasourceId}`;
|
||||
const formData = encodeURIComponent(JSON.stringify({ viz_type: this.state.visType }));
|
||||
return `${baseUrl}?form_data=${formData}`;
|
||||
}
|
||||
|
||||
gotoSlice() {
|
||||
window.location.href = this.exploreUrl();
|
||||
}
|
||||
|
||||
changeDatasource(e) {
|
||||
this.setState({
|
||||
datasourceValue: e.value,
|
||||
datasourceId: e.value.split('__')[0],
|
||||
datasourceType: e.value.split('__')[1],
|
||||
});
|
||||
}
|
||||
|
||||
changeVisType(e) {
|
||||
this.setState({ visType: e.value });
|
||||
}
|
||||
|
||||
isBtnDisabled() {
|
||||
return !(this.state.datasourceId && this.state.visType);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="container">
|
||||
<Panel header={<h3>{t('Create a new slice')}</h3>}>
|
||||
<Grid>
|
||||
<Row>
|
||||
<Col xs={12} sm={6}>
|
||||
<div>
|
||||
<p>{t('Choose a datasource')}</p>
|
||||
<Select
|
||||
clearable={false}
|
||||
name="select-datasource"
|
||||
onChange={this.changeDatasource.bind(this)}
|
||||
options={this.props.datasources}
|
||||
placeholder={t('Choose a datasource')}
|
||||
value={this.state.datasourceValue}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<p>{t('Choose a visualization type')}</p>
|
||||
<Select
|
||||
clearable={false}
|
||||
name="select-vis-type"
|
||||
onChange={this.changeVisType.bind(this)}
|
||||
options={this.vizTypeOptions}
|
||||
placeholder={t('Choose a visualization type')}
|
||||
value={this.state.visType}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<Button
|
||||
bsStyle="primary"
|
||||
disabled={this.isBtnDisabled()}
|
||||
onClick={this.gotoSlice.bind(this)}
|
||||
>
|
||||
{t('Create new slice')}
|
||||
</Button>
|
||||
<br /><br />
|
||||
</Col>
|
||||
</Row>
|
||||
</Grid>
|
||||
</Panel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AddSliceContainer.propTypes = propTypes;
|
||||
14
superset/assets/javascripts/addSlice/index.jsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { appSetup } from '../common';
|
||||
import AddSliceContainer from './AddSliceContainer';
|
||||
|
||||
appSetup();
|
||||
|
||||
const addSliceContainer = document.getElementById('js-add-slice-container');
|
||||
const bootstrapData = JSON.parse(addSliceContainer.getAttribute('data-bootstrap'));
|
||||
|
||||
ReactDOM.render(
|
||||
<AddSliceContainer datasources={bootstrapData.datasources} />,
|
||||
addSliceContainer,
|
||||
);
|
||||
182
superset/assets/javascripts/chart/Chart.jsx
Normal file
@@ -0,0 +1,182 @@
|
||||
/* eslint camelcase: 0 */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Mustache from 'mustache';
|
||||
|
||||
import { d3format } from '../modules/utils';
|
||||
import ChartBody from './ChartBody';
|
||||
import Loading from '../components/Loading';
|
||||
import StackTraceMessage from '../components/StackTraceMessage';
|
||||
import visMap from '../../visualizations/main';
|
||||
|
||||
const propTypes = {
|
||||
actions: PropTypes.object,
|
||||
chartKey: PropTypes.string.isRequired,
|
||||
containerId: PropTypes.string.isRequired,
|
||||
datasource: PropTypes.object.isRequired,
|
||||
formData: PropTypes.object.isRequired,
|
||||
height: PropTypes.number,
|
||||
width: PropTypes.number,
|
||||
setControlValue: PropTypes.func,
|
||||
timeout: PropTypes.number,
|
||||
vizType: PropTypes.string.isRequired,
|
||||
// state
|
||||
chartAlert: PropTypes.string,
|
||||
chartStatus: PropTypes.string,
|
||||
chartUpdateEndTime: PropTypes.number,
|
||||
chartUpdateStartTime: PropTypes.number,
|
||||
latestQueryFormData: PropTypes.object,
|
||||
queryRequest: PropTypes.object,
|
||||
queryResponse: PropTypes.object,
|
||||
lastRendered: PropTypes.number,
|
||||
triggerQuery: PropTypes.bool,
|
||||
// dashboard callbacks
|
||||
addFilter: PropTypes.func,
|
||||
getFilters: PropTypes.func,
|
||||
clearFilter: PropTypes.func,
|
||||
removeFilter: PropTypes.func,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
addFilter: () => ({}),
|
||||
getFilters: () => ({}),
|
||||
clearFilter: () => ({}),
|
||||
removeFilter: () => ({}),
|
||||
};
|
||||
|
||||
class Chart extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// these properties are used by visualizations
|
||||
this.containerId = props.containerId;
|
||||
this.selector = `#${this.containerId}`;
|
||||
this.formData = props.formData;
|
||||
this.datasource = props.datasource;
|
||||
this.addFilter = this.addFilter.bind(this);
|
||||
this.getFilters = this.getFilters.bind(this);
|
||||
this.clearFilter = this.clearFilter.bind(this);
|
||||
this.removeFilter = this.removeFilter.bind(this);
|
||||
this.height = this.height.bind(this);
|
||||
this.width = this.width.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.triggerQuery) {
|
||||
this.props.actions.runQuery(this.props.formData, false,
|
||||
this.props.timeout,
|
||||
this.props.chartKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.containerId = nextProps.containerId;
|
||||
this.selector = `#${this.containerId}`;
|
||||
this.formData = nextProps.formData;
|
||||
this.datasource = nextProps.datasource;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (
|
||||
this.props.queryResponse &&
|
||||
this.props.chartStatus === 'success' &&
|
||||
!this.props.queryResponse.error && (
|
||||
prevProps.queryResponse !== this.props.queryResponse ||
|
||||
prevProps.height !== this.props.height ||
|
||||
prevProps.width !== this.props.width ||
|
||||
prevProps.lastRendered !== this.props.lastRendered)
|
||||
) {
|
||||
this.renderViz();
|
||||
}
|
||||
}
|
||||
|
||||
getFilters() {
|
||||
return this.props.getFilters();
|
||||
}
|
||||
|
||||
addFilter(col, vals, merge = true, refresh = true) {
|
||||
this.props.addFilter(col, vals, merge, refresh);
|
||||
}
|
||||
|
||||
clearFilter() {
|
||||
this.props.clearFilter();
|
||||
}
|
||||
|
||||
removeFilter(col, vals) {
|
||||
this.props.removeFilter(col, vals);
|
||||
}
|
||||
|
||||
clearError() {
|
||||
this.setState({
|
||||
errorMsg: null,
|
||||
});
|
||||
}
|
||||
|
||||
width() {
|
||||
return this.props.width || this.container.el.offsetWidth;
|
||||
}
|
||||
|
||||
height() {
|
||||
return this.props.height || this.container.el.offsetHeight;
|
||||
}
|
||||
|
||||
d3format(col, number) {
|
||||
const { datasource } = this.props;
|
||||
const format = (datasource.column_formats && datasource.column_formats[col]) || '0.3s';
|
||||
|
||||
return d3format(format, number);
|
||||
}
|
||||
|
||||
render_template(s) {
|
||||
const context = {
|
||||
width: this.width(),
|
||||
height: this.height(),
|
||||
};
|
||||
return Mustache.render(s, context);
|
||||
}
|
||||
|
||||
renderViz() {
|
||||
const viz = visMap[this.props.vizType];
|
||||
try {
|
||||
viz(this, this.props.queryResponse, this.props.actions.setControlValue);
|
||||
} catch (e) {
|
||||
this.props.actions.chartRenderingFailed(e, this.props.chartKey);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const isLoading = this.props.chartStatus === 'loading';
|
||||
return (
|
||||
<div className={`token col-md-12 ${isLoading ? 'is-loading' : ''}`}>
|
||||
{isLoading &&
|
||||
<Loading size={25} />
|
||||
}
|
||||
|
||||
{this.props.chartAlert &&
|
||||
<StackTraceMessage
|
||||
message={this.props.chartAlert}
|
||||
queryResponse={this.props.queryResponse}
|
||||
/>
|
||||
}
|
||||
|
||||
{!this.props.chartAlert &&
|
||||
<ChartBody
|
||||
containerId={this.containerId}
|
||||
vizType={this.props.formData.viz_type}
|
||||
height={this.height}
|
||||
width={this.width}
|
||||
ref={(inner) => {
|
||||
this.container = inner;
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Chart.propTypes = propTypes;
|
||||
Chart.defaultProps = defaultProps;
|
||||
|
||||
export default Chart;
|
||||
54
superset/assets/javascripts/chart/ChartBody.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import $ from 'jquery';
|
||||
|
||||
const propTypes = {
|
||||
containerId: PropTypes.string.isRequired,
|
||||
vizType: PropTypes.string.isRequired,
|
||||
height: PropTypes.func.isRequired,
|
||||
width: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class ChartBody extends React.PureComponent {
|
||||
html(data) {
|
||||
this.el.innerHTML = data;
|
||||
}
|
||||
|
||||
css(property, value) {
|
||||
this.el.style[property] = value;
|
||||
}
|
||||
|
||||
get(n) {
|
||||
return $(this.el).get(n);
|
||||
}
|
||||
|
||||
find(classname) {
|
||||
return $(this.el).find(classname);
|
||||
}
|
||||
|
||||
show() {
|
||||
return $(this.el).show();
|
||||
}
|
||||
|
||||
height() {
|
||||
return this.props.height();
|
||||
}
|
||||
|
||||
width() {
|
||||
return this.props.width();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
id={this.props.containerId}
|
||||
className={`slice_container ${this.props.vizType}`}
|
||||
ref={(el) => { this.el = el; }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ChartBody.propTypes = propTypes;
|
||||
|
||||
export default ChartBody;
|
||||
28
superset/assets/javascripts/chart/ChartContainer.jsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import * as Actions from './chartAction';
|
||||
import Chart from './Chart';
|
||||
|
||||
function mapStateToProps({ charts }, ownProps) {
|
||||
const chart = charts[ownProps.chartKey];
|
||||
return {
|
||||
chartAlert: chart.chartAlert,
|
||||
chartStatus: chart.chartStatus,
|
||||
chartUpdateEndTime: chart.chartUpdateEndTime,
|
||||
chartUpdateStartTime: chart.chartUpdateStartTime,
|
||||
latestQueryFormData: chart.latestQueryFormData,
|
||||
lastRendered: chart.lastRendered,
|
||||
queryResponse: chart.queryResponse,
|
||||
queryRequest: chart.queryRequest,
|
||||
triggerQuery: chart.triggerQuery,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Chart);
|
||||
91
superset/assets/javascripts/chart/chartAction.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import { getExploreUrl } from '../explore/exploreUtils';
|
||||
import { t } from '../locales';
|
||||
|
||||
const $ = window.$ = require('jquery');
|
||||
|
||||
export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED';
|
||||
export function chartUpdateStarted(queryRequest, key) {
|
||||
return { type: CHART_UPDATE_STARTED, queryRequest, key };
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_SUCCEEDED = 'CHART_UPDATE_SUCCEEDED';
|
||||
export function chartUpdateSucceeded(queryResponse, key) {
|
||||
return { type: CHART_UPDATE_SUCCEEDED, queryResponse, key };
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_STOPPED = 'CHART_UPDATE_STOPPED';
|
||||
export function chartUpdateStopped(queryRequest, key) {
|
||||
if (queryRequest) {
|
||||
queryRequest.abort();
|
||||
}
|
||||
return { type: CHART_UPDATE_STOPPED, key };
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_TIMEOUT = 'CHART_UPDATE_TIMEOUT';
|
||||
export function chartUpdateTimeout(statusText, timeout, key) {
|
||||
return { type: CHART_UPDATE_TIMEOUT, statusText, timeout, key };
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED';
|
||||
export function chartUpdateFailed(queryResponse, key) {
|
||||
return { type: CHART_UPDATE_FAILED, queryResponse, key };
|
||||
}
|
||||
|
||||
export const CHART_RENDERING_FAILED = 'CHART_RENDERING_FAILED';
|
||||
export function chartRenderingFailed(error, key) {
|
||||
return { type: CHART_RENDERING_FAILED, error, key };
|
||||
}
|
||||
|
||||
export const REMOVE_CHART = 'REMOVE_CHART';
|
||||
export function removeChart(key) {
|
||||
return { type: REMOVE_CHART, key };
|
||||
}
|
||||
|
||||
export const TRIGGER_QUERY = 'TRIGGER_QUERY';
|
||||
export function triggerQuery(value = true, key) {
|
||||
return { type: TRIGGER_QUERY, value, key };
|
||||
}
|
||||
|
||||
// this action is used for forced re-render without fetch data
|
||||
export const RENDER_TRIGGERED = 'RENDER_TRIGGERED';
|
||||
export function renderTriggered(value, key) {
|
||||
return { type: RENDER_TRIGGERED, value, key };
|
||||
}
|
||||
|
||||
export const RUN_QUERY = 'RUN_QUERY';
|
||||
export function runQuery(formData, force = false, timeout = 60, key) {
|
||||
return (dispatch) => {
|
||||
const url = getExploreUrl(formData, 'json', force);
|
||||
const queryRequest = $.ajax({
|
||||
url,
|
||||
dataType: 'json',
|
||||
timeout: timeout * 1000,
|
||||
success: (queryResponse =>
|
||||
dispatch(chartUpdateSucceeded(queryResponse, key))
|
||||
),
|
||||
error: ((xhr) => {
|
||||
if (xhr.statusText === 'timeout') {
|
||||
dispatch(chartUpdateTimeout(xhr.statusText, timeout, key));
|
||||
} else {
|
||||
let error = '';
|
||||
if (!xhr.responseText) {
|
||||
const status = xhr.status;
|
||||
if (status === 0) {
|
||||
// This may happen when the worker in gunicorn times out
|
||||
error += (
|
||||
t('The server could not be reached. You may want to ' +
|
||||
'verify your connection and try again.'));
|
||||
} else {
|
||||
error += (t('An unknown error occurred. (Status: %s )', status));
|
||||
}
|
||||
}
|
||||
const errorResponse = Object.assign({}, xhr.responseJSON, error);
|
||||
dispatch(chartUpdateFailed(errorResponse, key));
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
dispatch(chartUpdateStarted(queryRequest, key));
|
||||
dispatch(triggerQuery(false, key));
|
||||
};
|
||||
}
|
||||
103
superset/assets/javascripts/chart/chartReducer.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/* eslint camelcase: 0 */
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { now } from '../modules/dates';
|
||||
import * as actions from './chartAction';
|
||||
import { t } from '../locales';
|
||||
|
||||
export const chartPropType = {
|
||||
chartKey: PropTypes.string.isRequired,
|
||||
chartAlert: PropTypes.string,
|
||||
chartStatus: PropTypes.string,
|
||||
chartUpdateEndTime: PropTypes.number,
|
||||
chartUpdateStartTime: PropTypes.number,
|
||||
latestQueryFormData: PropTypes.object,
|
||||
queryRequest: PropTypes.object,
|
||||
queryResponse: PropTypes.object,
|
||||
triggerQuery: PropTypes.bool,
|
||||
lastRendered: PropTypes.number,
|
||||
};
|
||||
|
||||
export const chart = {
|
||||
chartKey: '',
|
||||
chartAlert: null,
|
||||
chartStatus: 'loading',
|
||||
chartUpdateEndTime: null,
|
||||
chartUpdateStartTime: now(),
|
||||
latestQueryFormData: null,
|
||||
queryRequest: null,
|
||||
queryResponse: null,
|
||||
triggerQuery: true,
|
||||
lastRendered: 0,
|
||||
};
|
||||
|
||||
export default function chartReducer(charts = {}, action) {
|
||||
const actionHandlers = {
|
||||
[actions.CHART_UPDATE_SUCCEEDED](state) {
|
||||
return { ...state,
|
||||
chartStatus: 'success',
|
||||
queryResponse: action.queryResponse,
|
||||
chartUpdateEndTime: now(),
|
||||
};
|
||||
},
|
||||
[actions.CHART_UPDATE_STARTED](state) {
|
||||
return { ...state,
|
||||
chartStatus: 'loading',
|
||||
chartAlert: null,
|
||||
chartUpdateEndTime: null,
|
||||
chartUpdateStartTime: now(),
|
||||
queryRequest: action.queryRequest,
|
||||
};
|
||||
},
|
||||
[actions.CHART_UPDATE_STOPPED](state) {
|
||||
return { ...state,
|
||||
chartStatus: 'stopped',
|
||||
chartAlert: t('Updating chart was stopped'),
|
||||
};
|
||||
},
|
||||
[actions.CHART_RENDERING_FAILED](state) {
|
||||
return { ...state,
|
||||
chartStatus: 'failed',
|
||||
chartAlert: t('An error occurred while rendering the visualization: %s', action.error),
|
||||
};
|
||||
},
|
||||
[actions.CHART_UPDATE_TIMEOUT](state) {
|
||||
return { ...state,
|
||||
chartStatus: 'failed',
|
||||
chartAlert: (
|
||||
`<strong>${t('Query timeout')}</strong> - ` +
|
||||
t(`visualization queries are set to timeout at ${action.timeout} seconds. `) +
|
||||
t('Perhaps your data has grown, your database is under unusual load, ' +
|
||||
'or you are simply querying a data source that is too large ' +
|
||||
'to be processed within the timeout range. ' +
|
||||
'If that is the case, we recommend that you summarize your data further.')),
|
||||
};
|
||||
},
|
||||
[actions.CHART_UPDATE_FAILED](state) {
|
||||
return { ...state,
|
||||
chartStatus: 'failed',
|
||||
chartAlert: action.queryResponse ? action.queryResponse.error : t('Network error.'),
|
||||
chartUpdateEndTime: now(),
|
||||
queryResponse: action.queryResponse,
|
||||
};
|
||||
},
|
||||
[actions.TRIGGER_QUERY](state) {
|
||||
return { ...state, triggerQuery: action.value };
|
||||
},
|
||||
[actions.RENDER_TRIGGERED](state) {
|
||||
return { ...state, lastRendered: action.value };
|
||||
},
|
||||
};
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
if (action.type === actions.REMOVE_CHART) {
|
||||
delete charts[action.key];
|
||||
return charts;
|
||||
}
|
||||
|
||||
if (action.type in actionHandlers) {
|
||||
return { ...charts, [action.key]: actionHandlers[action.type](charts[action.key], action) };
|
||||
}
|
||||
|
||||
return charts;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
const $ = require('jquery');
|
||||
/* eslint-disable global-require */
|
||||
import $ from 'jquery';
|
||||
|
||||
const utils = require('./modules/utils');
|
||||
|
||||
$(document).ready(function () {
|
||||
$(':checkbox[data-checkbox-api-prefix]').change(function () {
|
||||
const $this = $(this);
|
||||
@@ -7,4 +10,23 @@ $(document).ready(function () {
|
||||
const id = $this.attr('id');
|
||||
utils.toggleCheckbox(prefix, '#' + id);
|
||||
});
|
||||
|
||||
// for language picker dropdown
|
||||
$('#language-picker a').click(function (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
const targetUrl = ev.currentTarget.href;
|
||||
$.ajax(targetUrl)
|
||||
.then(() => {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export function appSetup() {
|
||||
// A set of hacks to allow apps to run within a FAB template
|
||||
// this allows for the server side generated menus to function
|
||||
window.$ = $;
|
||||
window.jQuery = $;
|
||||
require('bootstrap');
|
||||
}
|
||||
|
||||
38
superset/assets/javascripts/components/AlertsWrapper.jsx
Normal file
@@ -0,0 +1,38 @@
|
||||
/* global notify */
|
||||
import React from 'react';
|
||||
import AlertContainer from 'react-alert';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const propTypes = {
|
||||
initMessages: PropTypes.array,
|
||||
};
|
||||
const defaultProps = {
|
||||
initMessages: [],
|
||||
};
|
||||
|
||||
export default class AlertsWrapper extends React.PureComponent {
|
||||
componentDidMount() {
|
||||
this.props.initMessages.forEach((msg) => {
|
||||
if (['info', 'error', 'success'].indexOf(msg[0]) >= 0) {
|
||||
notify[msg[0]](msg[1]);
|
||||
} else {
|
||||
notify.show(msg[1]);
|
||||
}
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<AlertContainer
|
||||
ref={(ref) => {
|
||||
global.notify = ref;
|
||||
}}
|
||||
offset={14}
|
||||
position="top right"
|
||||
theme="dark"
|
||||
time={5000}
|
||||
transition="fade"
|
||||
/>);
|
||||
}
|
||||
}
|
||||
AlertsWrapper.propTypes = propTypes;
|
||||
AlertsWrapper.defaultProps = defaultProps;
|
||||
145
superset/assets/javascripts/components/AlteredSliceTag.jsx
Normal file
@@ -0,0 +1,145 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Table, Tr, Td, Thead, Th } from 'reactable';
|
||||
import { isEqual, isEmpty } from 'underscore';
|
||||
|
||||
import TooltipWrapper from './TooltipWrapper';
|
||||
import { controls } from '../explore/stores/controls';
|
||||
import ModalTrigger from './ModalTrigger';
|
||||
import { t } from '../locales';
|
||||
|
||||
const propTypes = {
|
||||
origFormData: PropTypes.object.isRequired,
|
||||
currentFormData: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default class AlteredSliceTag extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const diffs = this.getDiffs(props);
|
||||
this.state = { diffs, hasDiffs: !isEmpty(diffs) };
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps) {
|
||||
// Update differences if need be
|
||||
if (isEqual(this.props, newProps)) {
|
||||
return;
|
||||
}
|
||||
const diffs = this.getDiffs(newProps);
|
||||
this.setState({ diffs, hasDiffs: !isEmpty(diffs) });
|
||||
}
|
||||
|
||||
getDiffs(props) {
|
||||
// Returns all properties that differ in the
|
||||
// current form data and the saved form data
|
||||
const ofd = props.origFormData;
|
||||
const cfd = props.currentFormData;
|
||||
const fdKeys = Object.keys(cfd);
|
||||
const diffs = {};
|
||||
for (const fdKey of fdKeys) {
|
||||
// Ignore values that are undefined/nonexisting in either
|
||||
if (!ofd[fdKey] && !cfd[fdKey]) {
|
||||
continue;
|
||||
}
|
||||
if (!isEqual(ofd[fdKey], cfd[fdKey])) {
|
||||
diffs[fdKey] = { before: ofd[fdKey], after: cfd[fdKey] };
|
||||
}
|
||||
}
|
||||
return diffs;
|
||||
}
|
||||
|
||||
formatValue(value, key) {
|
||||
// Format display value based on the control type
|
||||
// or the value type
|
||||
if (value === undefined) {
|
||||
return 'N/A';
|
||||
} else if (value === null) {
|
||||
return 'null';
|
||||
} else if (controls[key] && controls[key].type === 'FilterControl') {
|
||||
if (!value.length) {
|
||||
return '[]';
|
||||
}
|
||||
return value.map((v) => {
|
||||
const filterVal = v.val.constructor === Array ? `[${v.val.join(', ')}]` : v.val;
|
||||
return `${v.col} ${v.op} ${filterVal}`;
|
||||
}).join(', ');
|
||||
} else if (controls[key] && controls[key].type === 'BoundsControl') {
|
||||
return `Min: ${value[0]}, Max: ${value[1]}`;
|
||||
} else if (controls[key] && controls[key].type === 'CollectionControl') {
|
||||
return value.map(v => JSON.stringify(v)).join(', ');
|
||||
} else if (typeof value === 'boolean') {
|
||||
return value ? 'true' : 'false';
|
||||
} else if (value.constructor === Array) {
|
||||
return value.length ? value.join(', ') : '[]';
|
||||
} else if (typeof value === 'string' || typeof value === 'number') {
|
||||
return value;
|
||||
}
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
renderRows() {
|
||||
const diffs = this.state.diffs;
|
||||
const rows = [];
|
||||
for (const key in diffs) {
|
||||
rows.push(
|
||||
<Tr key={key}>
|
||||
<Td column="control" data={(controls[key] && controls[key].label) || key} />
|
||||
<Td column="before">{this.formatValue(diffs[key].before, key)}</Td>
|
||||
<Td column="after">{this.formatValue(diffs[key].after, key)}</Td>
|
||||
</Tr>,
|
||||
);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
renderModalBody() {
|
||||
return (
|
||||
<Table className="table" sortable>
|
||||
<Thead>
|
||||
<Th column="control">Control</Th>
|
||||
<Th column="before">Before</Th>
|
||||
<Th column="after">After</Th>
|
||||
</Thead>
|
||||
{this.renderRows()}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
renderTriggerNode() {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
label="difference"
|
||||
tooltip={t('Click to see difference')}
|
||||
>
|
||||
<span
|
||||
className="label label-warning m-l-5"
|
||||
style={{ fontSize: '12px' }}
|
||||
>
|
||||
{t('Altered')}
|
||||
</span>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
// Return nothing if there are no differences
|
||||
if (!this.state.hasDiffs) {
|
||||
return null;
|
||||
}
|
||||
// Render the label-warning 'Altered' tag which the user may
|
||||
// click to open a modal containing a table summarizing the
|
||||
// differences in the slice
|
||||
return (
|
||||
<ModalTrigger
|
||||
animation
|
||||
triggerNode={this.renderTriggerNode()}
|
||||
modalTitle={t('Slice changes')}
|
||||
bsSize="large"
|
||||
modalBody={this.renderModalBody()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AlteredSliceTag.propTypes = propTypes;
|
||||
@@ -1,19 +1,28 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Select from 'react-select';
|
||||
import { t } from '../locales';
|
||||
|
||||
const $ = window.$ = require('jquery');
|
||||
|
||||
const propTypes = {
|
||||
dataEndpoint: React.PropTypes.string.isRequired,
|
||||
onChange: React.PropTypes.func.isRequired,
|
||||
mutator: React.PropTypes.func.isRequired,
|
||||
value: React.PropTypes.number,
|
||||
valueRenderer: React.PropTypes.func,
|
||||
placeholder: React.PropTypes.string,
|
||||
dataEndpoint: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
mutator: PropTypes.func.isRequired,
|
||||
onAsyncError: PropTypes.func,
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
]),
|
||||
valueRenderer: PropTypes.func,
|
||||
placeholder: PropTypes.string,
|
||||
autoSelect: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
placeholder: 'Select ...',
|
||||
valueRenderer: (o) => (<div>{o.label}</div>),
|
||||
placeholder: t('Select ...'),
|
||||
valueRenderer: o => (<div>{o.label}</div>),
|
||||
onAsyncError: () => {},
|
||||
};
|
||||
|
||||
class AsyncSelect extends React.PureComponent {
|
||||
@@ -27,15 +36,26 @@ class AsyncSelect extends React.PureComponent {
|
||||
componentDidMount() {
|
||||
this.fetchOptions();
|
||||
}
|
||||
onChange(opt) {
|
||||
this.props.onChange(opt);
|
||||
}
|
||||
fetchOptions() {
|
||||
this.setState({ isLoading: true });
|
||||
const mutator = this.props.mutator;
|
||||
$.get(this.props.dataEndpoint, (data) => {
|
||||
this.setState({ options: mutator ? mutator(data) : data, isLoading: false });
|
||||
});
|
||||
}
|
||||
onChange(opt) {
|
||||
this.props.onChange(opt);
|
||||
$.get(this.props.dataEndpoint)
|
||||
.done((data) => {
|
||||
this.setState({ options: mutator ? mutator(data) : data, isLoading: false });
|
||||
|
||||
if (!this.props.value && this.props.autoSelect && this.state.options.length) {
|
||||
this.onChange(this.state.options[0]);
|
||||
}
|
||||
})
|
||||
.fail((xhr) => {
|
||||
this.props.onAsyncError(xhr.responseText);
|
||||
})
|
||||
.always(() => {
|
||||
this.setState({ isLoading: false });
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@@ -47,6 +67,7 @@ class AsyncSelect extends React.PureComponent {
|
||||
isLoading={this.state.isLoading}
|
||||
onChange={this.onChange.bind(this)}
|
||||
valueRenderer={this.props.valueRenderer}
|
||||
{...this.props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button as BootstrapButton, Tooltip, OverlayTrigger } from 'react-bootstrap';
|
||||
import { slugify } from '../modules/utils';
|
||||
|
||||
|
||||
70
superset/assets/javascripts/components/CachedLabel.jsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Label } from 'react-bootstrap';
|
||||
import moment from 'moment';
|
||||
import TooltipWrapper from './TooltipWrapper';
|
||||
import { t } from '../locales';
|
||||
|
||||
const propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
cachedTimestamp: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
class CacheLabel extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
tooltipContent: '',
|
||||
hovered: false,
|
||||
};
|
||||
}
|
||||
|
||||
updateTooltipContent() {
|
||||
const cachedText = this.props.cachedTimestamp ? (
|
||||
<span>
|
||||
{t('Loaded data cached')}
|
||||
<b> {moment.utc(this.props.cachedTimestamp).fromNow()}</b>
|
||||
</span>) :
|
||||
t('Loaded from cache');
|
||||
|
||||
const tooltipContent = (
|
||||
<span>
|
||||
{cachedText}. {t('Click to force-refresh')}
|
||||
</span>
|
||||
);
|
||||
this.setState({ tooltipContent });
|
||||
}
|
||||
|
||||
mouseOver() {
|
||||
this.updateTooltipContent();
|
||||
this.setState({ hovered: true });
|
||||
}
|
||||
|
||||
mouseOut() {
|
||||
this.setState({ hovered: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const labelStyle = this.state.hovered ? 'primary' : 'default';
|
||||
return (
|
||||
<TooltipWrapper
|
||||
tooltip={this.state.tooltipContent}
|
||||
label="cache-desc"
|
||||
>
|
||||
<Label
|
||||
className={this.props.className}
|
||||
bsStyle={labelStyle}
|
||||
style={{ fontSize: '10px', marginRight: '5px', cursor: 'pointer' }}
|
||||
onClick={this.props.onClick}
|
||||
onMouseOver={this.mouseOver.bind(this)}
|
||||
onMouseOut={this.mouseOut.bind(this)}
|
||||
>
|
||||
cached <i className="fa fa-refresh" />
|
||||
</Label>
|
||||
</TooltipWrapper>);
|
||||
}
|
||||
}
|
||||
CacheLabel.propTypes = propTypes;
|
||||
|
||||
export default CacheLabel;
|
||||
24
superset/assets/javascripts/components/Checkbox.jsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const propTypes = {
|
||||
checked: PropTypes.bool.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
export default function Checkbox({ checked, onChange, style }) {
|
||||
return (
|
||||
<span style={style}>
|
||||
<i
|
||||
className={`fa fa-check ${checked ? 'text-primary' : 'text-transparent'}`}
|
||||
onClick={onChange.bind(!checked)}
|
||||
style={{
|
||||
border: '1px solid #aaa',
|
||||
borderRadius: '2px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
/>
|
||||
</span>);
|
||||
}
|
||||
Checkbox.propTypes = propTypes;
|
||||
34
superset/assets/javascripts/components/ColumnOption.jsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import InfoTooltipWithTrigger from './InfoTooltipWithTrigger';
|
||||
|
||||
const propTypes = {
|
||||
column: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default function ColumnOption({ column }) {
|
||||
return (
|
||||
<span>
|
||||
<span className="m-r-5 option-label">
|
||||
{column.verbose_name || column.column_name}
|
||||
</span>
|
||||
{column.description &&
|
||||
<InfoTooltipWithTrigger
|
||||
className="m-r-5 text-muted"
|
||||
icon="info"
|
||||
tooltip={column.description}
|
||||
label={`descr-${column.column_name}`}
|
||||
/>
|
||||
}
|
||||
{column.expression && column.expression !== column.column_name &&
|
||||
<InfoTooltipWithTrigger
|
||||
className="m-r-5 text-muted"
|
||||
icon="question-circle-o"
|
||||
tooltip={column.expression}
|
||||
label={`expr-${column.column_name}`}
|
||||
/>
|
||||
}
|
||||
</span>);
|
||||
}
|
||||
ColumnOption.propTypes = propTypes;
|
||||
@@ -1,5 +1,7 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Tooltip, OverlayTrigger, MenuItem } from 'react-bootstrap';
|
||||
import { t } from '../locales';
|
||||
|
||||
const propTypes = {
|
||||
copyNode: PropTypes.node,
|
||||
@@ -16,7 +18,7 @@ const defaultProps = {
|
||||
onCopyEnd: () => {},
|
||||
shouldShowText: true,
|
||||
inMenu: false,
|
||||
tooltipText: 'Copy to clipboard',
|
||||
tooltipText: t('Copy to clipboard'),
|
||||
};
|
||||
|
||||
export default class CopyToClipboard extends React.Component {
|
||||
@@ -50,6 +52,10 @@ export default class CopyToClipboard extends React.Component {
|
||||
}
|
||||
|
||||
copyToClipboard(textToCopy) {
|
||||
const selection = document.getSelection();
|
||||
selection.removeAllRanges();
|
||||
document.activeElement.blur();
|
||||
const range = document.createRange();
|
||||
const textArea = document.createElement('textarea');
|
||||
|
||||
textArea.style.position = 'fixed';
|
||||
@@ -57,16 +63,22 @@ export default class CopyToClipboard extends React.Component {
|
||||
textArea.value = textToCopy;
|
||||
|
||||
document.body.appendChild(textArea);
|
||||
textArea.select();
|
||||
range.selectNode(textArea);
|
||||
selection.addRange(range);
|
||||
try {
|
||||
if (!document.execCommand('copy')) {
|
||||
throw new Error('Not successful');
|
||||
throw new Error(t('Not successful'));
|
||||
}
|
||||
} catch (err) {
|
||||
window.alert('Sorry, your browser does not support copying. Use Ctrl / Cmd + C!'); // eslint-disable-line
|
||||
window.alert(t('Sorry, your browser does not support copying. Use Ctrl / Cmd + C!')); // eslint-disable-line
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
if (selection.removeRange) {
|
||||
selection.removeRange(range);
|
||||
} else {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
|
||||
this.setState({ hasCopied: true });
|
||||
this.props.onCopyEnd();
|
||||
@@ -74,7 +86,7 @@ export default class CopyToClipboard extends React.Component {
|
||||
|
||||
tooltipText() {
|
||||
if (this.state.hasCopied) {
|
||||
return 'Copied!';
|
||||
return t('Copied!');
|
||||
}
|
||||
return this.props.tooltipText;
|
||||
}
|
||||
@@ -97,7 +109,7 @@ export default class CopyToClipboard extends React.Component {
|
||||
onClick={this.onClick.bind(this)}
|
||||
onMouseOut={this.onMouseOut}
|
||||
>
|
||||
{this.props.copyNode}
|
||||
{this.props.copyNode}
|
||||
</OverlayTrigger>
|
||||
</span>
|
||||
);
|
||||
|
||||
112
superset/assets/javascripts/components/EditableTitle.jsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import TooltipWrapper from './TooltipWrapper';
|
||||
import { t } from '../locales';
|
||||
|
||||
const propTypes = {
|
||||
title: PropTypes.string,
|
||||
canEdit: PropTypes.bool,
|
||||
onSaveTitle: PropTypes.func,
|
||||
noPermitTooltip: PropTypes.string,
|
||||
};
|
||||
const defaultProps = {
|
||||
title: t('Title'),
|
||||
canEdit: false,
|
||||
};
|
||||
|
||||
class EditableTitle extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isEditing: false,
|
||||
title: this.props.title,
|
||||
lastTitle: this.props.title,
|
||||
};
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleBlur = this.handleBlur.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.title !== this.state.title) {
|
||||
this.setState({
|
||||
lastTitle: this.state.title,
|
||||
title: nextProps.title,
|
||||
});
|
||||
}
|
||||
}
|
||||
handleClick() {
|
||||
if (!this.props.canEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isEditing: true,
|
||||
});
|
||||
}
|
||||
handleBlur() {
|
||||
if (!this.props.canEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isEditing: false,
|
||||
});
|
||||
|
||||
if (!this.state.title.length) {
|
||||
this.setState({
|
||||
title: this.state.lastTitle,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.lastTitle !== this.state.title) {
|
||||
this.setState({
|
||||
lastTitle: this.state.title,
|
||||
});
|
||||
this.props.onSaveTitle(this.state.title);
|
||||
}
|
||||
}
|
||||
handleChange(ev) {
|
||||
if (!this.props.canEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
title: ev.target.value,
|
||||
});
|
||||
}
|
||||
handleKeyPress(ev) {
|
||||
if (ev.key === 'Enter') {
|
||||
ev.preventDefault();
|
||||
|
||||
this.handleBlur();
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<span className="editable-title">
|
||||
<TooltipWrapper
|
||||
label="title"
|
||||
tooltip={this.props.canEdit ? t('click to edit title') :
|
||||
this.props.noPermitTooltip || t('You don\'t have the rights to alter this title.')}
|
||||
>
|
||||
<input
|
||||
required
|
||||
type={this.state.isEditing ? 'text' : 'button'}
|
||||
value={this.state.title}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.handleBlur}
|
||||
onClick={this.handleClick}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
EditableTitle.propTypes = propTypes;
|
||||
EditableTitle.defaultProps = defaultProps;
|
||||
|
||||
export default EditableTitle;
|
||||