Compare commits

..

591 Commits
rm ... 0.8.6

Author SHA1 Message Date
Maxime Beauchemin
c5dead4791 v0.8.6 2016-04-07 14:26:28 -07:00
Maxime Beauchemin
d933a21216 Prettyfying an image in the docs 2016-04-07 14:26:28 -07:00
michellethomas
59169bfc96 Merge pull request #212 from airbnb/big_number_total
Adding a big number total viz type that is not a timeseries metric
2016-04-07 14:22:12 -07:00
Maxime Beauchemin
bcca840f01 Adding from __future__ imports (#288)
* Adding from __future__ imports

* fixes

* Fixing doctests

* Removing unused ColorFactory (in js now)

* linting
2016-04-07 08:39:08 -07:00
mherr
90a3b9f2c4 Update INTHEWILD.md
added #GfKDataLab as a Caravel-User
2016-04-06 23:56:19 -07:00
Maxime Beauchemin
a37e431150 Adding _images to .gitignore 2016-04-06 23:32:35 -07:00
Maxime Beauchemin
bf38c714a5 Adding missing images 2016-04-06 21:10:41 -07:00
Julian Nadeau
6b0b03e009 Fix localhost link in installation docs 2016-04-06 20:13:04 -07:00
Maxime Beauchemin
8556b098f9 Enable Time Grain Option for Redshift 2016-04-06 20:12:24 -07:00
Julian Nadeau
d122b37f5d Add python-pip to the install docs 2016-04-06 18:11:24 -07:00
Maxime Beauchemin
1756c27930 Adding upgrade instructions to docs 2016-04-06 18:02:40 -07:00
Aaron Critchley
7867267608 SqlAlchemy -> SQLAlchemy in README.md
* SqlAlchemy -> SQLAlchemy in README.md

Source: http://www.sqlalchemy.org/

* SqlAlchemy -> SQLAlchemy in tutorial.rst
2016-04-06 17:54:41 -07:00
Maxime Beauchemin
92d588694b Improving the Installation docs 2016-04-06 08:46:32 -07:00
Maxime Beauchemin
d10eaeccc9 Adding a Gallery to the docs 2016-04-06 08:46:21 -07:00
greens231
c2bb49fec5 Fix 4e6a06bad7a8_init.py migration script to work with Postgres
* Update 4e6a06bad7a8_init.py

* removed comments
2016-04-06 08:24:52 -07:00
Maxime Beauchemin
062f2b81cf Datasource dropdown in Explore view 2016-04-06 08:23:27 -07:00
andrewhn
65e72d0d07 Csv download improvements
* name + extension for generated csv and json files

* write csv index where data is meaningful
2016-04-06 08:22:49 -07:00
Maxime Beauchemin
345727635e Adding y_axis_format to DistributionBarViz 2016-04-06 08:20:24 -07:00
Maxime Beauchemin
c2baa53b06 bugfix datatables move to new package 2016-04-05 21:40:24 -07:00
Maxime Beauchemin
31758827ae + button on Slice list view redirects to Table view with alert 2016-04-05 13:33:02 -07:00
Maxime Beauchemin
81de51bf6f Minor tweaks 2016-04-04 21:39:33 -07:00
andrewhn
0d1f27dbc1 add postgres grains 2016-04-04 20:56:10 -07:00
Maxime Beauchemin
c7282882d5 Fixing the pagination display on welcome 2016-04-04 20:47:12 -07:00
Maxime Beauchemin
f9d04e8a72 Fixed refresh_datasource redirect 2016-04-04 20:43:06 -07:00
Maxime Beauchemin
bf2e804331 Removed trailing coma in Database.extra default 2016-04-04 17:42:31 -07:00
Maxime Beauchemin
c349b0a1c1 Fixed link url in docs 2016-04-04 17:14:08 -07:00
Maxime Beauchemin
4d640b5a3d [fix] panel overflowing on welcome page 2016-04-04 16:56:10 -07:00
Maxime Beauchemin
380c3f0c75 Using boostrap panels for form fieldsets in explore view 2016-04-04 16:14:55 -07:00
andrewhn
e3e8202c98 clear element before redrawing sankey 2016-04-04 16:13:54 -07:00
Maxime Beauchemin
889844407f Adding extra options to deeper configure sqlalchemy 2016-04-04 16:13:08 -07:00
Maxime Beauchemin
f1830c36cf A better welcome page 2016-04-04 16:12:28 -07:00
Chris Williams
92f73b67ca Move window.alert() calls to bootstrap modals. Also log errors to console.
* Move window.alert() calls to bootstrap modals. Also log errors that occur to console.

* move misc modal to basic template so it's available on all pages.
2016-04-04 16:11:23 -07:00
skje
9c1af66ba4 Fix ignored SQL where clauses 2016-04-04 16:03:21 -07:00
Maxime Beauchemin
2b31ab498b [hotfix] fixing json endpoint 2016-04-04 15:20:10 -07:00
Maxime Beauchemin
034fd077e1 Doc formating fix 2016-04-04 10:36:51 -07:00
Maxime Beauchemin
ca4443247e Prettyfying the Caravel on README 2016-04-03 20:08:36 -07:00
Maxime Beauchemin
6f96252e45 A logo on the navbar 2016-04-03 20:03:27 -07:00
Maxime Beauchemin
0b93fd373d [hotfix] hashing unicode in py3 2016-04-03 14:04:53 -07:00
Jiayu Liu
c3789d53b4 Removing duplicate get_table in fetch_metadata 2016-04-03 07:40:58 -07:00
Maxime Beauchemin
aec3c0b358 Fixing bug when datasource has been deleted 2016-04-03 07:37:18 -07:00
Karel Vervaeke
ef45c20558 Hash cache keys to avoid too keys being too long. Resolves #240 2016-04-03 07:33:43 -07:00
Maxime Beauchemin
10ab678fc6 Finishing up the tutorial 2016-04-02 23:34:47 -07:00
Maxime Beauchemin
87fb40ae26 Bumping version of npm up 2016-04-02 23:24:36 -07:00
Maxime Beauchemin
d245fb91b5 travis tweaks 2016-04-02 23:20:05 -07:00
Maxime Beauchemin
c60032acce Pillow with a capital P 2016-04-02 23:17:27 -07:00
Maxime Beauchemin
d2f51900f1 Adding a tutorial 2016-04-02 23:11:52 -07:00
Maxime Beauchemin
93405dc23a Clarify SQLALCHEMY_DATABASE_URI in the docs 2016-04-01 16:41:02 -07:00
Maxime Beauchemin
dafdb51f35 Adding Caravel Docker link to README 2016-04-01 16:16:21 -07:00
Maxime Beauchemin
2d0fdf7e59 Adding a CHANGELOG.md 2016-04-01 13:55:04 -07:00
Maxime Beauchemin
718de6cd50 v0.8.5 2016-04-01 13:30:12 -07:00
Maxime Beauchemin
38062f160a Adding an INTHEWILD file 2016-04-01 13:23:51 -07:00
Maxime Beauchemin
9a5a27a101 Merge pull request #234 from airbnb/pinpandas
Pin pandas, remove numpy
2016-04-01 11:52:41 -07:00
Maxime Beauchemin
481d821721 Tweaking docs 2016-04-01 08:37:19 -07:00
Maxime Beauchemin
7b111b790e Adding an OS dependencies section to the install docs 2016-04-01 08:33:28 -07:00
Maxime Beauchemin
ab92e7a94d Pin pandas, remove numpy 2016-04-01 08:04:44 -07:00
Maxime Beauchemin
22d2b7fe0f Merge pull request #229 from jmcomets/patch-1
Remove "requirements.txt" mention from README
2016-04-01 00:23:51 -07:00
Jean-Marie Comets
23319eed10 Remove "requirements.txt" mention from README
I noticed that there isn't the file `requirements.txt` was removed when moving to PyPi. Plus there's no such thing as an open-source project without an "update README" PR. ;)
2016-04-01 09:05:12 +02:00
Maxime Beauchemin
12cc064059 Merge pull request #225 from airbnb/chris/remove-random-power-units
remove power units from sankey diagram
2016-03-31 23:23:42 -07:00
Maxime Beauchemin
ffa29b3909 Merge pull request #219 from airbnb/chris/sunburst-conditional-percent
Add 'Percent of previous' to sunburst vis. Appease npm warnings for data tables and d3.layout.cloud
2016-03-31 23:23:27 -07:00
Maxime Beauchemin
ee4e3c1b98 Merge pull request #224 from cyrusstoller/typo_fix
Fixing minor typos in the readme
2016-03-31 23:21:12 -07:00
Maxime Beauchemin
ebc16bb3fa Merge pull request #214 from airbnb/kim/fix_druid_datasource_bug
Fix an installation bug.
2016-03-31 23:19:44 -07:00
Chris Williams
0e2c0ce858 remove power units from sankey diagram 2016-03-31 16:59:39 -07:00
Cyrus Stoller
807f4dd0e5 Fixing minor typos in the readme 2016-03-31 15:38:34 -04:00
Chris Williams
b87d8a0fbf change 'of previous' to 'of parent' 2016-03-31 12:26:49 -07:00
Chris Williams
0b3e2e00cc Add 'Percent of previous' to sunburst vis. Appease npm warnings for data tables and d3-sankey. 2016-03-31 12:26:49 -07:00
Maxime Beauchemin
167fb64d0c Merge pull request #218 from airbnb/redirects
Redirecting URL from previous names to caravel
2016-03-31 12:24:16 -07:00
Maxime Beauchemin
eeba80c487 Merge branch 'master' into redirects 2016-03-31 12:07:35 -07:00
Maxime Beauchemin
a3f92f687d Merge pull request #223 from thebucknerlife/master
Fixed typo in README
2016-03-31 12:05:32 -07:00
Maxime Beauchemin
a4b61e97db Merge pull request #222 from brchristian/patch-1
remove duplicate Druid.io section in README.md
2016-03-31 12:04:59 -07:00
Greg Buckner
9595dcff4d Fixed typo in README 2016-03-31 12:02:26 -07:00
brchristian
58ab4e2415 remove duplicate Druid.io section in README.md 2016-03-31 11:47:33 -07:00
Maxime Beauchemin
2b71b72065 Redirecting URL from previous names to caravel 2016-03-31 09:31:07 -07:00
Maxime Beauchemin
bd9051a168 Fixing README link 2016-03-31 08:50:47 -07:00
Maxime Beauchemin
6f63b3033f Dedupping info in README by pointing to docs 2016-03-31 08:48:34 -07:00
Kim Pham
f659caa06b Fix an installation bug. 2016-03-30 19:08:38 -07:00
Maxime Beauchemin
5b7fe2b643 Merge pull request #213 from airbnb/kim/fix_druid_datasource_bug
Fix a bug when loading DruidDatasource.
2016-03-30 17:02:16 -07:00
Kim Pham
e5553ab45e Fix lint warning. 2016-03-30 16:38:02 -07:00
Kim Pham
4a77b70046 A better fix. 2016-03-30 16:28:08 -07:00
Kim Pham
f67c6b5f46 Fix a bug when loading DruidDatasource. 2016-03-30 16:11:14 -07:00
Maxime Beauchemin
fd407424ad A few replacements related to the rename
mostly just s/mistercrunch/airbnb/g
2016-03-30 14:29:07 -07:00
Maxime Beauchemin
e1b871982e Adding docs link badge 2016-03-29 21:28:43 -07:00
Maxime Beauchemin
b164244cd8 Renaming forgotten doc file 2016-03-29 21:24:01 -07:00
Maxime Beauchemin
00226cce7f Changing image size, second try 2016-03-29 21:18:17 -07:00
Maxime Beauchemin
3a3d5cd7fb Changing image size 2016-03-29 21:16:53 -07:00
Maxime Beauchemin
c6b77206ea Adding build status badge and image to README 2016-03-29 21:14:44 -07:00
Maxime Beauchemin
d885dd34f9 Getting coveralls to work 2016-03-29 12:24:00 -07:00
Maxime Beauchemin
54fe2348fc Dummy commit to trigger travis 2016-03-29 12:00:37 -07:00
Maxime Beauchemin
6e1413d2dd Adding dev-reqs.txt to build 2016-03-29 11:59:25 -07:00
Maxime Beauchemin
0296b839ec Changing repo token for coveralls 2016-03-29 11:28:06 -07:00
Maxime Beauchemin
1c44f34490 Merge pull request #204 from airbnb/fixes
Fixing the order and coverage report for the unit tests
2016-03-29 11:24:37 -07:00
Maxime Beauchemin
10f3991e1f Merge pull request #209 from airbnb/screenshots
Fresh screenshots
2016-03-29 11:12:10 -07:00
Maxime Beauchemin
cda1bd59f9 Fresh screenshots 2016-03-29 11:11:13 -07:00
Maxime Beauchemin
8e27099866 Fixing the tests for py3 2016-03-29 10:02:15 -07:00
Maxime Beauchemin
60bce9ed59 Fixing the order and coverage report for the unit tests 2016-03-28 23:50:11 -07:00
Maxime Beauchemin
1b4e750b2a Merge pull request #206 from airbnb/caravel
Caravel
2016-03-28 23:45:38 -07:00
Maxime Beauchemin
619d35878f [dashed->caravel] Replace in files 2016-03-28 22:01:21 -07:00
Maxime Beauchemin
d48796f00e Caravel - renaming files 2016-03-28 21:53:24 -07:00
Chris Williams
5561a4932a Merge pull request #205 from airbnb/chris/sunburst-fix
fix sunburst error. add `less` to package.json
2016-03-28 17:07:51 -07:00
Chris Williams
1aee5b7801 fix sunburst error. add less to package.json because less-loader complains if it's not there. 2016-03-28 15:20:08 -07:00
Maxime Beauchemin
74c72b3ce4 Merge pull request #203 from airbnb/fixes
Fixing mysql install
2016-03-27 23:03:19 -07:00
Maxime Beauchemin
09021aacad Adding LONG to list of numeric types, updating TODO 2016-03-27 22:51:45 -07:00
Maxime Beauchemin
26c725171b Fixing mysql install 2016-03-27 22:37:04 -07:00
Maxime Beauchemin
4a0ea5fff7 Merge pull request #202 from airbnb/better_tests
Using setup.py nosetests to run tests
2016-03-27 19:55:45 -07:00
Maxime Beauchemin
301dce2dd1 Using setup.py nosetests to run tests 2016-03-27 19:15:21 -07:00
Maxime Beauchemin
6dce6df6b2 JS Lint breaks the build 2016-03-27 15:36:32 -07:00
Maxime Beauchemin
2102e04fec Adding tests for ping and health enpoint 2016-03-27 14:23:49 -07:00
Maxime Beauchemin
2397645ed4 Fix intermitent bug with npm locks 2016-03-27 14:23:49 -07:00
Maxime Beauchemin
0a8a1eda94 Merge pull request #199 from airbnb/touchups
Fix a few minor bugs
2016-03-27 08:09:08 -07:00
Maxime Beauchemin
4d2492d8fd Merge pull request #200 from airbnb/sankey
Add a sankey example
2016-03-27 08:08:36 -07:00
Maxime Beauchemin
48210d5275 Add a sankey example 2016-03-27 00:27:48 -07:00
Maxime Beauchemin
5804991b19 Fix a few minor bugs 2016-03-27 00:18:26 -07:00
Maxime Beauchemin
5be7b03ba4 [hotfix] Fix tooltip overflow to be visible outside widget 2016-03-26 21:10:41 -07:00
Maxime Beauchemin
a898c27403 Minor CSS for navbar brand to not decorate the link 2016-03-26 18:10:40 -07:00
Maxime Beauchemin
49747150ae [hotfix] merging 2 migration scripts 2016-03-26 15:15:21 -07:00
Maxime Beauchemin
fdce2aac0d Merge pull request #192 from airbnb/kim/misc_hack
Fix Druid metadata refresh.
2016-03-25 22:16:54 -07:00
Maxime Beauchemin
1c19f7fc77 Merge pull request #198 from airbnb/welcome
A welcome page
2016-03-25 22:15:28 -07:00
Maxime Beauchemin
12e20ca440 Merge pull request #197 from NiharikaRay/master
Adding a DRUID_IS_ACTIVE flag and changing nav bar
2016-03-25 22:14:46 -07:00
Maxime Beauchemin
0ccc19ff9b Merge pull request #196 from airbnb/fix_audit
Fixing issues around fk nullable=False on audit fields
2016-03-25 22:13:45 -07:00
Maxime Beauchemin
e7bed92519 [hotfix] can't back out of history after entering explore 2016-03-25 22:02:50 -07:00
Maxime Beauchemin
8c0870e6ea Linting to perfection 2016-03-25 21:55:28 -07:00
Maxime Beauchemin
c9203554e7 a welcome page 2016-03-25 18:08:33 -07:00
Kim Pham
2378fdf9ce Disable polymorphism in DruidMetric as well 2016-03-25 16:45:35 -07:00
Kim Pham
23b6bca89e Fix style warning 2016-03-25 13:49:45 -07:00
Kim Pham
7a7eb33348 Disable Datasource sql polymorphism & Fix refresh Druid metadata. 2016-03-25 13:44:35 -07:00
Niharika Ray
fee6b3fafa Adding a DRUID_IS_ACTIVE flag and changing nav bar 2016-03-25 11:26:59 -07:00
Maxime Beauchemin
0f637bdd2e Fixing issues around fk nullable=False on audit fields 2016-03-25 08:13:15 -07:00
Maxime Beauchemin
10a1eddaa7 Improving the docs build script 2016-03-24 08:08:05 -07:00
Maxime Beauchemin
21d1c0a1b5 0.8.4 2016-03-23 22:26:16 -07:00
Maxime Beauchemin
3118d1b302 Merge pull request #193 from airbnb/favstar
Adding favorites for Slices and Dashboards
2016-03-23 22:25:12 -07:00
Maxime Beauchemin
2362b5a157 Tunning tooltips 2016-03-23 22:23:29 -07:00
Maxime Beauchemin
7ede732892 Adding favorites for Slices and Dashboards 2016-03-23 22:15:23 -07:00
Maxime Beauchemin
5b10b19ed7 Fixing the docs 2016-03-23 21:41:37 -07:00
Maxime Beauchemin
14f298b385 dashboard bug fixes and better page titles 2016-03-23 21:27:45 -07:00
Maxime Beauchemin
89da51f8d7 Pointing landscape badge to the right branch 2016-03-23 16:16:20 -07:00
Maxime Beauchemin
d5487c6b25 0.8.3 2016-03-23 14:11:37 -07:00
Maxime Beauchemin
a244f3aafb Fixing build issues with preventive rm /Users/maxime_beauchemin/.npm/*.lock 2016-03-23 14:11:37 -07:00
Maxime Beauchemin
9d3bf7763c Fixing build issues with preventive rm /Users/maxime_beauchemin/.npm/*.lock 2016-03-23 11:14:29 -07:00
Maxime Beauchemin
b0f10a90ce Merge pull request #188 from airbnb/caching
Introducing a caching layer!
2016-03-22 22:55:35 -07:00
Maxime Beauchemin
417749f880 Explore mode should only expose cache on first load 2016-03-22 22:09:02 -07:00
Maxime Beauchemin
fded04a51d Hack to get the force refresh in the explore view 2016-03-22 18:11:10 -07:00
Maxime Beauchemin
d8192eca0a Introducing a caching layer 2016-03-22 18:11:10 -07:00
Maxime Beauchemin
2d3edf3a2e js lint breaks the build 2016-03-22 08:16:23 -07:00
Maxime Beauchemin
0890d22899 Merge pull request #191 from airbnb/week-grain
Add week ending and week start to grain
2016-03-21 15:56:36 -07:00
Siddharth
bad3128df9 Update grain label name 2016-03-21 15:41:49 -07:00
Siddharth
48c8a90247 Fix multi-line statement 2016-03-21 14:27:03 -07:00
Siddharth
a9ba47fe12 Add week ending and week start to grain 2016-03-21 13:45:14 -07:00
Maxime Beauchemin
f09f3d7c4b Merge pull request #190 from airbnb/vnum
Cranking up version numbers
2016-03-19 21:46:03 -07:00
Maxime Beauchemin
e17d78e196 Cranking up version numbers 2016-03-19 21:33:39 -07:00
Maxime Beauchemin
9450c12552 note about the previous name in README 2016-03-19 16:09:08 -07:00
Maxime Beauchemin
f01b41827e Adding reqs badge 2016-03-19 16:03:15 -07:00
Maxime Beauchemin
b5f4d3b515 Adding reqs badge 2016-03-19 10:30:54 -07:00
Maxime Beauchemin
28e5a87cd0 pypi badges 2016-03-19 10:16:59 -07:00
Maxime Beauchemin
10c48f04cd [renaming] 2016-03-19 10:07:18 -07:00
Maxime Beauchemin
f79aca1796 rename - 2nd phase 2016-03-18 08:52:50 -07:00
Maxime Beauchemin
be6b2fe556 [panoramix] -> [dashed] 2016-03-17 23:44:58 -07:00
Chris Williams
8f4f5b126a Merge pull request #184 from mistercrunch/chris/sunburst-fixes
sunburst improvements
2016-03-17 17:54:10 -07:00
Maxime Beauchemin
2b1dcf0d2e [hotfix] granularity fix 2016-03-17 14:54:26 -07:00
Maxime Beauchemin
987a1afbb7 [hotfix] granularity fix 2016-03-17 14:45:21 -07:00
Maxime Beauchemin
f453932589 [hotfix] druid granularity missing 2016-03-17 14:37:14 -07:00
Chris Williams
3dc9996e96 hide breadcrumbs on mouseout 2016-03-17 14:10:15 -07:00
Chris Williams
3197c4b3f9 add utility function for wrapping svg text, apply to sunburst breadcrumbs, and make colors more readable for sunburst. 2016-03-17 14:02:54 -07:00
Maxime Beauchemin
f0b2f985b4 Merge pull request #186 from mistercrunch/docstrings
Adding docstrings !
2016-03-16 22:40:50 -07:00
Maxime Beauchemin
1c9c154f0f More docstrings 2016-03-16 22:26:17 -07:00
Maxime Beauchemin
ebf55bf20d Adding docstrings ! 2016-03-16 20:40:50 -07:00
Maxime Beauchemin
3461538fed [hotfix] appbuilder modal z-index fix 2016-03-16 17:27:56 -07:00
Maxime Beauchemin
7cdb23f585 [hotfix] grouping by grain, filtering on raw expression 2016-03-16 17:04:36 -07:00
Maxime Beauchemin
73daf2f8d1 [hotfix] casting dates for presto grain functions 2016-03-16 16:42:35 -07:00
Maxime Beauchemin
ae1e66f09b Merge pull request #181 from mistercrunch/time_grain
Dynamic time granularity on any datetime column
2016-03-16 16:11:42 -07:00
Chris Williams
06080945b6 fix misc sunburst bugs from refactor. 2016-03-16 15:52:52 -07:00
Maxime Beauchemin
61ab06d640 Removing unicode from country data 2016-03-16 15:49:01 -07:00
Chris Williams
0c045a9e52 trim '0' groups from sunburst paths to show null groups. add ability to map color to sunburst groupby groups. add fancier breadcrumbs to sunburst. 2016-03-16 15:24:30 -07:00
Maxime Beauchemin
27fb810dd7 Dynamic time granularity on any datetime column 2016-03-16 15:12:16 -07:00
Chris Williams
2aa0e0dce0 Merge pull request #182 from mistercrunch/chris/modal-and-dashboard-css-fixes
more css fixes
2016-03-16 09:11:47 -07:00
Maxime Beauchemin
417b5a5e09 Adding linting note to CONTRIBUTING.md 2016-03-16 08:23:59 -07:00
Maxime Beauchemin
7c5e660bd1 Merge pull request #178 from mistercrunch/fix_audit
Allowing all extra fields in AuditMixin to be nullable
2016-03-16 08:15:12 -07:00
Chris Williams
1a58b6d441 fix overflow scroll bars on all dashboard charts. make dashboard chart control toggle interaction nicer. make sure user-stylesheets are applied last. remove ace css editor error/warning parsing. make filters look nicer in dashboards. fix some linting. 2016-03-15 11:52:26 -07:00
Maxime Beauchemin
1ab89631b9 Adding caching to TODO 2016-03-13 23:04:43 -07:00
Chris Williams
e1eb236cf4 Merge pull request #175 from mistercrunch/chris/css-fixes
refactor dashboard chart html, make several css improvements.
2016-03-13 23:03:35 -07:00
Maxime Beauchemin
95b7b9779b Allowing all extra fields in AuditMixin to be nullable 2016-03-13 21:36:40 -07:00
Chris Williams
b0fa4bc924 remove unused css 2016-03-11 12:29:41 -08:00
Chris Williams
49590e28e3 refactor dashboard chart html, make several css improvements. 2016-03-11 12:22:41 -08:00
Maxime Beauchemin
fb6a9977f7 Merge pull request #172 from mistercrunch/packaging
Fixing the python and js packaging
2016-03-10 22:33:09 -05:00
Maxime Beauchemin
9e4b38b5e6 Adjusting css for display not to flicker on dashboard load 2016-03-10 08:46:20 -05:00
Maxime Beauchemin
e2cd14d320 Fixing the python and js packaging 2016-03-10 01:35:20 -05:00
Maxime Beauchemin
370c5af425 [hotfix] fix utils.markdown function chokes on None 2016-03-09 07:34:00 -05:00
Maxime Beauchemin
e53a1cc75b Adding a TODO entry for viz selector 2016-03-08 16:53:54 -05:00
Maxime Beauchemin
91833ce16f Merge pull request #171 from mistercrunch/fix_filter
Fixing multiple refresh bug in filter_box
2016-03-08 07:29:14 -05:00
Maxime Beauchemin
829271417e Fixing bug in filter_box 2016-03-07 23:03:30 -05:00
Maxime Beauchemin
55d4ac45fa Merge pull request #169 from mistercrunch/select2-style
Fixing the look of select2 components
2016-03-07 13:46:38 -05:00
Maxime Beauchemin
d6db3a9cf1 semicolon 2016-03-07 13:46:19 -05:00
Maxime Beauchemin
c0e4aca7e4 Using dash - instead of _ on filename, making input form-control white 2016-03-06 17:48:50 -05:00
Maxime Beauchemin
9855a60013 Fixing the look of select2 components 2016-03-06 14:48:05 -05:00
Maxime Beauchemin
a53dbfcfaa Merge pull request #168 from mistercrunch/travis_npm
Getting travis to build the npm related stuff
2016-03-06 08:07:37 -05:00
Maxime Beauchemin
b2d72fbfe1 Tweaks 2016-03-05 23:43:17 -05:00
Maxime Beauchemin
78e01ab0a1 Caching node_modules 2016-03-05 23:01:39 -05:00
Maxime Beauchemin
454bb10f5a Getting travis to build the npm related stuff 2016-03-05 22:22:36 -05:00
Maxime Beauchemin
ee025b3331 Fixing REST api and unsortable columns 2016-03-05 21:50:23 -05:00
Chris Williams
1e27f03b4d Merge pull request #166 from mistercrunch/chris/css
make css theme customization easier by using less for bootstrap themes
2016-03-05 12:45:59 -08:00
Chris Williams
9095cd3bca update contributing.md to explain updated LESS/CSS customization 2016-03-05 12:41:22 -08:00
Maxime Beauchemin
bfa6d13b49 Merge pull request #163 from mistercrunch/css
Shipping with CSS templates out of the box
2016-03-04 23:38:42 -05:00
Chris Williams
d3f7bbd3f1 remove pre-compiled bootstrap themes, use npm/wepack to compile from less variables instead. also fix a few css style bugs. 2016-03-04 18:20:49 -08:00
Maxime Beauchemin
570b9f09f6 Merge pull request #164 from mistercrunch/docs
Improving the docs
2016-03-04 18:58:12 -05:00
Maxime Beauchemin
e39f7db0a3 Merge pull request #165 from mistercrunch/window_resize
Fixing window resize for explore and standalone
2016-03-04 18:57:44 -05:00
Maxime Beauchemin
9de19b169f setResizeOnWindowResize -> bindResizeToWindowResize 2016-03-04 18:56:06 -05:00
Maxime Beauchemin
722c16a6e5 Fixing window resize for explore and standalone 2016-03-04 14:47:50 -05:00
Maxime Beauchemin
5486e5cac8 barol -> tirol 2016-03-04 13:47:04 -05:00
Chris Williams
1782d8f278 Merge pull request #161 from mistercrunch/chris/eslint
Add linting to package.json, do all of the linting.
2016-03-04 10:24:06 -08:00
Maxime Beauchemin
0a8ab6c499 Shipping with a CSS template out of the box 2016-03-04 00:44:55 -05:00
Maxime Beauchemin
a7e75a2bc5 [hotfix] cosmetic fitting for nvd3 line chart overflowing 2016-03-03 22:30:22 -05:00
Maxime Beauchemin
486fb8bfb4 [hotfix] fixing the examples 2016-03-03 22:30:22 -05:00
Maxime Beauchemin
bd296720b8 Improving the docs 2016-03-02 12:19:11 -08:00
Chris Williams
68f8937a2e lint standalone.js 2016-03-02 12:03:32 -08:00
Maxime Beauchemin
8703fa9460 Merge pull request #160 from mistercrunch/fix_dashed
Fixing the dashed line when using time compare
2016-03-02 11:47:50 -08:00
Chris Williams
673f741aa6 Add linting to package.json, run 'npm run lint' to run (will try to add commit hook later). Do all of the linting... 2016-03-02 11:32:27 -08:00
Maxime Beauchemin
b61ddd0009 semicolon 2016-03-02 11:12:55 -08:00
Maxime Beauchemin
e1e1746967 Fixing the dashed line when using time compare 2016-03-02 11:12:55 -08:00
Maxime Beauchemin
b6a2521722 hotfix - forgot to add standalone.js 2016-03-02 10:57:36 -08:00
Maxime Beauchemin
309a6dcb1d Merge pull request #159 from mistercrunch/standalone
Fixing the standalone mode
2016-03-02 00:28:50 -08:00
Maxime Beauchemin
51797ca9a5 Fixing the standalone mode 2016-03-01 18:22:41 -08:00
Maxime Beauchemin
2872c6262d Merge pull request #158 from mistercrunch/refactor
Refactor
2016-03-01 17:09:52 -08:00
Maxime Beauchemin
b44d48c724 Using vim-jsbeautify 2016-03-01 15:56:31 -08:00
Maxime Beauchemin
a68d7428c3 Javascript refactor 2016-03-01 15:51:06 -08:00
Maxime Beauchemin
e434cbe268 Better filtering 2016-03-01 15:50:09 -08:00
Maxime Beauchemin
367ca336cc Merge pull request #154 from mistercrunch/fix_dates
Digging into leap year bug and improvming tests
2016-03-01 14:35:10 -08:00
Maxime Beauchemin
4fe89a3811 Pinning parsedatetime to 2.0 2016-03-01 14:23:54 -08:00
Maxime Beauchemin
8c525b7b8f Hotfix nvd3's secondary xaxis uses the wrong formating 2016-03-01 13:44:06 -08:00
Chris Williams
b36b1ef05a Merge pull request #157 from mistercrunch/chris/copy-short-url
add button to auto-copy short URLs in /explore page
2016-03-01 12:10:11 -08:00
Chris Williams
88f9442297 add button to auto-copy short URLs in /explore page 2016-03-01 11:40:13 -08:00
Maxime Beauchemin
32cd9f5e73 Updating TODO.md 2016-03-01 07:47:13 -08:00
Maxime Beauchemin
eccf9c2ac7 [hotfix] saving as new bugfix 2016-02-29 22:36:44 -08:00
Maxime Beauchemin
8b0f2afc0a Merge pull request #149 from mistercrunch/immune_to_filter
Allowing to make certain widgets immune to filter
2016-02-29 20:06:39 -08:00
Maxime Beauchemin
be4a7a4077 Linting 2016-02-29 18:10:33 -08:00
Maxime Beauchemin
69cfcabb72 Making Dashboard look better 2016-02-29 16:55:59 -08:00
Maxime Beauchemin
3a38c601e0 Fixing tooltips 2016-02-29 15:55:54 -08:00
Maxime Beauchemin
22327e204f Transfering all the json in one point 2016-02-29 15:55:54 -08:00
Maxime Beauchemin
bd06f995ee Allowing to make certain widgets immune to filter 2016-02-29 15:55:54 -08:00
Maxime Beauchemin
9f809e9f8b hotfix, readme pointing to the right landscape branch 2016-02-29 14:59:49 -08:00
Maxime Beauchemin
34709c8846 Digging into leap year bug and improvming tests 2016-02-29 14:55:21 -08:00
Maxime Beauchemin
bb46887668 Merge pull request #151 from mistercrunch/lint
Linting
2016-02-29 14:35:56 -08:00
Maxime Beauchemin
74b32ac993 Merge pull request #153 from tay/patch-1
Improve README
2016-02-29 12:30:18 -08:00
Fiona Tay
ca124f271b Improve README
Fix typo
Link to the actual Contributing file
2016-02-29 12:04:39 -08:00
Maxime Beauchemin
0a842598df More linting 2016-02-29 00:32:52 -08:00
Maxime Beauchemin
cb46a61728 Linting 2016-02-29 00:04:37 -08:00
Maxime Beauchemin
8bf629c0b2 [hotfix] fixing explore view 2016-02-28 15:32:25 -08:00
Maxime Beauchemin
63b4f56c6a Merge pull request #139 from mistercrunch/chris/npm-ify2
NPMification & Reactification
2016-02-28 15:19:04 -08:00
Maxime Beauchemin
d40664bca7 Merge pull request #147 from mistercrunch/npm
Tackling Featured Datasets
2016-02-28 15:14:43 -08:00
Maxime Beauchemin
bc4182060a Rolling back to previous theme until we polish bootswarch.paper 2016-02-28 08:12:00 -08:00
Maxime Beauchemin
58c7b8c436 Removing js_files and css_files entries from viz.py 2016-02-27 09:02:39 -08:00
Maxime Beauchemin
c304cc493a Moving content of assets/readme.md to contributing.md 2016-02-27 07:47:56 -08:00
Maxime Beauchemin
4f4c67ce15 Moving html assets back to flask template folder 2016-02-27 07:33:06 -08:00
Maxime Beauchemin
c929b2a9c9 npmify datamaps dependency 2016-02-27 07:27:51 -08:00
Maxime Beauchemin
fd0e680cf0 Cleaning up assets/vendors 2016-02-26 18:35:59 -08:00
Maxime Beauchemin
70e1aa37e3 Adding missing fonts 2016-02-25 22:38:48 -08:00
Maxime Beauchemin
e4e7b911c5 Fixing dashboard.html 2016-02-25 21:15:03 -08:00
Maxime Beauchemin
d8409c1e0a Fixing table and pivot_table 2016-02-25 17:44:23 -08:00
Maxime Beauchemin
8dcd5e0628 Tackling Featured Datasets 2016-02-24 17:44:22 -08:00
Maxime Beauchemin
d2bb9aaf96 Merge pull request #148 from tay/patch-1
Fix typo
2016-02-24 17:38:52 -08:00
Fiona Tay
7c96a2eddf Fix typo 2016-02-24 17:19:44 -08:00
Chris Williams
71b11117d7 Merge pull request #145 from mistercrunch/npm
Moving files around ... yay!
2016-02-24 16:35:40 -08:00
Maxime Beauchemin
e70542d743 NPMify sql.html 2016-02-24 16:22:32 -08:00
Maxime Beauchemin
171301b6cf Moving files around 2016-02-24 15:12:51 -08:00
Chris Williams
3e834603fc Remove base.entry.js, declare all JS dependencies in explore using npm. Pin older select2 version to enable select2Sortable. 2016-02-24 13:30:42 -08:00
Maxime Beauchemin
71073d8f83 Merge pull request #142 from mistercrunch/npm
A few cosmetic fixes (nvd3 tooltips, buttons, tables)
2016-02-24 11:47:21 -08:00
Maxime Beauchemin
df8ea5287b Adjustments based on comment 2016-02-24 11:43:21 -08:00
Maxime Beauchemin
9552d09b85 A few cosmetic fixes (nvd3 tooltips, buttons, tables) 2016-02-24 11:30:01 -08:00
Maxime Beauchemin
dbb9f66202 Merge pull request #141 from mistercrunch/npm
A simple base template for npm
2016-02-24 09:48:24 -08:00
Maxime Beauchemin
d582efe76b Fixing 2 links 2016-02-24 09:45:30 -08:00
Maxime Beauchemin
f5e0ed7239 A simple base template for npm 2016-02-23 17:48:13 -08:00
Chris Williams
79e6fc986d huge npm refactor of all visualizations. table views are broken due to broken shimming for jquery/jquery-ui, dashboards are broken due to refactor of explore views. 2016-02-23 17:00:08 -08:00
Maxime Beauchemin
523b6d815a Merge pull request #140 from dayzzz/segment_selection
use the latest segment to extract metadata
2016-02-22 22:27:07 -08:00
Hongbo Zeng
5c38fc731a use the latest segment to extract metadata 2016-02-22 16:44:29 -08:00
Chris Williams
af34549377 partial refactor of explore page, visualizations not managed with webpack yet. 2016-02-19 15:12:25 -08:00
Chris Williams
0eb3dcd81f Update readme.md 2016-02-19 12:07:19 -08:00
Chris Williams
f40c024fda Add npm package.json and setup webpack to transpile ES6/JSX and compile JS files for frontend refactor. See readme.md in assets/ for npm setup instructions and visit the panoramix home page for a React sandbox. 2016-02-19 11:39:50 -08:00
Maxime Beauchemin
20bd4ca0eb Merge pull request #136 from mistercrunch/barbar
Improved the bar char to allow for dimensional breakdowns
2016-02-15 20:26:12 -08:00
Maxime Beauchemin
7e60b14448 Trying to fix a unicode bug with presto 2016-02-15 20:25:23 -08:00
Maxime Beauchemin
e42d1a1fc5 Improved the bar char to allow for dimensional breakdowns 2016-02-15 20:10:33 -08:00
Maxime Beauchemin
6f4397c7d7 Fixing druid metadata import 2016-02-12 15:47:23 -08:00
Maxime Beauchemin
1f41ce3a7d CLI adding refresh_druid command 2016-02-12 15:25:42 -08:00
Maxime Beauchemin
d970e896ad bugfix - Cluster -> DruidCluster 2016-02-12 00:49:43 -08:00
Maxime Beauchemin
5686dc0865 Bugfix Column -> DruidColumn 2016-02-12 00:45:09 -08:00
Maxime Beauchemin
80651a5dc2 More logging 2016-02-12 00:32:15 -08:00
Maxime Beauchemin
2c4396882e More verbose druid metadata refresh 2016-02-12 00:01:25 -08:00
Maxime Beauchemin
ba28fbbd6b Fixing link to cluster view 2016-02-11 17:58:12 -08:00
Maxime Beauchemin
4acf1865f8 Merge pull request #134 from mistercrunch/fix_init
Fixing the roles auto maintenance
2016-02-11 16:10:39 -08:00
Maxime Beauchemin
53a0f81985 Fixing the roles auto maintenance 2016-02-11 15:54:51 -08:00
Maxime Beauchemin
baac8c44a5 Desperatly changing view name to avoid proxy odd bug 2016-02-11 13:23:46 -08:00
Maxime Beauchemin
88b8f73489 Not specifying flask-login version, letting flask-appbuilder do it 2016-02-11 12:54:08 -08:00
Maxime Beauchemin
e02702d320 Pinning appbuilder to 1.6 2016-02-11 10:59:49 -08:00
Maxime Beauchemin
e39d6dbc3d Hack to log dashboard_ids when slugs are used 2016-02-10 14:12:38 -08:00
Maxime Beauchemin
07d52eda48 Merge pull request #132 from mistercrunch/fix_legend
[nvd3] fixing the legend toggle bug
2016-02-10 12:27:46 -08:00
Maxime Beauchemin
c7ecb331e4 [nvd3] fixing the legend toggle bug 2016-02-10 12:22:05 -08:00
Maxime Beauchemin
ec0566860a Fixing legend toggle in nvd3 charts 2016-02-10 11:34:46 -08:00
Maxime Beauchemin
e759dfaf0a Merge pull request #131 from mistercrunch/moretests
More tests using doctests!
2016-02-10 11:26:17 -08:00
Maxime Beauchemin
e039547762 More tests using doctests 2016-02-10 11:20:13 -08:00
Maxime Beauchemin
7b0c045a42 Merge pull request #130 from mistercrunch/log_more
Logging more
2016-02-10 11:13:35 -08:00
Maxime Beauchemin
5e9096f275 Merge pull request #129 from mistercrunch/rename_druid_classes
Renaming Classes related to Druid
2016-02-10 08:54:20 -08:00
Maxime Beauchemin
b1f88a53ad Logging more 2016-02-10 08:52:49 -08:00
Maxime Beauchemin
32442aa6b7 Adding Metric class as well 2016-02-10 07:18:59 -08:00
Maxime Beauchemin
b18d117852 Renaming Classes related to Druid 2016-02-10 06:56:35 -08:00
Maxime Beauchemin
460f6cbed5 Updated TODO and color bugfix 2016-02-04 17:01:40 -08:00
Maxime Beauchemin
61b3a85d7a improving the sql view 2016-02-04 00:26:20 -08:00
Maxime Beauchemin
98ba32399e Polish 2016-02-03 23:11:06 -08:00
Maxime Beauchemin
b10487cf39 Fixing the overflow for tables 2016-02-03 21:51:10 -08:00
Maxime Beauchemin
72cf50a8c3 Merge pull request #127 from mistercrunch/sql
SQL editor, eventually will be tied to a flow to create views
2016-02-03 21:36:48 -08:00
Maxime Beauchemin
3b9b81f93e Getting the back button to work 2016-02-03 21:36:21 -08:00
Maxime Beauchemin
9c47415d62 Error handling and table links 2016-02-03 21:36:21 -08:00
Maxime Beauchemin
50d7d0fb5b Making progress 2016-02-03 21:36:21 -08:00
Maxime Beauchemin
e8ae49d181 An airpal like interface 2016-02-03 21:35:57 -08:00
Maxime Beauchemin
354ef9b4bb Polishing the CSS template feature 2016-02-03 21:13:43 -08:00
Maxime Beauchemin
d276be8d50 Moving CSS templates link to Sources 2016-02-03 20:19:54 -08:00
Maxime Beauchemin
cf5d290a12 Merge pull request #128 from mistercrunch/css_templates
Allowing definition of css templates
2016-02-03 18:09:21 -08:00
Maxime Beauchemin
dbbedc3ba4 Allowing definition of css templates 2016-02-03 18:04:28 -08:00
Maxime Beauchemin
9838fbb107 Fixing bad merge 2016-01-29 10:32:23 -08:00
Maxime Beauchemin
95aa6e00fa [fix] can't back out with back button 2016-01-29 10:30:43 -08:00
Maxime Beauchemin
5156d9f2dd Merge pull request #126 from mistercrunch/heatmap
New viz: Heatmap!
2016-01-28 16:45:32 -08:00
Maxime Beauchemin
4e6e20daa4 Allowing for normalizing across x or y 2016-01-28 13:11:45 -08:00
Maxime Beauchemin
44b43a352a Adding vid to README.md 2016-01-27 14:04:27 -08:00
Maxime Beauchemin
0714dc62d0 Added smoothening option 2016-01-27 09:45:02 -08:00
Maxime Beauchemin
40b28d0afa Allowing different color schemes 2016-01-27 08:50:39 -08:00
Maxime Beauchemin
09c77242fc Working without zoom 2016-01-26 23:17:58 -08:00
Maxime Beauchemin
0f58c609d0 Heatmap 2016-01-26 12:57:12 -08:00
Maxime Beauchemin
a2f14b3787 getting something to show 2016-01-24 22:52:27 -08:00
Maxime Beauchemin
b91460db4f [bugfix] sunburst text shows behind arcs 2016-01-24 17:44:44 -08:00
Maxime Beauchemin
1b661a1ee8 Merge pull request #125 from mistercrunch/colors_perfect
Consistent colors rendered client side
2016-01-24 14:35:00 -08:00
Maxime Beauchemin
a3c2ee0e1d Consistent colors rendered client side 2016-01-24 13:56:20 -08:00
Maxime Beauchemin
e6920f8066 CRUD views improvements 2016-01-24 10:09:26 -08:00
Maxime Beauchemin
0ca59bcc21 Curating list of fields 2016-01-23 10:15:56 -08:00
Maxime Beauchemin
9fb708a74a Merge pull request #124 from mistercrunch/colors
A more cohesive color strategy
2016-01-23 10:03:16 -08:00
Maxime Beauchemin
32e4b9f2bc A more cohesive color strategy 2016-01-23 09:59:16 -08:00
Maxime Beauchemin
012a651586 v0.7.0 2016-01-23 07:16:45 -08:00
Maxime Beauchemin
b472cad5d1 Merge pull request #123 from mistercrunch/color_factory
Adding a color factory
2016-01-22 15:37:47 -08:00
Maxime Beauchemin
2df3cfd774 Adding a color factory 2016-01-22 15:26:02 -08:00
Maxime Beauchemin
2f6e971463 Merge pull request #122 from mistercrunch/para
Adding Parallel coordinates viz
2016-01-21 13:40:58 -08:00
Maxime Beauchemin
73989f41ac Adding Parallel coordinates viz 2016-01-21 08:35:20 -08:00
Maxime Beauchemin
2885227050 Autodocs 2016-01-20 18:09:31 -08:00
Maxime Beauchemin
52e6e97262 Merge pull request #121 from mistercrunch/iframe
Iframe
2016-01-19 12:59:14 -08:00
Maxime Beauchemin
5f880682c0 Fixing a bug 2016-01-19 12:58:44 -08:00
Maxime Beauchemin
5f9f95b717 Adding a basic ifram viz 2016-01-19 00:39:25 -08:00
Maxime Beauchemin
ef612ed66c Merge pull request #120 from mistercrunch/sliceinfo
Slice information can be displayed in dashboard
2016-01-19 00:37:48 -08:00
Maxime Beauchemin
110be3551a bugfix in explore view 2016-01-19 00:11:54 -08:00
Maxime Beauchemin
8d40717a92 Adding description for new field in crud 2016-01-19 00:06:23 -08:00
Maxime Beauchemin
e40f5bc6d6 Displaying markdown slice info on dash view 2016-01-19 00:02:46 -08:00
Maxime Beauchemin
ba1dfcb845 Refactor + timeformating options 2016-01-16 14:01:05 -08:00
Maxime Beauchemin
b594b8a93b BigNumber tweaks 2016-01-16 07:17:26 -08:00
Maxime Beauchemin
f1127a1e47 Merge pull request #117 from mistercrunch/refact
Doing some refactoring
2016-01-16 06:52:44 -08:00
Maxime Beauchemin
085430cb53 Doing some refactoring 2016-01-16 06:45:49 -08:00
Maxime Beauchemin
85963900ae Merge pull request #115 from mistercrunch/y_format
Providing options for Y axis number formating
2016-01-15 23:28:46 -08:00
Maxime Beauchemin
d9e4c75122 Parameterizing the number of gunicorn workers 2016-01-15 12:23:28 -08:00
Maxime Beauchemin
976b7772f0 Weeding some useless lines 2016-01-15 10:13:08 -08:00
Maxime Beauchemin
02e519ab61 Fixing the bug where filters don't apply on load 2016-01-15 10:05:29 -08:00
Maxime Beauchemin
5910bf007a Providing options for Y axis number formating 2016-01-14 15:31:23 -08:00
Maxime Beauchemin
69a385bade [hotfix] date casting 2016-01-14 09:54:19 -08:00
Maxime Beauchemin
67ea040d1f Merge pull request #112 from mistercrunch/url_shortner
Adding an URL shortner
2016-01-14 09:50:25 -08:00
Maxime Beauchemin
d97788b87a Merge pull request #113 from mistercrunch/check
Prettier checkboxes
2016-01-14 09:50:00 -08:00
Maxime Beauchemin
ba30dc4c22 Merge pull request #111 from mistercrunch/load_ex_dash
Loading another example amazing dash
2016-01-14 09:49:01 -08:00
Maxime Beauchemin
df797c0ae0 Prettier checkboxes 2016-01-13 22:16:24 -08:00
Maxime Beauchemin
f4ef1c02a2 Adding an URL shortner 2016-01-13 21:44:27 -08:00
Maxime Beauchemin
a3727fc091 Making sqlite work 2016-01-13 18:16:01 -08:00
Maxime Beauchemin
ef5511cccf Getting stuff to load 2016-01-13 17:19:12 -08:00
Maxime Beauchemin
a38a8d476e Loading another example amazing dash 2016-01-13 17:05:11 -08:00
Maxime Beauchemin
d726bd0e05 NVD3 form optinos for stacked/expanded/grouped ... 2016-01-13 13:43:39 -08:00
Maxime Beauchemin
7982dee834 Updating the CONTRIBUTING.md 2016-01-13 09:03:27 -08:00
Maxime Beauchemin
4f7a5f33bb Refactoring 2016-01-13 08:50:55 -08:00
Maxime Beauchemin
b6b8d046c8 Tunning timeseries settings 2016-01-12 14:57:34 -08:00
Maxime Beauchemin
089a8c677c [hotfix] no data 2016-01-12 12:06:34 -08:00
Maxime Beauchemin
f434f3c756 Raising earlier on no data 2016-01-12 12:02:26 -08:00
Maxime Beauchemin
ffe9a68712 Adding a picture for who dataset 2016-01-12 09:47:15 -08:00
Maxime Beauchemin
2b01340bb6 Allowing TableViz to show time granularity 2016-01-12 09:34:17 -08:00
Maxime Beauchemin
0e0ae7bc92 Increasing page_size to 500 in crud 2016-01-12 08:50:17 -08:00
Maxime Beauchemin
4941565a41 Making TableViz support a time_series 2016-01-12 08:48:28 -08:00
Maxime Beauchemin
299ad09576 [bugfix] columns dupplicated in Druid df 2016-01-12 08:43:36 -08:00
Maxime Beauchemin
552a3094df Getting the markdown to do what it should 2016-01-11 23:18:43 -08:00
Maxime Beauchemin
2b0c550a0b Improvments to load_examples 2016-01-11 20:53:20 -08:00
Maxime Beauchemin
2b69912c46 Minor bug fixes 2016-01-11 16:01:54 -08:00
Maxime Beauchemin
ceb0dc1985 Touchups on field list 2016-01-11 15:38:17 -08:00
Maxime Beauchemin
ed96f9b92f Fixing the word bad assumptions about field ordering 2016-01-11 15:29:18 -08:00
Maxime Beauchemin
4aa70d0f43 Ordering columns in the Druid pandas df 2016-01-11 15:15:11 -08:00
Maxime Beauchemin
6c92fa471d some error handling for WordCloud 2016-01-11 14:42:45 -08:00
Maxime Beauchemin
3efaec8983 Minor fix + TODO alterations 2016-01-11 14:34:18 -08:00
Maxime Beauchemin
2dbad2d124 Merge pull request #109 from mistercrunch/hash_change
Getting browser history to work on the explore view
2016-01-11 11:46:26 -08:00
Maxime Beauchemin
f0cdf4318d Getting browser history to work on the explore view 2016-01-11 11:42:46 -08:00
Maxime Beauchemin
ac8a78e388 Merge pull request #108 from bradmbaker/brad_baker_final_fix_for_tooltip
pulling to the front on hover
2016-01-11 11:07:41 -08:00
BradBaker
7fb845f38d pulling to the front on hover 2016-01-11 10:11:50 -08:00
Maxime Beauchemin
af5528519d Made json csv and standalone button more dynamic 2016-01-11 09:27:00 -08:00
Maxime Beauchemin
4c8b275f88 Minor tweaks 2016-01-10 20:53:57 -08:00
Maxime Beauchemin
a4c79648a9 Minor cosmetic changes 2016-01-10 09:57:45 -08:00
Maxime Beauchemin
fc038a6e78 JS bugfixes 2016-01-09 21:14:21 -08:00
Maxime Beauchemin
c9d42176f5 Merge pull request #104 from bradmbaker/brad_baker_fixing_tooltips_v2
simplifying tooltip code
2016-01-09 08:29:05 -08:00
Maxime Beauchemin
baf759b3ca Merge pull request #105 from bradmbaker/brad_baker_adding_stagger_to_all_date_charts
adding stagger for all charts that have a date axis
2016-01-08 18:10:15 -08:00
BradBaker
99aa6f71e2 adding stagger for all charts that have a date axis 2016-01-08 16:20:22 -08:00
BradBaker
e4f45ac285 simplifying tooltip code 2016-01-08 16:09:45 -08:00
Maxime Beauchemin
e36ebfe640 Merge pull request #102 from bradmbaker/brad_baker_adding_two_x_axis_rescaling_to_nvd3_file
Fix for 2-axis charts where it shrinks them a little bit
2016-01-08 14:27:20 -08:00
bradmbaker
7e827da3b1 fixing indents 2016-01-08 14:26:49 -08:00
Maxime Beauchemin
897d519b1b Merge pull request #101 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2016-01-08 13:11:57 -08:00
BradBaker
98809cb3f4 Fix for 2-axis charts where it shrinks them a little bit 2016-01-08 12:12:26 -08:00
Maxime Beauchemin
eafd438323 Merge pull request #100 from bradmbaker/patch-1
Update tooltips with new classes
2016-01-06 16:50:57 -08:00
Maxime Beauchemin
09b8ed5548 Adding link to Gitter channel in README 2016-01-06 16:47:53 -08:00
The Gitter Badger
05b391cf1c Add Gitter badge 2016-01-07 00:46:40 +00:00
Maxime Beauchemin
9bc2f08b10 Improving the Test Connection button 2016-01-06 16:02:50 -08:00
bradmbaker
a04cf2706f Update tooltips with new classes
The li classes changed, so I'm updating so that the tooltip overflow works. I also changed a variable name to be correct.
2016-01-06 15:49:49 -08:00
Maxime Beauchemin
27ceb150c3 Fixing jumpy clock number 2016-01-06 14:41:05 -08:00
Maxime Beauchemin
3fa3ce1a12 Fixing resampling options 2016-01-06 14:27:10 -08:00
Maxime Beauchemin
51e9cb3d3e Making all nvd3 timeseries have the full fieldset 2016-01-06 14:21:03 -08:00
Maxime Beauchemin
ee73b6fd12 Changing the time range selector default to False 2016-01-06 14:13:34 -08:00
Maxime Beauchemin
cd1258dfc0 Merge pull request #99 from mistercrunch/resample
Time resampling as in Pandas
2016-01-06 14:07:34 -08:00
Maxime Beauchemin
3216fa2140 Allowing line breaks in fieldsets 2016-01-06 14:02:58 -08:00
Maxime Beauchemin
1b7725b303 Merge pull request #98 from bradmbaker/patch-1
Change Scaling to Operate on SVG instead of Div
2016-01-06 13:58:10 -08:00
Maxime Beauchemin
ade917582f Adding basic resampling capabilities from pandas 2016-01-06 13:52:09 -08:00
bradmbaker
9959d266f0 Change Scaling to Operate on SVG instead of Div 2016-01-06 13:49:18 -08:00
Maxime Beauchemin
4f12e78a64 Fixed left panel in explore view 2016-01-06 13:32:47 -08:00
Maxime Beauchemin
3a3e7c8964 A much more clear TODO.md 2015-12-29 13:47:21 -08:00
Maxime Beauchemin
3f292e6308 Merge pull request #96 from mistercrunch/filter_box
Adding a filter box widget
2015-12-29 08:26:50 -08:00
Maxime Beauchemin
37cbf61480 Adding markdown support for table descriptions 2015-12-27 21:06:16 -08:00
Maxime Beauchemin
6df3e67bdb Fixing the filters 2015-12-27 14:21:10 -08:00
Maxime Beauchemin
ef14c21281 Adding volume indicators on filter box 2015-12-27 09:46:07 -08:00
Maxime Beauchemin
5ad4f38c49 Fixing images in docs 2015-12-26 14:04:46 -08:00
Maxime Beauchemin
07df0f109f Adding a filter box widget 2015-12-26 12:50:46 -08:00
Maxime Beauchemin
fa0d6c6776 Merge pull request #95 from mistercrunch/docs2
Working on docs
2015-12-25 21:49:06 -08:00
Maxime Beauchemin
e96494e0cf Working on docs 2015-12-25 21:48:09 -08:00
Maxime Beauchemin
0a9600d994 Minor improvements on the bubble plot 2015-12-24 22:57:21 -08:00
Maxime Beauchemin
9d0de6c8e7 Merge pull request #94 from mistercrunch/context
Massive js refactor + Dashboard filters
2015-12-24 11:57:36 -08:00
Maxime Beauchemin
010fbc3693 Fixed standalone view 2015-12-24 09:24:44 -08:00
Maxime Beauchemin
dfee55df1a Fixing save ops 2015-12-24 09:17:38 -08:00
Maxime Beauchemin
9427cd6216 Fixing date processing 2015-12-24 08:41:35 -08:00
Maxime Beauchemin
e7ccbefe87 Achieving ASYNC explore 2015-12-23 13:35:20 -08:00
Maxime Beauchemin
527bc14162 TODO 2015-12-23 12:45:18 -08:00
Maxime Beauchemin
b88f2825ea Improvements to bubble chart 2015-12-23 07:53:21 -08:00
Maxime Beauchemin
c3bec3e35b refactoring the imports 2015-12-22 22:54:54 -08:00
Maxime Beauchemin
a5c1358229 Fixing py3 error 2015-12-22 20:46:19 -08:00
Maxime Beauchemin
0f892c6a4d Fixing sqlite error msg 2015-12-22 20:35:35 -08:00
Maxime Beauchemin
afae89239d Adding another example file 2015-12-22 15:56:18 -08:00
Maxime Beauchemin
8682196eb8 Getting filters to a reasonable place 2015-12-22 15:52:15 -08:00
Maxime Beauchemin
e0586ec666 Working state 2015-12-22 15:35:06 -08:00
Maxime Beauchemin
4e21fb4285 Adding support for quoted field names 2015-12-22 08:12:47 -08:00
Maxime Beauchemin
6a28ad3f4e Adding standalone mode 2015-12-21 08:17:02 -08:00
Maxime Beauchemin
fffb0a7a80 Getting rid of the template heavy approach 2015-12-21 00:05:50 -08:00
Maxime Beauchemin
458703d9c8 Getting the dashboard filters to work 2015-12-20 21:49:59 -08:00
Maxime Beauchemin
b1399b97a9 Progress 2015-12-20 15:04:16 -08:00
Maxime Beauchemin
48f5fcfcc7 Some major refactoring 2015-12-20 13:54:40 -08:00
Maxime Beauchemin
4b481e938a Getting in a working state 2015-12-20 08:33:08 -08:00
Maxime Beauchemin
973f1a6235 removing table-info from featured datasets 2015-12-19 07:40:24 -08:00
Maxime Beauchemin
1893e90e34 Merge pull request #93 from mistercrunch/controller
Controller
2015-12-18 16:52:16 -08:00
Maxime Beauchemin
c1080638ae Passing a ctrl to the js 2015-12-18 15:45:11 -08:00
Maxime Beauchemin
5435f53702 Passing a controller object to widget 2015-12-18 15:09:14 -08:00
Maxime Beauchemin
47bb6b61ef Merge pull request #92 from mistercrunch/nogroupby
Allowing not to group by on table view
2015-12-18 15:07:44 -08:00
Maxime Beauchemin
19eb177fe3 Changing resize action to do nothing 2015-12-18 14:49:18 -08:00
Maxime Beauchemin
bd75a58f24 Re writting table viz 2015-12-18 14:42:44 -08:00
Maxime Beauchemin
55c4433b0b Allowing to not group by on table view 2015-12-18 12:06:01 -08:00
Maxime Beauchemin
1377c37b7b Merge pull request #91 from mistercrunch/exports
Exports
2015-12-17 20:37:09 -08:00
Maxime Beauchemin
d933810cae updating TODO 2015-12-17 18:15:19 -08:00
Maxime Beauchemin
1cd63c3e4a Adding a unit test 2015-12-17 18:14:40 -08:00
Maxime Beauchemin
5f6236c80b Export to csv or json 2015-12-17 18:14:40 -08:00
Maxime Beauchemin
31dd5bf1b3 Merge pull request #90 from mistercrunch/docs
A basic squeleton for the docs
2015-12-17 18:14:03 -08:00
Maxime Beauchemin
880c7397e1 A basic squeleton for the docs 2015-12-17 16:26:36 -08:00
Maxime Beauchemin
d2ae6ceed6 Merge pull request #89 from mistercrunch/featured_datasets
Featured datasets
2015-12-17 15:52:55 -08:00
Michelle Thomas
79e7818ba8 Changes to the layout of the featured datasets page 2015-12-17 15:43:28 -08:00
Maxime Beauchemin
2a30908328 Merge branch 'master' of github.com:mistercrunch/panoramix 2015-12-17 13:49:47 -08:00
Maxime Beauchemin
4e3d284785 Restoring error bubbling 2015-12-17 13:49:36 -08:00
Michelle Thomas
e5256ef6da Fixing alignment of a hanging indent for code quality 2015-12-17 11:35:18 -08:00
Michelle Thomas
f24e58abf2 Fixes to the downgrade migration for user_id in sqlatables 2015-12-17 11:28:06 -08:00
Maxime Beauchemin
b04c4223c5 Merge pull request #87 from bradmbaker/brad_adding_js_to_allow_overflow_to_actually_work
fixing a few bugs with tool tip overflow
2015-12-17 11:13:46 -08:00
Maxime Beauchemin
047e142b43 Merge pull request #88 from mistercrunch/map
World Map viz with bubbles
2015-12-17 11:12:09 -08:00
Maxime Beauchemin
b3edc077dc Touchups 2015-12-16 20:57:19 -08:00
Maxime Beauchemin
48c1481caa World Map with bubbles 2015-12-16 19:22:19 -08:00
Michelle Thomas
6f948f0783 Changing DataTables to default to show all and sort by database 2015-12-16 17:58:16 -08:00
Michelle Thomas
6bbcbe524a Fixing the button on the featured datasets page 2015-12-16 16:34:51 -08:00
Michelle Thomas
6155ff8de6 Adding owner to sqlatables and changing some of the formatting using DataTables 2015-12-16 15:35:59 -08:00
Michelle Thomas
30df7be258 Adding a view for featured datasets 2015-12-16 15:35:59 -08:00
BradBaker
e0f8f2cdca fixing a few bugs with tool tip overflow 2015-12-16 11:54:34 -08:00
Maxime Beauchemin
dcd36780ef Merge pull request #86 from bradmbaker/brad_adding_new_and_improved_date_formats
adjusting date formats
2015-12-16 11:45:53 -08:00
Maxime Beauchemin
d6b6433d52 Better list view for druid datasurces 2015-12-16 11:29:28 -08:00
BradBaker
e2220ded7f adjusting date formats 2015-12-15 18:00:41 -08:00
Maxime Beauchemin
cf0734b8cd Merge pull request #85 from mistercrunch/sankey
Adding sankey diagrams
2015-12-15 16:05:50 -08:00
Maxime Beauchemin
c09ff2b7eb Getting the query to show 2015-12-15 16:05:35 -08:00
Maxime Beauchemin
0b0a095163 Adding sankey diagrams 2015-12-15 15:59:58 -08:00
Maxime Beauchemin
eb6890f742 Namespacing sunburst CSS 2015-12-15 14:31:43 -08:00
Maxime Beauchemin
c2736b34cd Making row_limit freeform 2015-12-15 14:16:40 -08:00
Maxime Beauchemin
d4588e00ea Merge pull request #84 from mistercrunch/force
Adding directed force layout viz
2015-12-15 14:03:55 -08:00
Maxime Beauchemin
c563057099 Adding directed force layout viz 2015-12-15 13:59:31 -08:00
Maxime Beauchemin
f1ceac996c Merge pull request #83 from mistercrunch/js
Big JS refactor
2015-12-15 13:59:06 -08:00
Maxime Beauchemin
51b273b5b8 Big JS refactor 2015-12-14 22:18:26 -08:00
Maxime Beauchemin
f8963e0b30 Merge pull request #82 from bradmbaker/letting_tool_tips_overflow
letting tooltips in the dashboard overflow
2015-12-14 16:25:53 -08:00
BradBaker
65be15cc8d letting tooltips in the dashboard overflow 2015-12-14 13:46:05 -08:00
Maxime Beauchemin
c6d007cc8b Style 2015-12-14 10:21:46 -08:00
Maxime Beauchemin
eb13ce1840 Cleaning up the html indentation on explore.html 2015-12-14 08:48:37 -08:00
Maxime Beauchemin
6b069c6741 Cosmetics on dropdowns 2015-12-14 08:21:49 -08:00
Maxime Beauchemin
5f6a7423b8 Merge pull request #81 from mistercrunch/layout
Slightly better layout for explore page
2015-12-14 08:10:23 -08:00
Maxime Beauchemin
d50a768df9 Fix td align 2015-12-14 08:09:20 -08:00
Maxime Beauchemin
387bbb8b24 Merge pull request #80 from mistercrunch/checkboxes
Checkboxes everywhere
2015-12-13 17:46:35 -08:00
Maxime Beauchemin
0d6720ad37 Checkboxes everywhere 2015-12-13 13:29:13 -08:00
Maxime Beauchemin
c97b0b6026 Slightly better layout for explore page 2015-12-13 10:03:06 -08:00
Maxime Beauchemin
06c12e7cd9 Merge pull request #79 from mistercrunch/freeform_dropd
Cleanup around multiple select fields
2015-12-13 07:55:15 -08:00
Maxime Beauchemin
5701696c79 py3 compatibility 2015-12-12 19:17:09 -08:00
Maxime Beauchemin
f4e4c529a0 Cleanup around multiple select fields 2015-12-12 18:55:56 -08:00
Maxime Beauchemin
08fd4d1258 0.6.1 2015-12-12 09:44:56 -08:00
Maxime Beauchemin
18a2670f41 [bugfix] sqlite ALTER issue 2015-12-12 09:43:23 -08:00
Maxime Beauchemin
65c1c42bc8 Align dashboard title 2015-12-11 14:33:19 -08:00
Maxime Beauchemin
1fe15496ce Formatting change_on column in list views 2015-12-11 12:17:23 -08:00
Maxime Beauchemin
b628713685 Adding a link section to readme 2015-12-11 08:51:13 -08:00
Maxime Beauchemin
59c1ee3c03 fix migrations 2015-12-10 18:04:43 -08:00
Maxime Beauchemin
a4065e4be6 v0.6.0 2015-12-10 17:17:28 -08:00
Maxime Beauchemin
d3c0a86e67 Merge pull request #77 from mistercrunch/tooltips
Better tooltips and more ways to integrate them easily
2015-12-10 11:08:06 -08:00
Maxime Beauchemin
fc93f36339 Better tooltips and more ways to integrate them easily 2015-12-10 08:26:01 -08:00
Maxime Beauchemin
c64473c49e [sunburst] limit -> row_limit 2015-12-09 22:37:49 -08:00
Maxime Beauchemin
c3f96074b9 Insuring column order 2015-12-09 18:11:45 -08:00
Maxime Beauchemin
16859117fe Merge pull request #76 from mistercrunch/form_overrides
Introducing form overrides for label and tooltips
2015-12-09 15:33:55 -08:00
Maxime Beauchemin
d476dd2b8a Introducing form overrides for label and tooltips 2015-12-09 15:19:43 -08:00
Maxime Beauchemin
9c0dd5bf3c Merge pull request #75 from mistercrunch/sunburst
New viz: sunbursts
2015-12-09 14:44:13 -08:00
Maxime Beauchemin
f5b4a0290e New viz: sunbursts 2015-12-09 14:37:18 -08:00
Maxime Beauchemin
d526711f1e Changing default sort order for databases 2015-12-08 15:09:58 -08:00
Maxime Beauchemin
2833bd3825 bugfix - empty slug field 2015-12-08 14:15:48 -08:00
Maxime Beauchemin
021654cdf1 Merge pull request #74 from mistercrunch/fieldsets
Introducing fieldsets
2015-12-07 23:28:57 -08:00
Maxime Beauchemin
a32712d9cb Cleaning up 2015-12-07 23:24:43 -08:00
Maxime Beauchemin
b666508085 Introducing field sets 2015-12-07 22:25:01 -08:00
Maxime Beauchemin
6f2c953a9e Merge pull request #73 from mistercrunch/theme
Airflowlike theme
2015-12-04 15:05:10 -08:00
Maxime Beauchemin
1a62d5f74f Bugfix pivot table with no groupby 2015-12-04 14:24:36 -08:00
Maxime Beauchemin
04c0c05c01 Airflowlike theme 2015-12-04 14:16:31 -08:00
Maxime Beauchemin
6dc21c1e78 Merge pull request #72 from mistercrunch/log
Logging slice and dash views
2015-12-04 11:55:59 -08:00
Maxime Beauchemin
f882ff13ff Logging slice and dash views 2015-12-04 11:52:32 -08:00
Maxime Beauchemin
aed2f46413 Merge pull request #70 from mistercrunch/dash_slug
Adding url slug support for dashboard model
2015-12-04 10:30:28 -08:00
Maxime Beauchemin
a0e967e3b9 Merge pull request #71 from mistercrunch/showminmax
Add option to show minmax on x axis
2015-12-04 10:30:12 -08:00
Maxime Beauchemin
66089a8948 Adding migration file 2015-12-04 10:13:16 -08:00
Maxime Beauchemin
7ac0615d83 Merge pull request #69 from mistercrunch/save_as
Allowing for [Save AS] and [Overwrite]
2015-12-04 10:10:59 -08:00
Maxime Beauchemin
63b27bbece Add option to show minmax on x axis 2015-12-04 10:10:13 -08:00
Maxime Beauchemin
2743b2412f Adding url slug support for dashboard model 2015-12-04 10:02:16 -08:00
Maxime Beauchemin
b9d7253a48 Save AS and Overwrite 2015-12-04 09:30:43 -08:00
Maxime Beauchemin
618e117374 Merge pull request #68 from mistercrunch/cumsum
Adding cumsum to rolling functions
2015-11-30 15:07:05 -08:00
Maxime Beauchemin
03e13cb957 Adding cumsum to rolling functions 2015-11-30 14:58:15 -08:00
Maxime Beauchemin
525bd509cb Merge pull request #67 from mistercrunch/fix_debug_dup_call
Fix debug mode calls get_json twice
2015-11-30 13:48:11 -08:00
Maxime Beauchemin
2002f5e369 Fix debug mode calls get_json twice 2015-11-30 12:36:59 -08:00
Maxime Beauchemin
852e3c6667 Merge pull request #66 from mistercrunch/pivot_table
Adding a PivotTableViz
2015-11-26 07:10:22 -08:00
Maxime Beauchemin
7cd3696dd2 Adding missing jquery-ui images 2015-11-24 12:30:37 -08:00
Maxime Beauchemin
139e594cce Bugfix, wrong css reference 2015-11-24 12:21:36 -08:00
Maxime Beauchemin
b0f7b3c595 A little bit more explicit error handling 2015-11-24 12:09:30 -08:00
Maxime Beauchemin
8b0b13eedc Adding a PivotTableViz 2015-11-24 11:54:43 -08:00
Maxime Beauchemin
5968344613 Merge pull request #65 from mistercrunch/custom_having
Adding custom HAVING clause
2015-11-24 11:51:33 -08:00
Maxime Beauchemin
16c81280e6 Merge pull request #64 from mistercrunch/sort_select2
Preserving the ordering in selectmultiple
2015-11-24 11:51:28 -08:00
Maxime Beauchemin
4819be2fb2 Adding groupby to select2Sortable 2015-11-24 11:46:44 -08:00
Maxime Beauchemin
3cc5db5bbf Adding custom HAVING clause 2015-11-24 11:37:20 -08:00
Maxime Beauchemin
c8faeed5b3 Preserving the ordering in selectmultiple 2015-11-24 10:52:32 -08:00
Maxime Beauchemin
de52449c2a Removing dups in color array 2015-11-23 16:42:30 -08:00
Maxime Beauchemin
2e83bf3850 Merge pull request #63 from mistercrunch/hide_pass
Encrypting the passwords out of connection strings
2015-11-23 08:45:13 -08:00
Maxime Beauchemin
85227912b3 Encrypting the passwords out of connection strings 2015-11-21 12:35:49 -08:00
Maxime Beauchemin
4645c69c85 Merge pull request #61 from mistercrunch/better-boolean-field
BetterBooleanField to fix html omitting non-checked <input>
2015-11-14 18:50:06 -08:00
Patrick Leo Tardif
f592aa1012 Add BetterBooleanField 2015-11-13 17:16:34 -08:00
Maxime Beauchemin
d8c79cd26e bugfix for error msg not surfaced 2015-11-11 12:18:20 -08:00
Maxime Beauchemin
184262844a Fixing resize for nvd3 widgets 2015-11-10 17:01:04 -08:00
Maxime Beauchemin
9d65f8d866 Merge pull request #60 from NiharikaRay/fix_markup_widget
Fix Markup Widget bug
2015-11-10 12:26:33 -08:00
Niharika Ray
54e45babe7 Fix Markup Widget bug 2015-11-10 12:22:51 -08:00
Maxime Beauchemin
3c5867cafb Merge pull request #59 from patrickleotardif/y_axis_format
Adding y-axis format option
2015-11-10 11:59:19 -08:00
Patrick Leo Tardif
93c660f2c7 make y axis format one col width only 2015-11-10 11:33:35 -08:00
Patrick Leo Tardif
4233d34678 handle y2axis for y axis format 2015-11-10 11:33:05 -08:00
Patrick Leo Tardif
6b13d78f69 verbose explanation and link for d3 format" 2015-11-10 11:32:42 -08:00
Patrick Leo Tardif
38a4157ac6 Adding y-axis format option 2015-11-09 18:30:55 -08:00
Maxime Beauchemin
774ca9fa2f Merge pull request #58 from mistercrunch/min_periods
Setting min_periods to 1 for rolling windows
2015-11-08 09:13:17 -08:00
Maxime Beauchemin
d75c5c8da8 Setting min_periods to 1 for rolling windows 2015-11-08 09:10:45 -08:00
Maxime Beauchemin
a18cf2d26b Adding audit info to a few list views 2015-11-04 17:06:17 -08:00
Maxime Beauchemin
0889947394 Clarifying time filters, small refactor 2015-11-03 09:52:19 -08:00
Maxime Beauchemin
4e6aa4c5b5 Improvments around date handling for nvd3 charts 2015-10-31 15:34:23 -07:00
Krishna Puttaswamy
ed19b8e7eb Merge pull request #56 from mistercrunch/kp_enable_sort_order
adding sort order of the slices on changed_on field
2015-10-27 11:40:22 -07:00
Krishna Puttaswamy
6ecea9123c adding sort order of the slices on changed_on field 2015-10-27 11:36:25 -07:00
Maxime Beauchemin
5057593ec9 v0.5.3 2015-10-24 08:02:16 -07:00
Maxime Beauchemin
ec805d3bd8 pinning flask-sqlalchemy==2.0 2015-10-24 07:54:03 -07:00
Maxime Beauchemin
774f205d24 pinning sqla 2015-10-24 07:49:46 -07:00
Maxime Beauchemin
c07770e52a v0.5.2 2015-10-23 18:06:01 -07:00
Maxime Beauchemin
0ec69a4ac5 druid bugfix 2015-10-20 16:40:12 -07:00
Maxime
30513116f9 Using mysqlclient instead of pymysql 2015-10-20 22:26:55 +00:00
Maxime Beauchemin
c3903eff4f Adding forgotten template 2015-10-20 14:11:21 -07:00
Maxime Beauchemin
ac79265dcb Merge pull request #53 from mistercrunch/py3
Py3
2015-10-20 13:46:57 -07:00
Maxime Beauchemin
4d8966376f Aiming at python 3.4 - test 2015-10-20 13:19:13 -07:00
Maxime Beauchemin
a58d184711 Removing references to basestring 2015-10-20 13:00:42 -07:00
Maxime Beauchemin
fc76e87653 Trying mode='rt' 2015-10-20 12:50:12 -07:00
Maxime Beauchemin
e3e3d0b1f5 py3 compat changes 2015-10-20 12:50:11 -07:00
Maxime Beauchemin
5a967031c8 Adding python 3.5 to build matrix 2015-10-20 12:49:02 -07:00
Maxime Beauchemin
1ffb9a0fc6 Reverting to old deps notation as server is on 2.7.3 2015-10-20 12:42:19 -07:00
Maxime Beauchemin
2ddebc1a4c Pinning flask version 2015-10-20 12:21:44 -07:00
Maxime Beauchemin
8b67fa1d54 Merge pull request #51 from mistercrunch/offset
Adding timezone offset as a datasource param
2015-10-19 23:53:11 -07:00
Maxime Beauchemin
cdb32a1149 Merge pull request #52 from mistercrunch/travis_speedup
Speed up travis builds with wheels
2015-10-19 23:43:46 -07:00
Maxime Beauchemin
bdd5b08787 Cleaning up reqs versions 2015-10-19 23:34:48 -07:00
Maxime Beauchemin
ea18aad3b2 Speed up travis builds with wheels 2015-10-19 22:54:53 -07:00
Maxime Beauchemin
a7fca30010 Tweaks 2015-10-19 22:15:53 -07:00
Maxime Beauchemin
06e57bf890 Adding timezone offset as a datasource param 2015-10-19 21:43:14 -07:00
Maxime Beauchemin
8aa97f7e08 Better defaults for Druid endpoints and better error handling 2015-10-16 07:41:52 -07:00
Maxime Beauchemin
9d61ee2323 Bugfix for time series bar chart 2015-10-15 21:08:52 -07:00
Maxime Beauchemin
960596228e +entry in TODO 2015-10-14 08:39:18 -07:00
Maxime Beauchemin
4837968ea4 Merge pull request #48 from mistercrunch/timeout
Allowing to specify the gunicorn timeout in CLI and config
2015-10-13 16:09:24 -07:00
Maxime Beauchemin
0a1eb64da0 Bumping timeout to 60 2015-10-13 16:06:37 -07:00
Maxime Beauchemin
686069d283 Allowing to specify the gunicorn timeout in CLI and config 2015-10-13 15:50:12 -07:00
Maxime Beauchemin
7793e243ad Note about python version support 2015-10-13 09:41:27 -07:00
Maxime Beauchemin
37629fb548 v0.5.1 2015-10-13 08:05:40 -07:00
232 changed files with 18646 additions and 6010 deletions

View File

@@ -1 +1 @@
repo_token: EMkVRVEKYgUESKaNN9QyOhPnFnKNqyDcJ
repo_token: eESbYiv4An6KEvjpmguDs4L7YkubXbqn1

18
.gitignore vendored
View File

@@ -1,14 +1,26 @@
*.pyc
babel
.DS_Store
.coverage
panoramix/bin/panoramixc
_build
_static
_images
caravel/bin/caravelc
env_py3
.eggs
build
*.db
tmp
panoramix_config.py
caravel_config.py
local_config.py
env
dist
panoramix.egg-info/
caravel.egg-info/
app.db
*.bak
# Node.js, webpack artifacts
*.entry.js
*.js.map
node_modules
npm-debug.log

23
.landscape.yml Normal file
View File

@@ -0,0 +1,23 @@
doc-warnings: yes
test-warnings: no
strictness: medium
max-line-length: 90
uses:
- flask
autodetect: yes
pylint:
disable:
- cyclic-import
- invalid-name
- logging-format-interpolation
options:
docstring-min-length: 10
pep8:
full: true
ignore-paths:
- docs
- caravel/migrations/env.py
- caravel/ascii_art.py
ignore-patterns:
- ^example/doc_.*\.py$
- (^|/)docs(/|$)

View File

@@ -1,12 +1,22 @@
language: python
python:
- "2.7"
#- "3.5"
# command to install dependencies
- "3.4"
cache:
directories:
- $HOME/.wheelhouse/
before_install:
- npm install -g npm@'>=2.7.1'
install:
- python setup.py install
- pip install -r requirements.txt
# command to run tests
- pip wheel -w $HOME/.wheelhouse -f $HOME/.wheelhouse .
- pip install --find-links=$HOME/.wheelhouse --no-index .
- pip install --find-links=$HOME/.wheelhouse --no-index -r dev-reqs.txt
- cd caravel/assets
- npm --version
- npm install
- npm run lint
- npm run prod
- cd $TRAVIS_BUILD_DIR
script: bash run_tests.sh
after_success: coveralls
after_success:
- coveralls

185
CHANGELOG.md Normal file
View File

@@ -0,0 +1,185 @@
## Change Log
### 0.8.5 (2016/04/01 20:30 +00:00)
- [#234](https://github.com/airbnb/caravel/pull/234) Pin pandas, remove numpy (@mistercrunch)
- [#229](https://github.com/airbnb/caravel/pull/229) Remove "requirements.txt" mention from README (@jmcomets)
- [#225](https://github.com/airbnb/caravel/pull/225) remove power units from sankey diagram (@williaster)
- [#219](https://github.com/airbnb/caravel/pull/219) Add 'Percent of previous' to sunburst vis. Appease npm warnings for data tables and d3.layout.cloud (@williaster)
- [#224](https://github.com/airbnb/caravel/pull/224) Fixing minor typos in the readme (@cyrusstoller)
- [#214](https://github.com/airbnb/caravel/pull/214) Fix an installation bug. (@kim-pham-airbnb)
- [#218](https://github.com/airbnb/caravel/pull/218) Redirecting URL from previous names to caravel (@mistercrunch)
- [#223](https://github.com/airbnb/caravel/pull/223) Fixed typo in README (@thebucknerlife)
- [#222](https://github.com/airbnb/caravel/pull/222) remove duplicate Druid.io section in README.md (@brchristian)
- [#213](https://github.com/airbnb/caravel/pull/213) Fix a bug when loading DruidDatasource. (@kim-pham-airbnb)
- [#204](https://github.com/airbnb/caravel/pull/204) Fixing the order and coverage report for the unit tests (@mistercrunch)
- [#209](https://github.com/airbnb/caravel/pull/209) Fresh screenshots (@mistercrunch)
- [#206](https://github.com/airbnb/caravel/pull/206) Caravel (@mistercrunch)
- [#205](https://github.com/airbnb/caravel/pull/205) fix sunburst error. add `less` to package.json (@williaster)
- [#203](https://github.com/airbnb/caravel/pull/203) Fixing mysql install (@mistercrunch)
- [#202](https://github.com/airbnb/caravel/pull/202) Using setup.py nosetests to run tests (@mistercrunch)
- [#199](https://github.com/airbnb/caravel/pull/199) Fix a few minor bugs (@mistercrunch)
- [#200](https://github.com/airbnb/caravel/pull/200) Add a sankey example (@mistercrunch)
- [#192](https://github.com/airbnb/caravel/pull/192) Fix Druid metadata refresh. (@kim-pham-airbnb)
- [#198](https://github.com/airbnb/caravel/pull/198) A welcome page (@mistercrunch)
- [#197](https://github.com/airbnb/caravel/pull/197) Adding a DRUID_IS_ACTIVE flag and changing nav bar (@NiharikaRay)
- [#196](https://github.com/airbnb/caravel/pull/196) Fixing issues around fk nullable=False on audit fields (@mistercrunch)
### 0.8.4 (2016/03/24 05:26 +00:00)
- [#193](https://github.com/airbnb/caravel/pull/193) Adding favorites for Slices and Dashboards (@mistercrunch)
### 0.8.2 (2016/03/23 20:43 +00:00)
- [#188](https://github.com/airbnb/caravel/pull/188) Introducing a caching layer! (@mistercrunch)
### 0.8.1 (2016/03/21 23:41 +00:00)
- [#191](https://github.com/airbnb/caravel/pull/191) Add week ending and week start to grain (@airbnb)
- [#190](https://github.com/airbnb/caravel/pull/190) Cranking up version numbers (@mistercrunch)
- [#184](https://github.com/airbnb/caravel/pull/184) sunburst improvements (@williaster)
- [#186](https://github.com/airbnb/caravel/pull/186) Adding docstrings ! (@mistercrunch)
- [#181](https://github.com/airbnb/caravel/pull/181) Dynamic time granularity on any datetime column (@mistercrunch)
- [#182](https://github.com/airbnb/caravel/pull/182) more css fixes (@williaster)
- [#178](https://github.com/airbnb/caravel/pull/178) Allowing all extra fields in AuditMixin to be nullable (@mistercrunch)
- [#175](https://github.com/airbnb/caravel/pull/175) refactor dashboard chart html, make several css improvements. (@williaster)
### 0.8.0 (2016/03/11 03:33 +00:00)
- [#172](https://github.com/airbnb/caravel/pull/172) Fixing the python and js packaging (@mistercrunch)
- [#171](https://github.com/airbnb/caravel/pull/171) Fixing multiple refresh bug in filter_box (@mistercrunch)
- [#169](https://github.com/airbnb/caravel/pull/169) Fixing the look of select2 components (@mistercrunch)
- [#168](https://github.com/airbnb/caravel/pull/168) Getting travis to build the npm related stuff (@mistercrunch)
- [#166](https://github.com/airbnb/caravel/pull/166) make css theme customization easier by using less for bootstrap themes (@williaster)
- [#163](https://github.com/airbnb/caravel/pull/163) Shipping with CSS templates out of the box (@mistercrunch)
- [#164](https://github.com/airbnb/caravel/pull/164) Improving the docs (@mistercrunch)
- [#165](https://github.com/airbnb/caravel/pull/165) Fixing window resize for explore and standalone (@mistercrunch)
- [#161](https://github.com/airbnb/caravel/pull/161) Add linting to package.json, do all of the linting. (@williaster)
- [#160](https://github.com/airbnb/caravel/pull/160) Fixing the dashed line when using time compare (@mistercrunch)
- [#159](https://github.com/airbnb/caravel/pull/159) Fixing the standalone mode (@mistercrunch)
- [#158](https://github.com/airbnb/caravel/pull/158) Refactor (@mistercrunch)
- [#154](https://github.com/airbnb/caravel/pull/154) Digging into leap year bug and improvming tests (@mistercrunch)
- [#157](https://github.com/airbnb/caravel/pull/157) add button to auto-copy short URLs in /explore page (@williaster)
- [#149](https://github.com/airbnb/caravel/pull/149) Allowing to make certain widgets immune to filter (@mistercrunch)
- [#151](https://github.com/airbnb/caravel/pull/151) Linting (@mistercrunch)
- [#153](https://github.com/airbnb/caravel/pull/153) Improve README (@tay)
- [#139](https://github.com/airbnb/caravel/pull/139) NPMification & Reactification (@williaster, @mistercrunch)
- [#147](https://github.com/airbnb/caravel/pull/147) Tackling Featured Datasets (@mistercrunch)
- [#148](https://github.com/airbnb/caravel/pull/148) Fix typo (@tay)
- [#145](https://github.com/airbnb/caravel/pull/145) Moving files around ... yay! (@mistercrunch)
- [#142](https://github.com/airbnb/caravel/pull/142) A few cosmetic fixes (nvd3 tooltips, buttons, tables) (@mistercrunch)
- [#141](https://github.com/airbnb/caravel/pull/141) A simple base template for npm (@mistercrunch)
- [#140](https://github.com/airbnb/caravel/pull/140) use the latest segment to extract metadata (@dayzzz)
- [#136](https://github.com/airbnb/caravel/pull/136) Improved the bar char to allow for dimensional breakdowns (@mistercrunch)
- [#134](https://github.com/airbnb/caravel/pull/134) Fixing the roles auto maintenance (@mistercrunch)
- [#132](https://github.com/airbnb/caravel/pull/132) [nvd3] fixing the legend toggle bug (@mistercrunch)
- [#131](https://github.com/airbnb/caravel/pull/131) More tests using doctests! (@mistercrunch)
- [#130](https://github.com/airbnb/caravel/pull/130) Logging more (@mistercrunch)
- [#129](https://github.com/airbnb/caravel/pull/129) Renaming Classes related to Druid (@mistercrunch)
- [#127](https://github.com/airbnb/caravel/pull/127) SQL editor, eventually will be tied to a flow to create views (@mistercrunch)
- [#128](https://github.com/airbnb/caravel/pull/128) Allowing definition of css templates (@mistercrunch)
- [#126](https://github.com/airbnb/caravel/pull/126) New viz: Heatmap! (@mistercrunch)
- [#125](https://github.com/airbnb/caravel/pull/125) Consistent colors rendered client side (@mistercrunch)
- [#124](https://github.com/airbnb/caravel/pull/124) A more cohesive color strategy (@mistercrunch)
### 0.7.0 (2016/01/23 15:16 +00:00)
- [#123](https://github.com/airbnb/caravel/pull/123) Adding a color factory (@mistercrunch)
- [#122](https://github.com/airbnb/caravel/pull/122) Adding Parallel coordinates viz (@mistercrunch)
- [#121](https://github.com/airbnb/caravel/pull/121) Iframe (@mistercrunch)
- [#120](https://github.com/airbnb/caravel/pull/120) Slice information can be displayed in dashboard (@mistercrunch)
- [#117](https://github.com/airbnb/caravel/pull/117) Doing some refactoring (@mistercrunch)
- [#115](https://github.com/airbnb/caravel/pull/115) Providing options for Y axis number formating (@mistercrunch)
- [#112](https://github.com/airbnb/caravel/pull/112) Adding an URL shortner (@mistercrunch)
- [#113](https://github.com/airbnb/caravel/pull/113) Prettier checkboxes (@mistercrunch)
- [#111](https://github.com/airbnb/caravel/pull/111) Loading another example amazing dash (@mistercrunch)
- [#109](https://github.com/airbnb/caravel/pull/109) Getting browser history to work on the explore view (@mistercrunch)
- [#108](https://github.com/airbnb/caravel/pull/108) pulling to the front on hover (@BradBaker)
- [#104](https://github.com/airbnb/caravel/pull/104) simplifying tooltip code (@BradBaker)
- [#105](https://github.com/airbnb/caravel/pull/105) adding stagger for all charts that have a date axis (@BradBaker)
- [#102](https://github.com/airbnb/caravel/pull/102) Fix for 2-axis charts where it shrinks them a little bit (@bradmbaker, @BradBaker)
- [#101](https://github.com/airbnb/caravel/pull/101) Add a Gitter chat badge to README.md (@gitter-badger)
- [#100](https://github.com/airbnb/caravel/pull/100) Update tooltips with new classes (@bradmbaker)
- [#99](https://github.com/airbnb/caravel/pull/99) Time resampling as in Pandas (@mistercrunch)
- [#98](https://github.com/airbnb/caravel/pull/98) Change Scaling to Operate on SVG instead of Div (@bradmbaker)
- [#96](https://github.com/airbnb/caravel/pull/96) Adding a filter box widget (@mistercrunch)
- [#95](https://github.com/airbnb/caravel/pull/95) Working on docs (@mistercrunch)
- [#94](https://github.com/airbnb/caravel/pull/94) Massive js refactor + Dashboard filters (@mistercrunch)
- [#93](https://github.com/airbnb/caravel/pull/93) Controller (@mistercrunch)
- [#92](https://github.com/airbnb/caravel/pull/92) Allowing not to group by on table view (@mistercrunch)
- [#91](https://github.com/airbnb/caravel/pull/91) Exports (@mistercrunch)
- [#90](https://github.com/airbnb/caravel/pull/90) A basic squeleton for the docs (@mistercrunch)
- [#89](https://github.com/airbnb/caravel/pull/89) Featured datasets (@michellethomas)
- [#87](https://github.com/airbnb/caravel/pull/87) fixing a few bugs with tool tip overflow (@BradBaker)
- [#88](https://github.com/airbnb/caravel/pull/88) World Map viz with bubbles (@mistercrunch)
- [#86](https://github.com/airbnb/caravel/pull/86) adjusting date formats (@BradBaker)
- [#85](https://github.com/airbnb/caravel/pull/85) Adding sankey diagrams (@mistercrunch)
- [#84](https://github.com/airbnb/caravel/pull/84) Adding directed force layout viz (@mistercrunch)
- [#83](https://github.com/airbnb/caravel/pull/83) Big JS refactor (@mistercrunch)
- [#82](https://github.com/airbnb/caravel/pull/82) letting tooltips in the dashboard overflow (@BradBaker)
- [#81](https://github.com/airbnb/caravel/pull/81) Slightly better layout for explore page (@mistercrunch)
- [#80](https://github.com/airbnb/caravel/pull/80) Checkboxes everywhere (@mistercrunch)
- [#79](https://github.com/airbnb/caravel/pull/79) Cleanup around multiple select fields (@mistercrunch)
### 0.6.0 (2015/12/11 01:17 +00:00)
- [#77](https://github.com/airbnb/caravel/pull/77) Better tooltips and more ways to integrate them easily (@mistercrunch)
- [#76](https://github.com/airbnb/caravel/pull/76) Introducing form overrides for label and tooltips (@mistercrunch)
- [#75](https://github.com/airbnb/caravel/pull/75) New viz: sunbursts (@mistercrunch)
- [#74](https://github.com/airbnb/caravel/pull/74) Introducing fieldsets (@mistercrunch)
- [#73](https://github.com/airbnb/caravel/pull/73) Airflowlike theme (@mistercrunch)
- [#72](https://github.com/airbnb/caravel/pull/72) Logging slice and dash views (@mistercrunch)
- [#70](https://github.com/airbnb/caravel/pull/70) Adding url slug support for dashboard model (@mistercrunch)
- [#71](https://github.com/airbnb/caravel/pull/71) Add option to show minmax on x axis (@mistercrunch)
- [#69](https://github.com/airbnb/caravel/pull/69) Allowing for [Save AS] and [Overwrite] (@mistercrunch)
- [#68](https://github.com/airbnb/caravel/pull/68) Adding cumsum to rolling functions (@mistercrunch)
- [#67](https://github.com/airbnb/caravel/pull/67) Fix debug mode calls get_json twice (@mistercrunch)
- [#66](https://github.com/airbnb/caravel/pull/66) Adding a PivotTableViz (@mistercrunch)
- [#65](https://github.com/airbnb/caravel/pull/65) Adding custom HAVING clause (@mistercrunch)
- [#64](https://github.com/airbnb/caravel/pull/64) Preserving the ordering in selectmultiple (@mistercrunch)
- [#63](https://github.com/airbnb/caravel/pull/63) Encrypting the passwords out of connection strings (@mistercrunch)
- [#61](https://github.com/airbnb/caravel/pull/61) BetterBooleanField to fix html omitting non-checked <input> (@patrickleotardif)
- [#60](https://github.com/airbnb/caravel/pull/60) Fix Markup Widget bug (@NiharikaRay)
- [#59](https://github.com/airbnb/caravel/pull/59) Adding y-axis format option (@patrickleotardif)
- [#58](https://github.com/airbnb/caravel/pull/58) Setting min_periods to 1 for rolling windows (@mistercrunch)
- [#56](https://github.com/airbnb/caravel/pull/56) adding sort order of the slices on changed_on field (@mistercrunch)
### 0.5.2 (2015/10/24 01:06 +00:00)
- [#53](https://github.com/airbnb/caravel/pull/53) Py3 (@mistercrunch)
- [#51](https://github.com/airbnb/caravel/pull/51) Adding timezone offset as a datasource param (@mistercrunch)
- [#52](https://github.com/airbnb/caravel/pull/52) Speed up travis builds with wheels (@mistercrunch)
- [#48](https://github.com/airbnb/caravel/pull/48) Allowing to specify the gunicorn timeout in CLI and config (@mistercrunch)
### 0.5.0 (2015/10/13 01:09 +00:00)
- [#46](https://github.com/airbnb/caravel/pull/46) Allowing to change the "Time Column" on SqlA (@mistercrunch)
- [#45](https://github.com/airbnb/caravel/pull/45) Bootstrapping widgets from javascript initializer. (@akuhn)
- [#43](https://github.com/airbnb/caravel/pull/43) Supporting arbitrary expressions (@mistercrunch)
- [#42](https://github.com/airbnb/caravel/pull/42) Adding ability to style a dashboard with CSS (@mistercrunch)
- [#41](https://github.com/airbnb/caravel/pull/41) Cleaning up the static folder (@mistercrunch)
- [#35](https://github.com/airbnb/caravel/pull/35) A first draft on default security roles (@mistercrunch)
- [#40](https://github.com/airbnb/caravel/pull/40) Introducing time comparison (@mistercrunch)
- [#39](https://github.com/airbnb/caravel/pull/39) Adding interpolation choice for line charts (@mistercrunch)
- [#38](https://github.com/airbnb/caravel/pull/38) Extract css rules and scripts into separate files. (@akuhn)
- [#37](https://github.com/airbnb/caravel/pull/37) Viz type (@mistercrunch)
- [#36](https://github.com/airbnb/caravel/pull/36) Extract widget javascript to separate files. (@akuhn)
- [#34](https://github.com/airbnb/caravel/pull/34) Ripping out Highcharts. (@mistercrunch)
### 0.4.0 (2015/09/27 04:39 +00:00)
- [#33](https://github.com/airbnb/caravel/pull/33) Adding nvd3 support (@mistercrunch)
- [#32](https://github.com/airbnb/caravel/pull/32) Adding a foundation for unit tests (@mistercrunch)
- [#31](https://github.com/airbnb/caravel/pull/31) Adding a button to test connections (@mistercrunch)
- [#30](https://github.com/airbnb/caravel/pull/30) Word cloud widget! (@mistercrunch)
- [#29](https://github.com/airbnb/caravel/pull/29) Adding support for markup (html/markdown) widgets (@mistercrunch)
- [#28](https://github.com/airbnb/caravel/pull/28) Fix default Sqlite path. (@noddi)
- [#27](https://github.com/airbnb/caravel/pull/27) More refactor and bugfixes (@mistercrunch)
- [#26](https://github.com/airbnb/caravel/pull/26) Bugfix (@mistercrunch)
- [#25](https://github.com/airbnb/caravel/pull/25) Adding basic dashboarding support! (@mistercrunch)
- [#23](https://github.com/airbnb/caravel/pull/23) Custom WHERE clause for tables (not druid) + error handling refactor (@mistercrunch)
- [#22](https://github.com/airbnb/caravel/pull/22) Form factory refactor (@mistercrunch)
- [#20](https://github.com/airbnb/caravel/pull/20) add tzinfo config, useful when start druid without utc timezone (@wbchn)
### 0.2.1 (2015/09/05 22:08 +00:00)
- [#19](https://github.com/airbnb/caravel/pull/19) Preparing pypi package (@mistercrunch)
### 0.2.0 (2015/09/05 20:43 +00:00)
- [#16](https://github.com/airbnb/caravel/pull/16) Adding Bubble charts (@mistercrunch)
- [#13](https://github.com/airbnb/caravel/pull/13) Now supporting SQL Multiple database (@mistercrunch)
- [#12](https://github.com/airbnb/caravel/pull/12) Cosmetricks (@mistercrunch)
- [#11](https://github.com/airbnb/caravel/pull/11) Fixing the ways metrics are autogenerated (@mistercrunch)
- [#10](https://github.com/airbnb/caravel/pull/10) Now enabling multi-cluster, connection info managed in UI (@mistercrunch)
- [#9](https://github.com/airbnb/caravel/pull/9) Multi delete action on datasources (@mistercrunch)
- [#8](https://github.com/airbnb/caravel/pull/8) Preventing bad json from creating problems (@mistercrunch)
- [#3](https://github.com/airbnb/caravel/pull/3) Implementing my own highcharts wrapper (@mistercrunch)

View File

@@ -9,7 +9,7 @@ You can contribute in many ways:
### Report Bugs
Report bugs through Gihub
Report bugs through Github
If you are reporting a bug, please include:
@@ -28,14 +28,10 @@ open to whoever wants to implement it.
Look through the GitHub issues for features. Anything tagged with
"feature" is open to whoever wants to implement it.
We've created the operators, hooks, macros and executors we needed, but we
made sure that this part of Airflow is extensible. New operators,
hooks and operators are very welcomed!
### Documentation
Airflow could always use better documentation,
whether as part of the official Airflow docs,
Caravel could always use better documentation,
whether as part of the official Caravel docs,
in docstrings, `docs/*.rst` or even on the web as blog posts or
articles.
@@ -51,40 +47,134 @@ If you are proposing a feature:
- Remember that this is a volunteer-driven project, and that
contributions are welcome :)
## Latests Documentation
## Latest Documentation
[API Documentation](http://pythonhosted.com/airflow)
[API Documentation](http://pythonhosted.com/caravel)
## Setting up a Python development environment
# 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/caravel.git
# [optional] setup a virtual env and activate it
virtualenv env
source env/bin/activate
# install for development
python setup.py develop
# Create an admin user
fabmanager create-admin --app caravel
# Initialize the database
caravel db upgrade
# Create default roles and permissions
caravel init
# Load some data to play with
caravel load_examples
# start a dev web server
caravel runserver -d
## Setting up the node / npm javascript environment
`caravel/assets` contains all npm-managed, front end assets.
Flask-Appbuilder itself comes bundled with jQuery and bootstrap.
While these may be phased out over time, these packages are currently not
managed with npm.
### Using npm to generate bundled files
#### npm
First, npm must be available in your environment. If it is not you can run the following commands
(taken from [this source](https://gist.github.com/DanHerbert/9520689))
```
brew install node --without-npm
echo prefix=~/.npm-packages >> ~/.npmrc
curl -L https://www.npmjs.com/install.sh | sh
```
The final step is to add
`~/.node/bin` to your `PATH` so commands you install globally are usable.
Add something like this to your `.bashrc` file.
```
export PATH="$HOME/.node/bin:$PATH"
```
#### npm packages
To install third party libraries defined in `package.json`, run the
following within this directory which will install them in a
new `node_modules/` folder within `assets/`.
```
npm install
```
To parse and generate bundled files for caravel, run either of the
following commands. The `dev` flag will keep the npm script running and
re-run it upon any changes within the assets directory.
```
# Compiles the production / optimized js & css
npm run prod
# Start a web server that manages and updates your assets as you modify them
npm run dev
```
For every development session you will have to start a flask dev server
as well as an npm watcher
```
caravel runserver -d -p 8081
npm run dev
```
## Testing
Install development requirements:
pip install -r requirements.txt
Tests can then be run with:
./run_unit_tests.sh
Lint the project with:
# for python changes
flake8 changes tests
# for javascript
npm run lint
## API documentation
Generate the documentation with:
cd docs && ./build.sh
## CSS Themes
As part of the npm build process, CSS for Caravel is compiled from ```Less```, a dynamic stylesheet language.
It's possible to customize or add your own theme to Caravel, either by overriding CSS rules or preferably
by modifying the Less variables or files in ```assets/stylesheets/less/```.
The ```variables.less``` and ```bootswatch.less``` files that ship with Caravel are derived from
[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
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
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.

11
INTHEWILD.md Normal file
View File

@@ -0,0 +1,11 @@
Please use [pull requests](https://github.com/airbnb/caravel/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)
Projects
----------
- None we know of yet

View File

@@ -1,4 +1,8 @@
recursive-include panoramix/templates *
recursive-include panoramix/static *
recursive-include panoramix/data *
recursive-include panoramix/migrations *
recursive-include caravel/templates *
recursive-include caravel/static *
recursive-exclude caravel/static/assets/node_modules *
recursive-include caravel/static/assets/node_modules/font-awesome *
recursive-exclude caravel/static/docs *
recursive-exclude tests *
recursive-include caravel/data *
recursive-include caravel/migrations *

181
README.md
View File

@@ -1,159 +1,110 @@
Panoramix
Caravel
=========
![img](https://travis-ci.org/mistercrunch/panoramix.svg?branch=master)
[![Coverage Status](https://coveralls.io/repos/mistercrunch/panoramix/badge.svg?branch=master&service=github)](https://coveralls.io/github/mistercrunch/panoramix?branch=master)
<img src="http://i.imgur.com/H0Kyvyi.jpg" style="border-radius: 20px; box-shadow:5px 5px 5px gray;" alt="Caravel" width="500"/>
Panoramix is a data exploration platform designed to be visual, intuitive
[![Build Status](https://travis-ci.org/airbnb/caravel.svg?branch=master)](https://travis-ci.org/airbnb/caravel)
[![PyPI version](https://badge.fury.io/py/caravel.svg)](https://badge.fury.io/py/caravel)
[![Coverage Status](https://coveralls.io/repos/airbnb/caravel/badge.svg?branch=master&service=github)](https://coveralls.io/github/airbnb/caravel?branch=master)
[![Code Health](https://landscape.io/github/airbnb/caravel/master/landscape.svg?style=flat)](https://landscape.io/github/airbnb/caravel/master)
[![Requirements Status](https://requires.io/github/airbnb/caravel/requirements.svg?branch=master)](https://requires.io/github/airbnb/caravel/requirements/?branch=master)
[![Join the chat at https://gitter.im/airbnb/caravel](https://badges.gitter.im/airbnb/caravel.svg)](https://gitter.im/airbnb/caravel?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Documentation](https://img.shields.io/badge/docs-airbnb.io-blue.svg)](http://airbnb.io/caravel/)
Caravel is a data exploration platform designed to be visual, intuitive
and interactive.
![img](http://i.imgur.com/bi09J9X.png)
![img](http://i.imgur.com/aOaH0ty.png)
[this project used to be named **Panoramix**]
Panoramix
Video - Introduction to Caravel
---------------------------------
[![Caravel - ](http://img.youtube.com/vi/3Txm_nj_R7M/0.jpg)](http://www.youtube.com/watch?v=3Txm_nj_R7M)
Screenshots
------------
![img](http://i.imgur.com/JRbTnTx.png)
![img](http://i.imgur.com/4wRtxwb.png)
Caravel
---------
Panoramix's main goal is to make it easy to slice, dice and visualize data.
It empowers its user to perform **analytics at the speed of thought**.
Caravel'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**.
Panoramix provides:
* A quick way to intuitively visualize datasets
* Create and share simple dashboards
Caravel 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 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
* Deep integration with Druid allows for Panoramix to stay blazing fast while
* 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
* Deep integration with Druid allows for Caravel to stay blazing fast while
slicing and dicing large, realtime datasets
Buzz Phrases
------------
* Analytics at the speed of thought!
* Instantaneous learning curve
* Realtime analytics when querying [Druid.io](http://druid.io)
* Extentsible to infinity
Database Support
----------------
Panoramix was originally designed on to of Druid.io, but quickly broadened
its scope to support other databases through the use of SqlAlchemy, a Python
Caravel was originally designed on top of Druid.io, but quickly broadened
its scope to support other databases through the use of SQLAlchemy, a Python
ORM that is compatible with
[most common databases](http://docs.sqlalchemy.org/en/rel_1_0/core/engines.html).
[most common databases](http://docs.sqlalchemy.org/en/rel_1_0/core/engines.html).
What is Druid?
-------------
From their website at http://druid.io
*Druid is an open-source analytics data store designed for
business intelligence (OLAP) queries on event data. Druid provides low
latency (real-time) data ingestion, flexible data exploration,
and fast data aggregation. Existing Druid deployments have scaled to
trillions of events and petabytes of data. Druid is best used to
*Druid is an open-source analytics data store designed for
business intelligence (OLAP) queries on event data. Druid provides low
latency (real-time) data ingestion, flexible data exploration,
and fast data aggregation. Existing Druid deployments have scaled to
trillions of events and petabytes of data. Druid is best used to
power analytic dashboards and applications.*
Installation
------------
Installation & Configuration
----------------------------
Follow these few simple steps to install Panoramix
[See in the documentation](http://airbnb.io/caravel/installation.html)
```
# Install panoramix
pip install panoramix
# Create an admin user
fabmanager create-admin --app panoramix
# Initialize the database
panoramix db upgrade
# Create default roles and permissions
panoramix init
# Load some data to play with
panoramix load_examples
# Start the development web server
panoramix runserver -d
```
After installation, you should be able to point your browser to the right
hostname:port [http://localhost:8088](http://localhost:8088), login using
the credential you entered while creating the admin account, and navigate to
`Menu -> Admin -> Refresh Metadata`. This action should bring in all of
your datasources for Panoramix to be aware of, and they should show up in
`Menu -> Datasources`, from where you can start playing with your data!
Configuration
-------------
To configure your application, you need to create a file (module)
`panoramix_config.py` and make sure it is in your PYTHONPATH. Here are some
of the parameters you can copy / paste in that configuration module:
```
#---------------------------------------------------------
# Panoramix specifix config
#---------------------------------------------------------
ROW_LIMIT = 5000
WEBSERVER_THREADS = 8
PANORAMIX_WEBSERVER_PORT = 8088
#---------------------------------------------------------
#---------------------------------------------------------
# Flask App Builder configuration
#---------------------------------------------------------
# Your App secret key
SECRET_KEY = '\2\1thisismyscretkey\1\2\e\y\y\h'
# The SQLAlchemy connection string.
SQLALCHEMY_DATABASE_URI = 'sqlite:////tmp/panoramix.db'
# Flask-WTF flag for CSRF
CSRF_ENABLED = True
# Whether to run the web server in debug mode or not
DEBUG = True
```
This file also allows you to define configuration parameters used by
Flask App Builder, the web framework used by Panoramix. Please consult
the [Flask App Builder Documentation](http://flask-appbuilder.readthedocs.org/en/latest/config.html) for more information on how to configure Panoramix.
* From the UI, enter the information about your clusters in the
``Admin->Clusters`` menu by hitting the + sign.
* Once the Druid cluster connection information is entered, hit the
``Admin->Refresh Metadata`` menu item to populate
* Navigate to your datasources
More screenshots
----------------
![img](http://i.imgur.com/Rt6gNQ9.png)
![img](http://i.imgur.com/t7VOtqQ.png)
![img](http://i.imgur.com/PaiFQnH.png)
![img](http://i.imgur.com/CdcGHuC.png)
![img](http://i.imgur.com/MAFZTtU.png)
![img](http://i.imgur.com/xcy1QjN.png)
![img](http://i.imgur.com/RWqA8ly.png)
![img](http://i.imgur.com/D2kZL7q.png)
![img](http://i.imgur.com/0UPTK61.png)
![img](http://i.imgur.com/ahHoCuS.png)
Resources
-------------
* [Caravel Google Group](https://groups.google.com/forum/#!forum/airbnb_caravel)
* [Gitter (live chat) Channel](https://gitter.im/airbnb/caravel)
* [Docker image](https://hub.docker.com/r/kochalex/caravel/) (community contributed)
Tip of the Hat
--------------
Panoramix would not be possible without these great frameworks / libs
Caravel 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 library out there
* Much more, check out the requirements.txt file!
* 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/caravel/blob/master/setup.py) file!
Contributing
------------
Interested in contributing? Casual hacking? Check out [Contributing.MD](https://github.com/airbnb/caravel/blob/master/CONTRIBUTING.md)

65
TODO.md
View File

@@ -1,19 +1,56 @@
# TODO
List of TODO items for Panoramix
List of TODO items for Caravel
## Improvments
## Important
* **Getting proper JS testing:** unit tests on the Python side are pretty
solid, but now we need a test suite for the JS part of the site,
testing all the ajax-type calls
* **Viz Plugins:** Allow people to define and share visualization plugins.
ideally one would only need to drop in a set of files in a folder and
Caravel would discover and expose the plugins
## Features
* **Dashboard URL filters:** `{dash_url}#fltin__fieldname__value1,value2`
* **Default slice:** choose a default slice for the dataset instead of
default endpoint
* **refresh freq**: specifying the refresh frequency of a dashboard and
specific slices within it, some randomization would be nice
* **Widget sets / chart grids:** a way to have all charts support making
a series of charts and putting them in a grid. The same way that you
can groupby for series, you could chart by. The form field set would be
common and use a single field to "grid by", a limit number of chart as
an N * N grid size.
* **Advanced dashboard configuration:** currently you can define which
slices in a dashboard are immune to filtering.
* **Annotations layers:** allow for people to maintain data annotations,
attached to a layer and time range. These layers can be added on top of
some visualizations as annotations. An example of a layer might be
"holidays" or "site outages", ...
* **Slack integration** - TBD
* **Sexy Viz Selector:** the visualization selector should be a nice large
modal with nice thumbnails for each one of the viz
* **Comments:** allow for people to comment on slices and dashes
## Easy-ish fix
* Build matrix to include mysql using tox
* Figure out why coverage isn't working
* Kill switch for Druid in docs
* CREATE VIEW button from SQL editor
* Test button for when editing SQL expression
* Slider form element
* datasource in explore mode could be a dropdown
* [druid] Allow for post aggregations (ratios!)
* [sql] define column based grouping
* [sql] make "Test Connection" test further
* csv export out of table view
* in/notin filters autocomplete
* in/notin filters autocomplete (druid)
## Better Javascript enables
* Async on Druidify! in exploration page
* Async form reload onchange of viz_type dropdown
* Reintroduce query and stopwatch
* Fix resize / refresh
## New viz
* Maps that use geocodes
* Time animated scatter plots
* Horizon charts
* Calendar heatmap
* Chord diagram
* ...
## New Features
* Annotations layers
* Add a per-datasource permission
## Community
* Create a proper user documentation (started using Sphinx and boostrap...)
* Usage vid

View File

@@ -29,7 +29,7 @@ script_location = migrations
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = scheme://localhost/panoramix
sqlalchemy.url = scheme://localhost/caravel
# Logging configuration
[loggers]

View File

@@ -1,3 +0,0 @@
[python: **.py]
[jinja2: **/templates/**.html]
encoding = utf-8

View File

@@ -1 +0,0 @@

View File

@@ -1,13 +1,20 @@
"""Package's main module!"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import logging
import os
from flask import Flask
from flask import Flask, redirect
from flask.ext.appbuilder import SQLA, AppBuilder, IndexView
from flask.ext.appbuilder.baseviews import expose
from flask.ext.migrate import Migrate
from panoramix import config
from flask.ext.cache import Cache
APP_DIR = os.path.dirname(__file__)
CONFIG_MODULE = os.environ.get('PANORAMIX_CONFIG', 'panoramix.config')
CONFIG_MODULE = os.environ.get('CARAVEL_CONFIG', 'caravel.config')
# Logging configuration
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(name)s:%(message)s')
@@ -16,18 +23,24 @@ logging.getLogger().setLevel(logging.DEBUG)
app = Flask(__name__)
app.config.from_object(CONFIG_MODULE)
db = SQLA(app)
cache = Cache(app, config=app.config.get('CACHE_CONFIG'))
migrate = Migrate(app, db, directory=APP_DIR + "/migrations")
class MyIndexView(IndexView):
index_template = 'index.html'
@expose('/')
def index(self):
return redirect('/caravel/welcome')
appbuilder = AppBuilder(
app, db.session, base_template='panoramix/base.html',
app, db.session,
base_template='caravel/base.html',
indexview=MyIndexView,
security_manager_class=app.config.get("CUSTOM_SECURITY_MANAGER"))
sm = appbuilder.sm
get_session = appbuilder.get_session
from panoramix import views
from caravel import config, views # noqa

View File

@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
error = (
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+

3
caravel/assets/.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets" : ["es2015", "react"]
}

View File

@@ -0,0 +1,3 @@
node_modules/*
vendor/*
javascripts/dist/*

234
caravel/assets/.eslintrc Normal file
View File

@@ -0,0 +1,234 @@
{
"root": true,
"globals": {
"Symbol": false,
"Map": false,
"Set": false,
"Reflect": false,
},
"env": {
"es6": false,
"browser": true,
"node": true,
},
"parserOptions": {
"ecmaVersion": 5,
"sourceType": "module"
},
"rules": {
"array-bracket-spacing": [2, "never", {
"singleValue": false,
"objectsInArrays": false,
"arraysInArrays": false
}],
"array-callback-return": [2],
"block-spacing": [2, "always"],
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"callback-return": [2, ["callback"]],
"camelcase": [0],
"comma-dangle": [2, "never"],
"comma-spacing": [2],
"comma-style": [2, "last"],
"curly": [2, "all"],
"eqeqeq": 2,
"func-names": [0],
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
"keyword-spacing": [2, {
"before": true,
"after": true,
"overrides": {
"return": { "after": true },
"throw": { "after": true },
"case": { "after": true }
}
}],
"linebreak-style": [2, "unix"],
"lines-around-comment": [2, {
"beforeBlockComment": false,
"afterBlockComment": false,
"beforeLineComment": false,
"allowBlockStart": true,
"allowBlockEnd": true
}],
"max-depth": [2, 5],
"max-len": [0, 80, 4],
"max-nested-callbacks": [1, 3],
"max-params": [1, 4],
"new-parens": [2],
"newline-after-var": [0],
"no-bitwise": [0],
"no-cond-assign": [2],
"no-console": [1, { allow: ["warn", "error"] }],
"no-const-assign": [2],
"no-constant-condition": [2],
"no-control-regex": [2],
"no-debugger": [2],
"no-delete-var": [2],
"no-dupe-args": [2],
"no-dupe-class-members": [2],
"no-dupe-keys": [2],
"no-duplicate-case": [2],
"no-else-return": [0],
"no-empty": [2],
"no-eq-null": [0],
"no-eval": [2],
"no-ex-assign": [2],
"no-extend-native": [2],
"no-extra-bind": [2],
"no-extra-boolean-cast": [2],
"no-extra-label": [2],
"no-extra-parens": [0], // needed for clearer #math eg (a - b) / c
"no-extra-semi": [2],
"no-fallthrough": [2],
"no-floating-decimal": [2],
"no-func-assign": [2],
"no-implied-eval": [2],
"no-implicit-coercion": [2, {
"boolean": false,
"number": true,
"string": true
}],
"no-implicit-globals": [2],
"no-inline-comments": [0],
"no-invalid-regexp": [2],
"no-irregular-whitespace": [2],
"no-iterator": [2],
"no-label-var": [2],
"no-labels": [2, { "allowLoop": false, "allowSwitch": false }],
"no-lone-blocks": [2],
"no-lonely-if": [2],
"no-loop-func": [2],
"no-magic-numbers": [0], // doesn't work well with vis cosmetic constant
"no-mixed-requires": [1, false],
"no-mixed-spaces-and-tabs": [2, false],
"no-multi-spaces": [2, {
"exceptions": {
"ImportDeclaration": true,
"Property": true,
"VariableDeclarator": true
}
}],
"no-multi-str": [2],
"no-multiple-empty-lines": [2, { "max": 1, "maxEOF": 1 }],
"no-native-reassign": [2],
"no-negated-condition": [2],
"no-negated-in-lhs": [2],
"no-nested-ternary": [0],
"no-new": [2],
"no-new-func": [2],
"no-new-object": [2],
"no-new-require": [0],
"no-new-symbol": [2],
"no-new-wrappers": [2],
"no-obj-calls": [2],
"no-octal": [2],
"no-octal-escape": [2],
"no-path-concat": [0],
"no-process-env": [0],
"no-process-exit": [2],
"no-proto": [2],
"no-redeclare": [2],
"no-regex-spaces": [2],
"no-restricted-modules": [0],
"no-restricted-imports": [0],
"no-restricted-syntax": [2,
"DebuggerStatement",
"LabeledStatement",
"WithStatement"
],
"no-return-assign": [2, "always"],
"no-script-url": [2],
"no-self-assign": [2],
"no-self-compare": [0],
"no-sequences": [2],
"no-shadow-restricted-names": [2],
"no-spaced-func": [2],
"no-sparse-arrays": [2],
"no-sync": [0],
"no-ternary": [0],
"no-this-before-super": [2],
"no-throw-literal": [2],
"no-trailing-spaces": [2, { "skipBlankLines": false }],
"no-undef": [2, { "typeof": true }],
"no-undef-init": [2],
"no-undefined": [0],
"no-underscore-dangle": [0], // __data__ sometimes
"no-unexpected-multiline": [2],
"no-unmodified-loop-condition": [2],
"no-unneeded-ternary": [2],
"no-unreachable": [2],
"no-unused-expressions": [2],
"no-unused-labels": [2],
"no-unused-vars": [2, {
"vars": "all",
"args": "none", // (d, i) pattern d3 func makes difficult to enforce
"varsIgnorePattern": "jQuery"
}],
"no-use-before-define": [0],
"no-useless-call": [2],
"no-useless-concat": [2],
"no-useless-constructor": [2],
"no-void": [0],
"no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
"no-with": [2],
"no-whitespace-before-property": [2],
"object-curly-spacing": [2, "always"],
"object-shorthand": [2, "never"],
"one-var": [0],
"one-var-declaration-per-line": [2, "initializations"],
"operator-assignment": [0, "always"],
"padded-blocks": [0],
"prefer-arrow-callback": [0],
"prefer-const": [0],
"prefer-reflect": [0],
"prefer-rest-params": [0],
"prefer-spread": [0],
"prefer-template": [0],
"quote-props": [2, "as-needed", { "keywords": true }],
"radix": [2],
"require-yield": [2],
"semi": [2],
"semi-spacing": [2, { "before": false, "after": true }],
"sort-vars": [0],
"sort-imports": [0],
"space-before-function-paren": [2, { "anonymous": "always", "named": "never" }],
"space-before-blocks": [2, { "functions": "always", "keywords": "always" }],
"space-in-brackets": [0, "never", {
"singleValue": true,
"arraysInArrays": false,
"arraysInObjects": false,
"objectsInArrays": true,
"objectsInObjects": true,
"propertyName": false
}],
},
// Temporarily not enforced
"new-cap": [2], // @TODO more tricky for the moment
"newline-per-chained-call": [2, { "ignoreChainWithDepth": 6 }],
"no-param-reassign": [0], // turn on once default args supported
"no-shadow": [2, { // @TODO more tricky for the moment with eg 'data'
"builtinGlobals": false,
"hoist": "functions",
"allow": ["i", "d"]
}],
"space-in-parens": [2, "never"],
"space-infix-ops": [2],
"space-unary-ops": [2, { "words": true, "nonwords": false }],
"spaced-comment": [2, "always", { "markers": ["!"] }],
"spaced-line-comment": [0, "always"],
"strict": [2, "global"],
"template-curly-spacing": [2, "never"],
"use-isnan": [2],
"valid-jsdoc": [0],
"valid-typeof": [2],
"vars-on-top": [0],
"wrap-iife": [2],
"wrap-regex": [2],
"yield-star-spacing": [2, { "before": false, "after": true }],
"yoda": [2, "never", { "exceptRange": true, "onlyEquality": false }]
}

View File

Before

Width:  |  Height:  |  Size: 459 KiB

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 552 KiB

After

Width:  |  Height:  |  Size: 552 KiB

View File

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 236 KiB

View File

Before

Width:  |  Height:  |  Size: 702 KiB

After

Width:  |  Height:  |  Size: 702 KiB

View File

Before

Width:  |  Height:  |  Size: 328 KiB

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@@ -0,0 +1,5 @@
require('../node_modules/select2/select2.css');
require('../node_modules/select2-bootstrap-css/select2-bootstrap.min.css');
require('../node_modules/jquery-ui/themes/base/jquery-ui.css');
require('select2');
require('../vendor/select2.sortable.js');

View File

@@ -0,0 +1 @@
require('../stylesheets/less/index.less');

View File

@@ -0,0 +1,258 @@
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
var px = require('./modules/caravel.js');
var d3 = require('d3');
var showModal = require('./modules/utils.js').showModal;
require('bootstrap');
var ace = require('brace');
require('brace/mode/css');
require('brace/theme/crimson_editor');
require('./caravel-select2.js');
require('../node_modules/gridster/dist/jquery.gridster.min.css');
require('../node_modules/gridster/dist/jquery.gridster.min.js');
var Dashboard = function (dashboardData) {
var dashboard = $.extend(dashboardData, {
filters: {},
init: function () {
this.initDashboardView();
px.initFavStars();
var sliceObjects = [],
dash = this;
dashboard.slices.forEach(function (data) {
if (data.error) {
var html = '<div class="alert alert-danger">' + data.error + '</div>';
$("#slice_" + data.slice_id).find('.token').html(html);
} else {
var slice = px.Slice(data, dash);
$("#slice_" + data.slice_id).find('a.refresh').click(function () {
slice.render(true);
});
sliceObjects.push(slice);
slice.render();
}
});
this.slices = sliceObjects;
},
setFilter: function (slice_id, col, vals) {
this.addFilter(slice_id, col, vals, false);
},
addFilter: function (slice_id, col, vals, merge) {
if (merge === undefined) {
merge = true;
}
if (!(slice_id in this.filters)) {
this.filters[slice_id] = {};
}
if (!(col in this.filters[slice_id]) || !merge) {
this.filters[slice_id][col] = vals;
} else {
this.filters[slice_id][col] = d3.merge([this.filters[slice_id][col], vals]);
}
this.refreshExcept(slice_id);
},
readFilters: function () {
// Returns a list of human readable active filters
return JSON.stringify(this.filters, null, 4);
},
refreshExcept: function (slice_id) {
var immune = this.metadata.filter_immune_slice || [];
this.slices.forEach(function (slice) {
if (slice.data.slice_id !== slice_id && immune.indexOf(slice.data.slice_id) === -1) {
slice.render();
}
});
},
clearFilters: function (slice_id) {
delete this.filters[slice_id];
this.refreshExcept(slice_id);
},
removeFilter: function (slice_id, col, vals) {
if (slice_id in this.filters) {
if (col in this.filters[slice_id]) {
var a = [];
this.filters[slice_id][col].forEach(function (v) {
if (vals.indexOf(v) < 0) {
a.push(v);
}
});
this.filters[slice_id][col] = a;
}
}
this.refreshExcept(slice_id);
},
getSlice: function (slice_id) {
slice_id = parseInt(slice_id, 10);
for (var i=0; i < this.slices.length; i++) {
if (this.slices[i].data.slice_id === slice_id) {
return this.slices[i];
}
}
},
initDashboardView: function () {
dashboard = this;
var gridster = $(".gridster ul").gridster({
autogrow_cols: true,
widget_margins: [10, 10],
widget_base_dimensions: [95, 95],
draggable: {
handle: '.drag'
},
resize: {
enabled: true,
stop: function (e, ui, element) {
dashboard.getSlice($(element).attr('slice_id')).resize();
}
},
serialize_params: function (_w, wgd) {
return {
slice_id: $(_w).attr('slice_id'),
col: wgd.col,
row: wgd.row,
size_x: wgd.size_x,
size_y: wgd.size_y
};
}
}).data('gridster');
// Displaying widget controls on hover
$('.chart-header').hover(
function () {
$(this).find('.chart-controls').fadeIn(300);
},
function () {
$(this).find('.chart-controls').fadeOut(300);
}
);
$("div.gridster").css('visibility', 'visible');
$("#savedash").click(function () {
var expanded_slices = {};
$.each($(".slice_info"), function (i, d) {
var widget = $(this).parents('.widget');
var slice_description = widget.find('.slice_description');
if (slice_description.is(":visible")) {
expanded_slices[$(d).attr('slice_id')] = true;
}
});
var data = {
positions: gridster.serialize(),
css: editor.getValue(),
expanded_slices: expanded_slices
};
$.ajax({
type: "POST",
url: '/caravel/save_dash/' + dashboard.id + '/',
data: {
data: JSON.stringify(data)
},
success: function () {
showModal({
title: "Success",
body: "This dashboard was saved successfully."
});
},
error: function (error) {
showModal({
title: "Error",
body: "Sorry, there was an error saving this dashboard:<br />" + error
});
console.warn("Save dashboard error", error);
}
});
});
var editor = ace.edit("dash_css");
editor.$blockScrolling = Infinity;
editor.setTheme("ace/theme/crimson_editor");
editor.setOptions({
minLines: 16,
maxLines: Infinity,
useWorker: false
});
editor.getSession().setMode("ace/mode/css");
$(".select2").select2({
dropdownAutoWidth: true
});
$("#css_template").on("change", function () {
var css = $(this).find('option:selected').data('css');
editor.setValue(css);
$('#dash_css').val(css);
injectCss("dashboard-template", css);
});
$('#filters').click(function () {
showModal({
title: "<span class='fa fa-info-circle'></span> Current Global Filters",
body: "The following global filters are currently applied:<br/>" + dashboard.readFilters()
});
});
$('#refresh_dash').click(function () {
dashboard.slices.forEach(function (slice) {
slice.render(true);
});
});
$("a.remove-chart").click(function () {
var li = $(this).parents("li");
gridster.remove_widget(li);
});
$("li.widget").click(function (e) {
var $this = $(this);
var $target = $(e.target);
if ($target.hasClass("slice_info")) {
$this.find(".slice_description").slideToggle(0, function () {
$this.find('.refresh').click();
});
} else if ($target.hasClass("controls-toggle")) {
$this.find(".chart-controls").toggle();
}
});
editor.on("change", function () {
var css = editor.getValue();
$('#dash_css').val(css);
injectCss("dashboard-template", css);
});
var css = $('.dashboard').data('css');
injectCss("dashboard-template", css);
// Injects the passed css string into a style sheet with the specified className
// If a stylesheet doesn't exist with the passed className, one will be injected into <head>
function injectCss(className, css) {
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.querySelector('.' + className);
if (!style) {
if (className.split(' ').length > 1) {
throw new Error("This method only supports selections with a single class name.");
}
style = document.createElement('style');
style.className = className;
style.type = 'text/css';
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.innerHTML = css;
}
}
}
});
dashboard.init();
return dashboard;
};
$(document).ready(function () {
Dashboard($('.dashboard').data('dashboard'));
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
});

View File

@@ -0,0 +1,352 @@
// Javascript for the explorer page
// Init explorer view -> load vis dependencies -> read data (from dynamic html) -> render slice
// nb: to add a new vis, you must also add a Python fn in viz.py
//
// js
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
var px = require('./modules/caravel.js');
var showModal = require('./modules/utils.js').showModal;
require('jquery-ui');
$.widget.bridge('uitooltip', $.ui.tooltip); // Shutting down jq-ui tooltips
require('bootstrap');
require('./caravel-select2.js');
require('../node_modules/bootstrap-toggle/js/bootstrap-toggle.min.js');
// css
require('../vendor/pygments.css');
require('../node_modules/bootstrap-toggle/css/bootstrap-toggle.min.css');
var slice;
function prepForm() {
var i = 1;
// Assigning the right id to form elements in filters
$("#filters > div").each(function () {
$(this).attr("id", function () {
return "flt_" + i;
});
$(this).find("#flt_col_0")
.attr("id", function () {
return "flt_col_" + i;
})
.attr("name", function () {
return "flt_col_" + i;
});
$(this).find("#flt_op_0")
.attr("id", function () {
return "flt_op_" + i;
})
.attr("name", function () {
return "flt_op_" + i;
});
$(this).find("#flt_eq_0")
.attr("id", function () {
return "flt_eq_" + i;
})
.attr("name", function () {
return "flt_eq_" + i;
});
i++;
});
}
function query(force, pushState) {
if (force === undefined) {
force = false;
}
if (pushState !== false) {
history.pushState({}, document.title, slice.querystring());
}
$('.query-and-save button').attr('disabled', 'disabled');
$('.btn-group.results span,a').attr('disabled', 'disabled');
$('div.alert').remove();
$('#is_cached').hide();
prepForm();
slice.render(force);
}
function initExploreView() {
function get_collapsed_fieldsets() {
var collapsed_fieldsets = $("#collapsed_fieldsets").val();
if (collapsed_fieldsets !== undefined && collapsed_fieldsets !== "") {
collapsed_fieldsets = collapsed_fieldsets.split('||');
} else {
collapsed_fieldsets = [];
}
return collapsed_fieldsets;
}
function toggle_fieldset(legend, animation) {
var parent = legend.parent();
var fieldset = parent.find(".legend_label").text();
var collapsed_fieldsets = get_collapsed_fieldsets();
var index;
if (parent.hasClass("collapsed")) {
if (animation) {
parent.find(".panel-body").slideDown();
} else {
parent.find(".panel-body").show();
}
parent.removeClass("collapsed");
parent.find("span.collapser").text("[-]");
// removing from array, js is overcomplicated
index = collapsed_fieldsets.indexOf(fieldset);
if (index !== -1) {
collapsed_fieldsets.splice(index, 1);
}
} else { // not collapsed
if (animation) {
parent.find(".panel-body").slideUp();
} else {
parent.find(".panel-body").hide();
}
parent.addClass("collapsed");
parent.find("span.collapser").text("[+]");
index = collapsed_fieldsets.indexOf(fieldset);
if (index === -1 && fieldset !== "" && fieldset !== undefined) {
collapsed_fieldsets.push(fieldset);
}
}
$("#collapsed_fieldsets").val(collapsed_fieldsets.join("||"));
}
px.initFavStars();
$('form .panel-heading').click(function () {
toggle_fieldset($(this), true);
$(this).css('cursor', 'pointer');
});
function copyURLToClipboard(url) {
var textArea = document.createElement("textarea");
textArea.style.position = 'fixed';
textArea.style.left = '-1000px';
textArea.value = url;
document.body.appendChild(textArea);
textArea.select();
try {
var successful = document.execCommand('copy');
if (!successful) {
throw new Error("Not successful");
}
} catch (err) {
window.alert("Sorry, your browser does not support copying. Use Ctrl / Cmd + C!");
}
document.body.removeChild(textArea);
return successful;
}
$('#shortner').click(function () {
$.ajax({
type: "POST",
url: '/r/shortner/',
data: {
data: '/' + window.location.pathname + slice.querystring()
},
success: function (data) {
var close = '<a style="cursor: pointer;"><i class="fa fa-close" id="close_shortner"></i></a>';
var copy = '<a style="cursor: pointer;"><i class="fa fa-clipboard" title="Copy to clipboard" id="copy_url"></i></a>';
var spaces = '&nbsp;&nbsp;&nbsp;';
var popover = data + spaces + copy + spaces + close;
var $shortner = $('#shortner')
.popover({
content: popover,
placement: 'left',
html: true,
trigger: 'manual'
})
.popover('show');
$('#copy_url').tooltip().click(function () {
var success = copyURLToClipboard(data);
if (success) {
$(this).attr("data-original-title", "Copied!").tooltip('fixTitle').tooltip('show');
window.setTimeout(destroyPopover, 1200);
}
});
$('#close_shortner').click(destroyPopover);
function destroyPopover() {
$shortner.popover('destroy');
}
},
error: function (error) {
showModal({
title: "Error",
body: "Sorry, an error occurred during this operation:<br/>" + error
});
console.warn("Short URL error", error);
}
});
});
$("#viz_type").change(function () {
$("#query").submit();
});
$("#datasource_id").change(function () {
var url = $(this).find('option:selected').attr('url');
window.location = url;
});
var collapsed_fieldsets = get_collapsed_fieldsets();
for (var i = 0; i < collapsed_fieldsets.length; i++) {
toggle_fieldset($('legend:contains("' + collapsed_fieldsets[i] + '")'), false);
}
$(".select2").select2({
dropdownAutoWidth: true
});
$(".select2Sortable").select2({
dropdownAutoWidth: true
});
$(".select2Sortable").select2Sortable({
bindOrder: 'sortableStop'
});
$("form").show();
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
$(".ui-helper-hidden-accessible").remove(); // jQuery-ui 1.11+ creates a div for every tooltip
function set_filters() {
for (var i = 1; i < 10; i++) {
var eq = px.getParam("flt_eq_" + i);
if (eq !== '') {
add_filter(i);
}
}
}
set_filters();
function add_filter(i) {
var cp = $("#flt0").clone();
$(cp).appendTo("#filters");
$(cp).show();
if (i !== undefined) {
$(cp).find("#flt_eq_0").val(px.getParam("flt_eq_" + i));
$(cp).find("#flt_op_0").val(px.getParam("flt_op_" + i));
$(cp).find("#flt_col_0").val(px.getParam("flt_col_" + i));
}
$(cp).find('select').select2();
$(cp).find('.remove').click(function () {
$(this).parent().parent().remove();
});
}
$(window).bind("popstate", function (event) {
// Browser back button
var returnLocation = history.location || document.location;
// Could do something more lightweight here, but we're not optimizing
// for the use of the back button anyways
returnLocation.reload();
});
$("#plus").click(add_filter);
$("#btn_save").click(function () {
var slice_name = prompt("Name your slice!");
if (slice_name !== "" && slice_name !== null) {
$("#slice_name").val(slice_name);
prepForm();
$("#action").val("save");
$("#query").submit();
}
});
$("#btn_overwrite").click(function () {
var flag = confirm("Overwrite slice [" + $("#slice_name").val() + "] !?");
if (flag) {
$("#action").val("overwrite");
prepForm();
$("#query").submit();
}
});
$(".query").click(function () {
query(true);
});
function create_choices(term, data) {
var filtered = $(data).filter(function () {
return this.text.localeCompare(term) === 0;
});
if (filtered.length === 0) {
return {
id: term,
text: term
};
}
}
function initSelectionToValue(element, callback) {
callback({
id: element.val(),
text: element.val()
});
}
$(".select2_freeform").each(function () {
var parent = $(this).parent();
var name = $(this).attr('name');
var l = [];
var selected = '';
for (var i = 0; i < this.options.length; i++) {
l.push({
id: this.options[i].value,
text: this.options[i].text
});
if (this.options[i].selected) {
selected = this.options[i].value;
}
}
parent.append(
'<input class="' + $(this).attr('class') + '" name="' + name + '" type="text" value="' + selected + '">'
);
$("input[name='" + name + "']").select2({
createSearchChoice: create_choices,
initSelection: initSelectionToValue,
dropdownAutoWidth: true,
multiple: false,
data: l
});
$(this).remove();
});
}
$(document).ready(function () {
initExploreView();
// Dynamically register this visualization
var visType = window.viz_type.value;
px.registerViz(visType);
var data = $('.slice').data('slice');
slice = px.Slice(data);
//
$('.slice').data('slice', slice);
// call vis render method, which issues ajax
query(false, false);
// make checkbox inputs display as toggles
$(':checkbox')
.addClass('pull-right')
.attr("data-onstyle", "default")
.bootstrapToggle({
size: 'mini'
});
$('div.toggle').addClass('pull-right');
slice.bindResizeToWindowResize();
});

View File

@@ -0,0 +1,18 @@
var $ = require('jquery');
var jQuery = $;
import React from 'react';
import { render } from 'react-dom';
import { Jumbotron } from 'react-bootstrap';
class App extends React.Component {
render () {
return (
<Jumbotron>
<h1>Caravel</h1>
<p>Extensible visualization tool for exploring data from any database.</p>
</Jumbotron>
);
}
}
render(<App />, document.getElementById('app'));

View File

@@ -0,0 +1,381 @@
var $ = require('jquery');
var jQuery = $;
var d3 = require('d3');
// vis sources
var sourceMap = {
area: 'nvd3_vis.js',
bar: 'nvd3_vis.js',
bubble: 'nvd3_vis.js',
big_number: 'big_number.js',
big_number_total: 'big_number.js',
compare: 'nvd3_vis.js',
dist_bar: 'nvd3_vis.js',
directed_force: 'directed_force.js',
filter_box: 'filter_box.js',
heatmap: 'heatmap.js',
iframe: 'iframe.js',
line: 'nvd3_vis.js',
markup: 'markup.js',
para: 'parallel_coordinates.js',
pie: 'nvd3_vis.js',
pivot_table: 'pivot_table.js',
sankey: 'sankey.js',
sunburst: 'sunburst.js',
table: 'table.js',
word_cloud: 'word_cloud.js',
world_map: 'world_map.js'
};
var color = function () {
// Color related utility functions go in this object
var bnbColors = [
//rausch hackb kazan babu lima beach barol
'#ff5a5f', '#7b0051', '#007A87', '#00d1c1', '#8ce071', '#ffb400', '#b4a76c',
'#ff8083', '#cc0086', '#00a1b3', '#00ffeb', '#bbedab', '#ffd266', '#cbc29a',
'#ff3339', '#ff1ab1', '#005c66', '#00b3a5', '#55d12e', '#b37e00', '#988b4e'
];
var spectrums = {
blue_white_yellow: ['#00d1c1', 'white', '#ffb400'],
fire: ['white', 'yellow', 'red', 'black'],
white_black: ['white', 'black'],
black_white: ['black', 'white']
};
var colorBnb = function () {
// Color factory
var seen = {};
return function (s) {
// next line is for caravel series that should have the same color
s = s.replace('---', '');
if (seen[s] === undefined) {
seen[s] = Object.keys(seen).length;
}
return this.bnbColors[seen[s] % this.bnbColors.length];
};
};
var colorScalerFactory = function (colors, data, accessor) {
// Returns a linear scaler our of an array of color
if (!Array.isArray(colors)) {
colors = spectrums[colors];
}
var ext = [0, 1];
if (data !== undefined) {
ext = d3.extent(data, accessor);
}
var points = [];
var chunkSize = (ext[1] - ext[0]) / colors.length;
$.each(colors, function (i, c) {
points.push(i * chunkSize);
});
return d3.scale.linear().domain(points).range(colors);
};
return {
bnbColors: bnbColors,
category21: colorBnb(),
colorScalerFactory: colorScalerFactory
};
};
var px = (function () {
var visualizations = {};
var slice;
function getParam(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
function UTC(dttm) {
return new Date(dttm.getUTCFullYear(), dttm.getUTCMonth(), dttm.getUTCDate(), dttm.getUTCHours(), dttm.getUTCMinutes(), dttm.getUTCSeconds());
}
var tickMultiFormat = d3.time.format.multi([
[".%L", function (d) {
return d.getMilliseconds();
}], // If there are millisections, show only them
[":%S", function (d) {
return d.getSeconds();
}], // If there are seconds, show only them
["%a %b %d, %I:%M %p", function (d) {
return d.getMinutes() !== 0;
}], // If there are non-zero minutes, show Date, Hour:Minute [AM/PM]
["%a %b %d, %I %p", function (d) {
return d.getHours() !== 0;
}], // If there are hours that are multiples of 3, show date and AM/PM
["%a %b %d, %Y", function (d) {
return d.getDate() !== 1;
}], // If not the first of the month, do "month day, year."
["%B %Y", function (d) {
return d.getMonth() !== 0 && d.getDate() === 1;
}], // If the first of the month, do "month day, year."
["%Y", function (d) {
return true;
}] // fall back on month, year
]);
function formatDate(dttm) {
var d = UTC(new Date(dttm));
//d = new Date(d.getTime() - 1 * 60 * 60 * 1000);
return tickMultiFormat(d);
}
function timeFormatFactory(d3timeFormat) {
var f = d3.time.format(d3timeFormat);
return function (dttm) {
var d = UTC(new Date(dttm));
return f(d);
};
}
function initFavStars() {
var baseUrl = '/caravel/favstar/';
// Init star behavihor for favorite
function show() {
if ($(this).hasClass('selected')) {
$(this).html('<i class="fa fa-star"></i>');
} else {
$(this).html('<i class="fa fa-star-o"></i>');
}
}
$('.favstar')
.attr('title', 'Click to favorite/unfavorite')
.each(show)
.each(function () {
var url = baseUrl + $(this).attr("class_name");
var star = this;
url += '/' + $(this).attr("obj_id") + '/';
$.getJSON(url + 'count/', function (data) {
if (data.count > 0) {
$(star)
.addClass('selected')
.each(show);
}
});
})
.click(function () {
$(this).toggleClass('selected');
var url = baseUrl + $(this).attr("class_name");
url += '/' + $(this).attr("obj_id") + '/';
if ($(this).hasClass('selected')) {
url += 'select/';
} else {
url += 'unselect/';
}
$.get(url);
$(this).each(show);
})
.tooltip();
}
var Slice = function (data, dashboard) {
var timer;
var token = $('#' + data.token);
var container_id = data.token + '_con';
var selector = '#' + container_id;
var container = $(selector);
var slice_id = data.slice_id;
var dttm = 0;
var stopwatch = function () {
dttm += 10;
var num = dttm / 1000;
$('#timer').text(num.toFixed(2) + " sec");
};
var qrystr = '';
var always = function (data) {
//Private f, runs after done and error
clearInterval(timer);
$('#timer').removeClass('btn-warning');
};
slice = {
data: data,
container: container,
container_id: container_id,
selector: selector,
querystring: function () {
var parser = document.createElement('a');
parser.href = data.json_endpoint;
if (dashboard !== undefined) {
var flts = encodeURIComponent(JSON.stringify(dashboard.filters));
qrystr = parser.search + "&extra_filters=" + flts;
} else if ($('#query').length === 0) {
qrystr = parser.search;
} else {
qrystr = '?' + $('#query').serialize();
}
return qrystr;
},
getWidgetHeader: function () {
return this.container.parents("li.widget").find(".chart-header");
},
jsonEndpoint: function () {
var parser = document.createElement('a');
parser.href = data.json_endpoint;
var endpoint = parser.pathname + this.querystring();
endpoint += "&json=true";
endpoint += "&force=" + this.force;
return endpoint;
},
done: function (data) {
clearInterval(timer);
token.find("img.loading").hide();
container.show();
var cachedSelector = null;
if (dashboard === undefined) {
cachedSelector = $('#is_cached');
if (data !== undefined && data.is_cached) {
cachedSelector
.attr('title', 'Served from data cached at ' + data.cached_dttm + '. Click to force-refresh')
.show()
.tooltip('fixTitle');
} else {
cachedSelector.hide();
}
} else {
var refresh = this.getWidgetHeader().find('.refresh');
if (data !== undefined && data.is_cached) {
refresh
.addClass('danger')
.attr(
'title',
'Served from data cached at ' + data.cached_dttm + '. Click to force-refresh')
.tooltip('fixTitle');
} else {
refresh
.removeClass('danger')
.attr(
'title',
'Click to force-refresh')
.tooltip('fixTitle');
}
}
if (data !== undefined) {
$("#query_container").html(data.query);
}
$('#timer').removeClass('btn-warning');
$('#timer').addClass('btn-success');
$('span.query').removeClass('disabled');
$('#json').click(function () {
window.location = data.json_endpoint;
});
$('#standalone').click(function () {
window.location = data.standalone_endpoint;
});
$('#csv').click(function () {
window.location = data.csv_endpoint;
});
$('.btn-group.results span,a').removeAttr('disabled');
$('.query-and-save button').removeAttr('disabled');
always(data);
},
error: function (msg) {
token.find("img.loading").hide();
var err = '<div class="alert alert-danger">' + msg + '</div>';
container.html(err);
container.show();
$('span.query').removeClass('disabled');
$('#timer').addClass('btn-danger');
$('.btn-group.results span,a').removeAttr('disabled');
$('.query-and-save button').removeAttr('disabled');
always(data);
},
width: function () {
return token.width();
},
height: function () {
var others = 0;
var widget = container.parents('.widget');
var slice_description = widget.find('.slice_description');
if (slice_description.is(":visible")) {
others += widget.find('.slice_description').height() + 25;
}
others += widget.find('.chart-header').height();
return widget.height() - others - 10;
},
bindResizeToWindowResize: function () {
var resizeTimer;
$(window).on('resize', function (e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function () {
slice.resize();
}, 500);
});
},
render: function (force) {
if (force === undefined) {
force = false;
}
this.force = force;
token.find("img.loading").show();
container.hide();
container.html('');
dttm = 0;
timer = setInterval(stopwatch, 10);
$('#timer').removeClass('btn-danger btn-success');
$('#timer').addClass('btn-warning');
this.viz.render();
},
resize: function () {
token.find("img.loading").show();
container.hide();
container.html('');
this.viz.render();
this.viz.resize();
},
addFilter: function (col, vals) {
if (dashboard !== undefined) {
dashboard.addFilter(slice_id, col, vals);
}
},
setFilter: function (col, vals) {
if (dashboard !== undefined) {
dashboard.setFilter(slice_id, col, vals);
}
},
clearFilter: function () {
if (dashboard !== undefined) {
delete dashboard.clearFilter(slice_id);
}
},
removeFilter: function (col, vals) {
if (dashboard !== undefined) {
delete dashboard.removeFilter(slice_id, col, vals);
}
}
};
var visType = data.form_data.viz_type;
px.registerViz(visType);
slice.viz = visualizations[data.form_data.viz_type](slice);
return slice;
};
function registerViz(name) {
var visSource = sourceMap[name];
if (visSource) {
var visFactory = require('../../visualizations/' + visSource);
if (typeof visFactory === 'function') {
visualizations[name] = visFactory;
}
} else {
throw new Error("require(" + name + ") failed.");
}
}
// Export public functions
return {
registerViz: registerViz,
Slice: Slice,
formatDate: formatDate,
timeFormatFactory: timeFormatFactory,
color: color(),
getParam: getParam,
initFavStars: initFavStars
};
})();
module.exports = px;

View File

@@ -0,0 +1,80 @@
var $ = require('jquery');
var d3 = require('d3');
/*
Utility function that takes a d3 svg:text selection and a max width, and splits the
text's text across multiple tspan lines such that any given line does not exceed max width
If text does not span multiple lines AND adjustedY is passed, will set the text to the passed val
*/
function wrapSvgText(text, width, adjustedY) {
var lineHeight = 1; // ems
text.each(function () {
var text = d3.select(this),
words = text.text().split(/\s+/),
word,
line = [],
lineNumber = 0,
x = text.attr("x"),
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null)
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", dy + "em");
var didWrap = false;
for (var i = 0; i < words.length; i++) {
word = words[i];
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop(); // remove word that pushes over the limit
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
didWrap = true;
}
}
if (!didWrap && typeof adjustedY !== "undefined") {
tspan.attr("y", adjustedY);
}
});
}
/**
* Sets the body and title content of a modal, and shows it. Assumes HTML for modal exists and that
* it handles closing (i.e., works with bootstrap)
*
* @param {object} options object of the form
* {
* title: {string},
* body: {string},
* modalSelector: {string, default: '.misc-modal' },
* titleSelector: {string, default: '.misc-modal .modal-title' },
* bodySelector: {string, default: '.misc-modal .modal-body' },
* }
*/
function showModal(options) {
options.modalSelector = options.modalSelector || ".misc-modal";
options.titleSelector = options.titleSelector || ".misc-modal .modal-title";
options.bodySelector = options.bodySelector || ".misc-modal .modal-body";
$(options.titleSelector).html(options.title || "");
$(options.bodySelector).html(options.body || "");
$(options.modalSelector).modal("show");
}
module.exports = {
wrapSvgText: wrapSvgText,
showModal: showModal
};

View File

@@ -0,0 +1,103 @@
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
var showModal = require('./modules/utils.js').showModal;
require('select2');
require('datatables.net-bs');
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
require('bootstrap');
var ace = require('brace');
require('brace/mode/sql');
require('brace/theme/crimson_editor');
$(document).ready(function () {
function getParam(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
function initSqlEditorView() {
var database_id = $('#database_id').val();
var editor = ace.edit("sql");
editor.$blockScrolling = Infinity;
editor.getSession().setUseWrapMode(true);
$('#sql').hide();
editor.setTheme("ace/theme/crimson_editor");
editor.setOptions({
minLines: 16,
maxLines: Infinity
});
editor.getSession().setMode("ace/mode/sql");
editor.focus();
$("select").select2({
dropdownAutoWidth: true
});
function showTableMetadata() {
$(".metadata").load(
'/caravel/table/' + database_id + '/' + $("#dbtable").val() + '/');
}
$("#dbtable").on("change", showTableMetadata);
showTableMetadata();
$("#create_view").click(function () {
showModal({
title: "Error",
body: "Sorry, this feature is not yet implemented"
});
});
$(".sqlcontent").show();
function selectStarOnClick() {
$.ajax('/caravel/select_star/' + database_id + '/' + $("#dbtable").val() + '/')
.done(function (msg) {
editor.setValue(msg);
});
}
$("#select_star").click(selectStarOnClick);
editor.setValue(getParam('sql'));
$(window).bind("popstate", function (event) {
// Could do something more lightweight here, but we're not optimizing
// for the use of the back button anyways
editor.setValue(getParam('sql'));
$("#run").click();
});
$("#run").click(function () {
$('#results').hide(0);
$('#loading').show(0);
history.pushState({}, document.title, '?sql=' + encodeURIComponent(editor.getValue()));
$.ajax({
type: "POST",
url: '/caravel/runsql/',
data: {
data: JSON.stringify({
database_id: $('#database_id').val(),
sql: editor.getSession().getValue()
})
},
success: function (data) {
$('#loading').hide(0);
$('#results').show(0);
$('#results').html(data);
$('table.sql_results').DataTable({
paging: false,
searching: true,
aaSorting: []
});
},
error: function (err, err2) {
$('#loading').hide(0);
$('#results').show(0);
$('#results').html(err.responseText);
}
});
});
}
initSqlEditorView();
});

View File

@@ -0,0 +1,13 @@
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
var px = require('./modules/caravel.js');
require('bootstrap');
$(document).ready(function () {
var slice;
var data = $('.slice').data('slice');
slice = px.Slice(data);
slice.render();
slice.bindResizeToWindowResize();
});

View File

@@ -0,0 +1,67 @@
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
require('../stylesheets/welcome.css');
require('bootstrap');
require('datatables.net-bs');
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
require('../node_modules/cal-heatmap/cal-heatmap.css');
var CalHeatMap = require('cal-heatmap');
function modelViewTable(selector, modelEndpoint) {
// Builds a dataTable from a flask appbuilder api endpoint
$.getJSON(modelEndpoint + '/api/read', function (data) {
var tableData = jQuery.map(data.result, function (el, i) {
var row = $.map(data.list_columns, function (col, i) {
return el[col];
});
return [row];
});
var cols = jQuery.map(data.list_columns, function (col, i) {
return { sTitle: data.label_columns[col] };
});
var panel = $(selector).parents('.panel');
panel.find("img.loading").remove();
$(selector).DataTable({
aaData: tableData,
aoColumns: cols,
bPaginate: true,
pageLength: 10,
bLengthChange: false,
aaSorting: [],
searching: true,
bInfo: false
});
// Hack to move the searchbox in the right spot
var search = panel.find(".dataTables_filter input");
search.addClass('form-control').detach();
search.appendTo(panel.find(".search"));
panel.find('.dataTables_filter').remove();
// Hack to display the page navigator properly
panel.find('.col-sm-5').remove();
var nav = panel.find('.col-sm-7');
nav.removeClass('col-sm-7');
nav.addClass('col-sm-12');
$(selector).slideDown();
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
});
}
$(document).ready(function () {
var cal = new CalHeatMap();
cal.init({
start: new Date().setFullYear(new Date().getFullYear() - 1),
range: 13,
data: '/caravel/activity_per_day',
domain: "month",
subDomain: "day",
itemName: "action",
tooltip: true
});
modelViewTable('#dash_table', '/dashboardmodelviewasync');
modelViewTable('#slice_table', '/sliceasync');
});

View File

@@ -0,0 +1,78 @@
{
"name": "caravel",
"version": "0.1.0",
"description": "Any database to any visualization",
"directories": {
"doc": "docs",
"test": "tests"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack -d --watch --colors",
"prod": "webpack -p --colors",
"lint": "npm run --silent lint:js",
"lint:js": "eslint --ignore-path=.eslintignore --ext .js ."
},
"repository": {
"type": "git",
"url": "git+https://github.com/airbnb/caravel.git"
},
"keywords": [
"big",
"data",
"exploratory",
"analysis",
"react",
"d3",
"airbnb",
"nerds",
"database",
"flask"
],
"author": "Airbnb",
"bugs": {
"url": "https://github.com/airbnb/caravel/issues"
},
"homepage": "https://github.com/airbnb/caravel#readme",
"dependencies": {
"babel-loader": "^6.2.1",
"babel-polyfill": "^6.3.14",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"bootstrap": "^3.3.6",
"bootstrap-datepicker": "^1.6.0",
"bootstrap-toggle": "^2.2.1",
"brace": "^0.7.0",
"cal-heatmap": "3.5.4",
"css-loader": "^0.23.1",
"d3": "^3.5.14",
"d3-cloud": "^1.2.1",
"d3-sankey": "^0.2.1",
"d3-tip": "^0.6.7",
"datamaps": "^0.4.4",
"datatables-bootstrap3-plugin": "^0.4.0",
"datatables.net-bs": "^1.10.11",
"exports-loader": "^0.6.3",
"font-awesome": "^4.5.0",
"gridster": "^0.5.6",
"imports-loader": "^0.6.5",
"jquery": "^2.2.1",
"jquery-ui": "^1.10.5",
"less": "^2.6.1",
"less-loader": "^2.2.2",
"nvd3": "1.8.2",
"react": "^0.14.7",
"react-bootstrap": "^0.28.3",
"react-dom": "^0.14.7",
"select2": "3.5",
"select2-bootstrap-css": "^1.4.6",
"style-loader": "^0.13.0",
"topojson": "^1.6.22",
"webpack": "^1.12.12"
},
"devDependencies": {
"eslint": "^2.2.0",
"file-loader": "^0.8.5",
"url-loader": "^0.5.7"
}
}

View File

@@ -0,0 +1,226 @@
body {
margin: 0px !important;
}
.modal-dialog {
z-index: 1100;
}
.label {
font-size: 100%;
}
.no-wrap {
white-space: nowrap;
}
input.form-control {
background-color: white;
}
.chart-header a.danger {
color: red;
}
.col-left-fixed {
width:350px;
position: absolute;
float: left;
}
.col-offset {
margin-left: 365px;
}
.favstar {
margin-right: 10px;
opacity: 0.5;
cursor: pointer;
}
.slice_description{
padding: 8px;
margin: 5px;
border: 1px solid #DDD;
background-color: #F8F8F8;
border-radius: 5px;
font-size: 12px;
}
.slice_info{
cursor: pointer;
}
.padded {
padding: 10px;
}
.intable-longtext{
max-height: 200px;
overflow: auto;
}
.container-fluid {
text-align: left;
}
input[type="checkbox"] {
display: inline-block;
width: 16px;
height: 16px;
float: right;
}
form div {
padding-top: 1px;
}
.navbar-brand a {
color: white;
text-decoration: none;
}
.navbar-brand a:hover {
color: white;
text-decoration: none;
}
.header span {
margin-left: 5px;
}
.widget-is-cached {
display: none;
}
.header span.label {
margin-left: 5px;
margin-right: 5px;
}
#timer {
width: 80px;
text-align: right;
}
.notbtn {
cursor: default;
box-shadow: none;
border: 1px solid #ccc;
}
hr {
margin-top: 15px;
margin-bottom: 15px;
}
span.title-block {
background-color: #EEE;
border-radius: 4px;
padding: 6px 12px;
margin: 0px 10px;
font-size: 20px;
}
.nvtooltip {
//position: relative !important;
z-index: 888;
}
.nvtooltip table td{
font-size: 11px !important;
}
.navbar {
-webkit-box-shadow: 0px 3px 3px #AAA;
-moz-box-shadow: 0px 3px 3px #AAA;
box-shadow: 0px 3px 3px #AAA;
z-index: 999;
}
.panel.panel-primary {
margin: 10px;
}
.datasource form div.form-control {
margin-bottom: 5px !important;
}
.datasource form input.form-control {
margin-bottom: 5px !important;
}
.datasource .tooltip-inner {
max-width: 350px;
}
img.loading {
width: 40px;
}
.dashboard a i {
cursor: pointer;
}
.dashboard i.drag {
cursor: move !important;
}
.dashboard .gridster .preview-holder {
z-index: 1;
position: absolute;
background-color: #AAA;
border-color: #AAA;
opacity: 0.3;
}
.gridster li.widget{
list-style-type: none;
border-radius: 0;
margin: 5px;
border: 1px solid #ccc;
box-shadow: 2px 1px 5px -2px #aaa;
background-color: #fff;
}
.dashboard .gridster .dragging,
.dashboard .gridster .resizing {
opacity: 0.5;
}
.dashboard img.loading {
width: 20px;
margin: 5px;
}
.dashboard .title {
text-align: center;
}
.dashboard .slice_title {
text-align: center;
font-weight: bold;
font-size: 14px;
padding: 5px;
}
.dashboard div.slice_content {
width: 100%;
height: 100%;
}
.dashboard div.nvtooltip {
z-index: 888; /* this lets tool tips go on top of other slices */
}
div.header {
font-weight: bold;
}
li.widget:hover {
z-index: 1000;
}
li.widget .chart-header {
padding: 5px;
background-color: #f1f1f1;
}
li.widget .chart-header a {
margin-left: 5px;
}
#is_cached {
display: none;
}
li.widget .chart-controls {
background-color: #f1f1f1;
position: absolute;
right: 0;
left: 0;
padding: 0px 5px;
opacity: 0.75;
display: none;
}
li.widget .slice_container {
overflow: auto;
}

View File

@@ -0,0 +1,616 @@
// Paper 3.3.5
// Bootswatch
// -----------------------------------------------------
@web-font-path: "https://fonts.googleapis.com/css?family=Roboto:300,400,500,700";
.web-font(@path) {
@import url("@{path}");
}
.web-font(@web-font-path);
// Navbar =====================================================================
.navbar {
border: none;
.box-shadow(0 1px 2px rgba(0,0,0,.3));
&-brand {
font-size: 24px;
}
&-inverse {
.navbar-form {
input[type=text],
input[type=password] {
color: #fff;
.box-shadow(inset 0 -1px 0 @navbar-inverse-link-color);
.placeholder(@navbar-inverse-link-color);
&:focus {
.box-shadow(inset 0 -2px 0 #fff);
}
}
}
}
}
// Buttons ====================================================================
#btn(@class,@bg) {
.btn-@{class} {
background-size: 200%;
background-position: 50%;
&:focus {
background-color: @bg;
}
&:hover,
&:active:hover {
background-color: darken(@bg, 6%);
}
&:active {
background-color: darken(@bg, 12%);
#gradient > .radial(darken(@bg, 12%) 10%, @bg 11%);
background-size: 1000%;
.box-shadow(2px 2px 4px rgba(0,0,0,.4));
}
}
}
#btn(default,@btn-default-bg);
#btn(primary,@btn-primary-bg);
#btn(success,@btn-success-bg);
#btn(info,@btn-info-bg);
#btn(warning,@btn-warning-bg);
#btn(danger,@btn-danger-bg);
#btn(link,#fff);
.btn {
text-transform: uppercase;
border: none;
.box-shadow(1px 1px 4px rgba(0,0,0,.4));
.transition(all 0.4s);
&-link {
border-radius: @btn-border-radius-base;
.box-shadow(none);
color: @btn-default-color;
&:hover,
&:focus {
.box-shadow(none);
color: @btn-default-color;
text-decoration: none;
}
}
&-default {
&.disabled {
background-color: rgba(0, 0, 0, 0.1);
color: rgba(0, 0, 0, 0.4);
opacity: 1;
}
}
}
.btn-group {
.btn + .btn,
.btn + .btn-group,
.btn-group + .btn,
.btn-group + .btn-group {
margin-left: 0;
}
&-vertical {
> .btn + .btn,
> .btn + .btn-group,
> .btn-group + .btn,
> .btn-group + .btn-group {
margin-top: 0;
}
}
}
// Typography =================================================================
body {
-webkit-font-smoothing: antialiased;
letter-spacing: .1px;
}
p {
margin: 0 0 1em;
}
input,
button {
-webkit-font-smoothing: antialiased;
letter-spacing: .1px;
}
a {
.transition(all 0.2s);
}
// Tables =====================================================================
.table-hover {
> tbody > tr,
> tbody > tr > th,
> tbody > tr > td {
.transition(all 0.2s);
}
}
// Forms ======================================================================
label {
font-weight: normal;
}
textarea,
textarea.form-control,
input.form-control,
input[type=text],
input[type=password],
input[type=email],
input[type=number],
[type=text].form-control,
[type=password].form-control,
[type=email].form-control,
[type=tel].form-control,
[contenteditable].form-control {
padding: 0;
border: none;
border-radius: 0;
-webkit-appearance: none;
.box-shadow(inset 0 -1px 0 #ddd);
font-size: 16px;
&:focus {
.box-shadow(inset 0 -2px 0 @brand-primary);
}
&[disabled],
&[readonly] {
.box-shadow(none);
border-bottom: 1px dotted #ddd;
}
&.input {
&-sm {
font-size: @font-size-small;
}
&-lg {
font-size: @font-size-large;
}
}
}
select,
select.form-control {
border: 0;
border-radius: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
padding-left: 0;
padding-right: 0\9; // remove padding for < ie9 since default arrow can't be removed
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAAJ1BMVEVmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmaP/QSjAAAADHRSTlMAAgMJC0uWpKa6wMxMdjkoAAAANUlEQVR4AeXJyQEAERAAsNl7Hf3X6xt0QL6JpZWq30pdvdadme+0PMdzvHm8YThHcT1H7K0BtOMDniZhWOgAAAAASUVORK5CYII=);
background-size: 13px;
background-repeat: no-repeat;
background-position: right center;
.box-shadow(inset 0 -1px 0 #ddd);
font-size: 16px;
line-height: 1.5;
&::-ms-expand {
display: none;
}
&.input {
&-sm {
font-size: @font-size-small;
}
&-lg {
font-size: @font-size-large;
}
}
&:focus {
.box-shadow(inset 0 -2px 0 @brand-primary);
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAAJ1BMVEUhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISF8S9ewAAAADHRSTlMAAgMJC0uWpKa6wMxMdjkoAAAANUlEQVR4AeXJyQEAERAAsNl7Hf3X6xt0QL6JpZWq30pdvdadme+0PMdzvHm8YThHcT1H7K0BtOMDniZhWOgAAAAASUVORK5CYII=);
}
&[multiple] {
background: none;
}
}
.radio,
.radio-inline,
.checkbox,
.checkbox-inline {
label {
padding-left: 25px;
}
input[type="radio"],
input[type="checkbox"] {
margin-left: -25px;
}
}
input[type="radio"],
.radio input[type="radio"],
.radio-inline input[type="radio"] {
position: relative;
margin-top: 6px;
margin-right: 4px;
vertical-align: top;
border: none;
background-color: transparent;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
&:focus {
outline: none;
}
&:before,
&:after {
content: "";
display: block;
width: 18px;
height: 18px;
border-radius: 50%;
.transition(240ms);
}
&:before {
position: absolute;
left: 0;
top: -3px;
background-color: @brand-primary;
.scale(0);
}
&:after {
position: relative;
top: -3px;
border: 2px solid @gray;
}
&:checked:before {
.scale(0.5);
}
&:disabled:checked:before {
background-color: @gray-light;
}
&:checked:after {
border-color: @brand-primary;
}
&:disabled:after,
&:disabled:checked:after {
border-color: @gray-light;
}
}
input[type="checkbox"],
.checkbox input[type="checkbox"],
.checkbox-inline input[type="checkbox"] {
position: relative;
border: none;
margin-bottom: -4px;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
&:focus {
outline: none;
}
&:focus:after {
border-color: @brand-primary;
}
&:after {
content: "";
display: block;
width: 18px;
height: 18px;
margin-top: -2px;
margin-right: 5px;
border: 2px solid @gray;
border-radius: 2px;
.transition(240ms);
}
&:checked:before {
content: "";
position: absolute;
top: 0;
left: 6px;
display: table;
width: 6px;
height: 12px;
border: 2px solid #fff;
border-top-width: 0;
border-left-width: 0;
.rotate(45deg);
}
&:checked:after {
background-color: @brand-primary;
border-color: @brand-primary;
}
&:disabled:after {
border-color: @gray-light;
}
&:disabled:checked:after {
background-color: @gray-light;
border-color: transparent;
}
}
.has-warning {
input:not([type=checkbox]),
.form-control,
input.form-control[readonly],
input[type=text][readonly],
[type=text].form-control[readonly],
input:not([type=checkbox]):focus,
.form-control:focus {
border-bottom: none;
.box-shadow(inset 0 -2px 0 @brand-warning);
}
}
.has-error {
input:not([type=checkbox]),
.form-control,
input.form-control[readonly],
input[type=text][readonly],
[type=text].form-control[readonly],
input:not([type=checkbox]):focus,
.form-control:focus {
border-bottom: none;
.box-shadow(inset 0 -2px 0 @brand-danger);
}
}
.has-success {
input:not([type=checkbox]),
.form-control,
input.form-control[readonly],
input[type=text][readonly],
[type=text].form-control[readonly],
input:not([type=checkbox]):focus,
.form-control:focus {
border-bottom: none;
.box-shadow(inset 0 -2px 0 @brand-success);
}
}
// Remove the Bootstrap feedback styles for input addons
.input-group-addon {
.has-warning &, .has-error &, .has-success & {
color: @input-color;
border-color: @input-group-addon-border-color;
background-color: @input-group-addon-bg;
}
}
// Navs =======================================================================
.nav-tabs {
> li > a,
> li > a:focus {
margin-right: 0;
background-color: transparent;
border: none;
color: @navbar-default-link-color;
.box-shadow(inset 0 -1px 0 #ddd);
.transition(all 0.2s);
&:hover {
background-color: transparent;
.box-shadow(inset 0 -2px 0 @brand-primary);
color: @brand-primary;
}
}
& > li.active > a,
& > li.active > a:focus {
border: none;
.box-shadow(inset 0 -2px 0 @brand-primary);
color: @brand-primary;
&:hover {
border: none;
color: @brand-primary;
}
}
& > li.disabled > a {
.box-shadow(inset 0 -1px 0 #ddd);
}
&.nav-justified {
& > li > a,
& > li > a:hover,
& > li > a:focus,
& > .active > a,
& > .active > a:hover,
& > .active > a:focus {
border: none;
}
}
.dropdown-menu {
margin-top: 0;
}
}
.dropdown-menu {
margin-top: 0;
border: none;
.box-shadow(0 1px 4px rgba(0,0,0,.3));
}
// Indicators =================================================================
.alert {
border: none;
color: #fff;
&-success {
background-color: @brand-success;
}
&-info {
background-color: @brand-info;
}
&-warning {
background-color: @brand-warning;
}
&-danger {
background-color: @brand-danger;
}
a:not(.close),
.alert-link {
color: #fff;
font-weight: bold;
}
.close {
color: #fff;
}
}
.badge {
padding: 4px 6px 4px;
}
.progress {
position: relative;
z-index: 1;
height: 6px;
border-radius: 0;
.box-shadow(none);
&-bar {
.box-shadow(none);
&:last-child {
border-radius: 0 3px 3px 0;
}
&:last-child {
&:before {
display: block;
content: "";
position: absolute;
width: 100%;
height: 100%;
left: 0;
right: 0;
z-index: -1;
background-color: lighten(@progress-bar-bg, 35%);
}
}
&-success:last-child.progress-bar:before {
background-color: lighten(@brand-success, 35%);
}
&-info:last-child.progress-bar:before {
background-color: lighten(@brand-info, 45%);
}
&-warning:last-child.progress-bar:before {
background-color: lighten(@brand-warning, 35%);
}
&-danger:last-child.progress-bar:before {
background-color: lighten(@brand-danger, 25%);
}
}
}
// Progress bars ==============================================================
// Containers =================================================================
.close {
font-size: 34px;
font-weight: 300;
line-height: 24px;
opacity: 0.6;
.transition(all 0.2s);
&:hover {
opacity: 1;
}
}
.list-group {
&-item {
padding: 15px;
}
&-item-text {
color: @gray-light;
}
}
.well {
border-radius: 0;
.box-shadow(none);
}
.panel {
border: none;
border-radius: 2px;
.box-shadow(0 1px 4px rgba(0,0,0,.3));
&-heading {
border-bottom: none;
}
&-footer {
border-top: none;
}
}
.popover {
border: none;
.box-shadow(0 1px 4px rgba(0,0,0,.3));
}
.carousel {
&-caption {
h1, h2, h3, h4, h5, h6 {
color: inherit;
}
}
}

View File

@@ -0,0 +1,5 @@
// Index .less, any imports here will be included in the final css build
@import "~bootstrap/less/bootstrap.less";
@import "./variables.less";
@import "./bootswatch.less";

View File

@@ -0,0 +1,881 @@
// Modified from Bootswatch Paper 3.3.6
// Variables
// --------------------------------------------------
//== Colors
//
//## Airbnb colors
@rausch: #ff5a5f; // coral
@kazan: #007a87; // dark teal
@hackberry: #7b0051; // purple
@babu: #00d1c1; // light teal
@lima: #8ce071; // bright green
@beach: #ffb400; // yellow
@ebisu: #ffaa91; // peach
@tirol: #b4a76c; // khaki
@foggy: #9CA299; // dark grey
@hof: #565A5C; // light grey
//## Gray and brand colors for use across Bootstrap.
@gray-base: #000;
@gray-darker: lighten(@gray-base, 13.5%); // #222
@gray-dark: #212121;
@gray: #666;
@gray-light: #bbb;
@gray-lighter: lighten(@gray-base, 93.5%); // #eee
@brand-primary: darken(@babu, 5%);
@brand-success: darken(@lima, 15%);
@brand-info: @beach;
@brand-warning: @hackberry;
@brand-danger: darken(@rausch, 5%);
//== Scaffolding
//
//## Settings for some of the most global styles.
//** Background color for `<body>`.
@body-bg: #fff;
//** Global text color on `<body>`.
@text-color: @gray;
//** Global textual link color.
@link-color: @brand-primary;
//** Link hover color set via `darken()` function.
@link-hover-color: darken(@link-color, 15%);
//** Link hover decoration.
@link-hover-decoration: underline;
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
@font-family-sans-serif: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-serif: Georgia, "Times New Roman", Times, serif;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
@font-family-base: @font-family-sans-serif;
@font-size-base: 13px;
@font-size-large: ceil((@font-size-base * 1.25)); // ~18px
@font-size-small: ceil((@font-size-base * 0.85)); // ~12px
@font-size-h1: 56px;
@font-size-h2: 45px;
@font-size-h3: 34px;
@font-size-h4: 24px;
@font-size-h5: 20px;
@font-size-h6: 14px;
//** Unit-less `line-height` for use in components like buttons.
@line-height-base: 1.846; // 20/14
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px
//** By default, this inherits from the `<body>`.
@headings-font-family: inherit;
@headings-font-weight: 400;
@headings-line-height: 1.1;
@headings-color: #444;
//== Iconography
//
//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
//** Load fonts from this directory.
@icon-font-path: "../fonts/";
//** File name for all font files.
@icon-font-name: "glyphicons-halflings-regular";
//** Element ID within SVG icon file.
@icon-font-svg-id: "glyphicons_halflingsregular";
//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
@padding-base-vertical: 6px;
@padding-base-horizontal: 16px;
@padding-large-vertical: 10px;
@padding-large-horizontal: 16px;
@padding-small-vertical: 5px;
@padding-small-horizontal: 10px;
@padding-xs-vertical: 1px;
@padding-xs-horizontal: 5px;
@line-height-large: 1.3333333; // extra decimals for Win 8.1 Chrome
@line-height-small: 1.5;
@border-radius-base: 3px;
@border-radius-large: 3px;
@border-radius-small: 3px;
//** Global color for active items (e.g., navs or dropdowns).
@component-active-color: #fff;
//** Global background color for active items (e.g., navs or dropdowns).
@component-active-bg: @brand-primary;
//** Width of the `border` for generating carets that indicator dropdowns.
@caret-width-base: 4px;
//** Carets increase slightly in size for larger components.
@caret-width-large: 5px;
//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.
//** Padding for `<th>`s and `<td>`s.
@table-cell-padding: 8px;
//** Padding for cells in `.table-condensed`.
@table-condensed-cell-padding: 5px;
//** Default background color used for all tables.
@table-bg: transparent;
//** Background color used for `.table-striped`.
@table-bg-accent: #f9f9f9;
//** Background color used for `.table-hover`.
@table-bg-hover: @gray-lighter;
@table-bg-active: @table-bg-hover;
//** Border color for table and cell borders.
@table-border-color: #ddd;
//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.
@btn-font-weight: normal;
@btn-default-color: #444;
@btn-default-bg: #fff;
@btn-default-border: transparent;
@btn-primary-color: #fff;
@btn-primary-bg: @brand-primary;
@btn-primary-border: transparent;
@btn-success-color: #fff;
@btn-success-bg: @brand-success;
@btn-success-border: transparent;
@btn-info-color: #fff;
@btn-info-bg: @brand-info;
@btn-info-border: transparent;
@btn-warning-color: #fff;
@btn-warning-bg: @brand-warning;
@btn-warning-border: transparent;
@btn-danger-color: #fff;
@btn-danger-bg: @brand-danger;
@btn-danger-border: transparent;
@btn-link-disabled-color: @gray-light;
// Allows for customizing button radius independently from global border radius
@btn-border-radius-base: @border-radius-base;
@btn-border-radius-large: @border-radius-large;
@btn-border-radius-small: @border-radius-small;
//== Forms
//
//##
//** `<input>` background color
@input-bg: transparent;
//** `<input disabled>` background color
@input-bg-disabled: transparent;
//** Text color for `<input>`s
@input-color: @gray;
//** `<input>` border color
@input-border: transparent;
// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
//** Default `.form-control` border radius
// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.
@input-border-radius: @border-radius-base;
//** Large `.form-control` border radius
@input-border-radius-large: @border-radius-large;
//** Small `.form-control` border radius
@input-border-radius-small: @border-radius-small;
//** Border color for inputs on focus
@input-border-focus: #66afe9;
//** Placeholder text color
@input-color-placeholder: @gray-light;
//** Default `.form-control` height
@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
//** Large `.form-control` height
@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
//** Small `.form-control` height
@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
//** `.form-group` margin
@form-group-margin-bottom: 15px;
@legend-color: @gray-dark;
@legend-border-color: #e5e5e5;
//** Background color for textual input addons
@input-group-addon-bg: transparent;
//** Border color for textual input addons
@input-group-addon-border-color: @input-border;
//** Disabled cursor for form controls and buttons.
@cursor-disabled: not-allowed;
//== Dropdowns
//
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
@dropdown-bg: #fff;
//** Dropdown menu `border-color`.
@dropdown-border: rgba(0,0,0,.15);
//** Dropdown menu `border-color` **for IE8**.
@dropdown-fallback-border: #ccc;
//** Divider color for between dropdown items.
@dropdown-divider-bg: #e5e5e5;
//** Dropdown link text color.
@dropdown-link-color: @text-color;
//** Hover color for dropdown links.
@dropdown-link-hover-color: darken(@gray-dark, 5%);
//** Hover background for dropdown links.
@dropdown-link-hover-bg: @gray-lighter;
//** Active dropdown menu item text color.
@dropdown-link-active-color: @component-active-color;
//** Active dropdown menu item background color.
@dropdown-link-active-bg: @component-active-bg;
//** Disabled dropdown menu item background color.
@dropdown-link-disabled-color: @gray-light;
//** Text color for headers within dropdown menus.
@dropdown-header-color: @gray-light;
//** Deprecated `@dropdown-caret-color` as of v3.1.0
@dropdown-caret-color: @gray-light;
//-- Z-index master list
//
// Warning: Avoid customizing these values. They're used for a bird's eye view
// of components dependent on the z-axis and are designed to all work together.
//
// Note: These variables are not generated into the Customizer.
@zindex-navbar: 1000;
@zindex-dropdown: 1000;
@zindex-popover: 1060;
@zindex-tooltip: 1070;
@zindex-navbar-fixed: 1030;
@zindex-modal-background: 1040;
@zindex-modal: 1050;
//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
// Extra small screen / phone
//** Deprecated `@screen-xs` as of v3.0.1
@screen-xs: 480px;
//** Deprecated `@screen-xs-min` as of v3.2.0
@screen-xs-min: @screen-xs;
//** Deprecated `@screen-phone` as of v3.0.1
@screen-phone: @screen-xs-min;
// Small screen / tablet
//** Deprecated `@screen-sm` as of v3.0.1
@screen-sm: 768px;
@screen-sm-min: @screen-sm;
//** Deprecated `@screen-tablet` as of v3.0.1
@screen-tablet: @screen-sm-min;
// Medium screen / desktop
//** Deprecated `@screen-md` as of v3.0.1
@screen-md: 992px;
@screen-md-min: @screen-md;
//** Deprecated `@screen-desktop` as of v3.0.1
@screen-desktop: @screen-md-min;
// Large screen / wide desktop
//** Deprecated `@screen-lg` as of v3.0.1
@screen-lg: 1200px;
@screen-lg-min: @screen-lg;
//** Deprecated `@screen-lg-desktop` as of v3.0.1
@screen-lg-desktop: @screen-lg-min;
// So media queries don't overlap when required, provide a maximum
@screen-xs-max: (@screen-sm-min - 1);
@screen-sm-max: (@screen-md-min - 1);
@screen-md-max: (@screen-lg-min - 1);
//== Grid system
//
//## Define your custom responsive grid.
//** Number of columns in the grid.
@grid-columns: 12;
//** Padding between columns. Gets divided in half for the left and right.
@grid-gutter-width: 30px;
// Navbar collapse
//** Point at which the navbar becomes uncollapsed.
@grid-float-breakpoint: @screen-sm-min;
//** Point at which the navbar begins collapsing.
@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.
// Small screen / tablet
@container-tablet: (720px + @grid-gutter-width);
//** For `@screen-sm-min` and up.
@container-sm: @container-tablet;
// Medium screen / desktop
@container-desktop: (940px + @grid-gutter-width);
//** For `@screen-md-min` and up.
@container-md: @container-desktop;
// Large screen / wide desktop
@container-large-desktop: (1140px + @grid-gutter-width);
//** For `@screen-lg-min` and up.
@container-lg: @container-large-desktop;
//== Navbar
//
//##
// Basics of a navbar
@navbar-height: 64px;
@navbar-margin-bottom: @line-height-computed;
@navbar-border-radius: @border-radius-base;
@navbar-padding-horizontal: floor((@grid-gutter-width / 2));
@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
@navbar-collapse-max-height: 340px;
@navbar-default-color: @gray-light;
@navbar-default-bg: #fff;
@navbar-default-border: transparent;
// Navbar links
@navbar-default-link-color: @gray;
@navbar-default-link-hover-color: @gray-dark;
@navbar-default-link-hover-bg: transparent;
@navbar-default-link-active-color: @gray-dark;
@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
@navbar-default-link-disabled-color: #ccc;
@navbar-default-link-disabled-bg: transparent;
// Navbar brand label
@navbar-default-brand-color: @navbar-default-link-color;
@navbar-default-brand-hover-color: @navbar-default-link-hover-color;
@navbar-default-brand-hover-bg: transparent;
// Navbar toggle
@navbar-default-toggle-hover-bg: transparent;
@navbar-default-toggle-icon-bar-bg: rgba(0,0,0,0.5);
@navbar-default-toggle-border-color: transparent;
//=== Inverted navbar
// Reset inverted navbar basics
@navbar-inverse-color: @gray-light;
@navbar-inverse-bg: @brand-primary;
@navbar-inverse-border: transparent;
// Inverted navbar links
@navbar-inverse-link-color: lighten(@brand-primary, 30%);
@navbar-inverse-link-hover-color: #fff;
@navbar-inverse-link-hover-bg: transparent;
@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
@navbar-inverse-link-disabled-color: #444;
@navbar-inverse-link-disabled-bg: transparent;
// Inverted navbar brand label
@navbar-inverse-brand-color: @navbar-inverse-link-color;
@navbar-inverse-brand-hover-color: #fff;
@navbar-inverse-brand-hover-bg: transparent;
// Inverted navbar toggle\
@navbar-inverse-toggle-hover-bg: transparent;
@navbar-inverse-toggle-icon-bar-bg: rgba(0,0,0,0.5);
@navbar-inverse-toggle-border-color: transparent;
//== Navs
//
//##
//=== Shared nav styles
@nav-link-padding: 10px 15px;
@nav-link-hover-bg: @gray-lighter;
@nav-disabled-link-color: @gray-light;
@nav-disabled-link-hover-color: @gray-light;
//== Tabs
@nav-tabs-border-color: transparent;
@nav-tabs-link-hover-border-color: @gray-lighter;
@nav-tabs-active-link-hover-bg: transparent;
@nav-tabs-active-link-hover-color: @gray;
@nav-tabs-active-link-hover-border-color: transparent;
@nav-tabs-justified-link-border-color: @nav-tabs-border-color;
@nav-tabs-justified-active-link-border-color: @body-bg;
//== Pills
@nav-pills-border-radius: @border-radius-base;
@nav-pills-active-link-hover-bg: @component-active-bg;
@nav-pills-active-link-hover-color: @component-active-color;
//== Pagination
//
//##
@pagination-color: @link-color;
@pagination-bg: #fff;
@pagination-border: #ddd;
@pagination-hover-color: @link-hover-color;
@pagination-hover-bg: @gray-lighter;
@pagination-hover-border: #ddd;
@pagination-active-color: #fff;
@pagination-active-bg: @brand-primary;
@pagination-active-border: @brand-primary;
@pagination-disabled-color: @gray-light;
@pagination-disabled-bg: #fff;
@pagination-disabled-border: #ddd;
//== Pager
//
//##
@pager-bg: @pagination-bg;
@pager-border: @pagination-border;
@pager-border-radius: 15px;
@pager-hover-bg: @pagination-hover-bg;
@pager-active-bg: @pagination-active-bg;
@pager-active-color: @pagination-active-color;
@pager-disabled-color: @pagination-disabled-color;
//== Jumbotron
//
//##
@jumbotron-padding: 30px;
@jumbotron-color: inherit;
@jumbotron-bg: #f9f9f9;
@jumbotron-heading-color: @headings-color;
@jumbotron-font-size: ceil((@font-size-base * 1.5));
@jumbotron-heading-font-size: ceil((@font-size-base * 4.5));
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.
@state-success-text: @brand-success;
@state-success-bg: #dff0d8;
@state-success-border: darken(spin(@state-success-bg, -10), 5%);
@state-info-text: @brand-info;
@state-info-bg: #e1bee7;
@state-info-border: darken(spin(@state-info-bg, -10), 7%);
@state-warning-text: @brand-warning;
@state-warning-bg: #ffe0b2;
@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
@state-danger-text: @brand-danger;
@state-danger-bg: #f9bdbb;
@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
//== Tooltips
//
//##
//** Tooltip max width
@tooltip-max-width: 200px;
//** Tooltip text color
@tooltip-color: #fff;
//** Tooltip background color
@tooltip-bg: #727272;
@tooltip-opacity: .9;
//** Tooltip arrow width
@tooltip-arrow-width: 5px;
//** Tooltip arrow color
@tooltip-arrow-color: @tooltip-bg;
//== Popovers
//
//##
//** Popover body background color
@popover-bg: #fff;
//** Popover maximum width
@popover-max-width: 276px;
//** Popover border color
@popover-border-color: transparent;
//** Popover fallback border color
@popover-fallback-border-color: transparent;
//** Popover title background color
@popover-title-bg: darken(@popover-bg, 3%);
//** Popover arrow width
@popover-arrow-width: 10px;
//** Popover arrow color
@popover-arrow-color: @popover-bg;
//** Popover outer arrow width
@popover-arrow-outer-width: (@popover-arrow-width + 1);
//** Popover outer arrow color
@popover-arrow-outer-color: fadein(@popover-border-color, 7.5%);
//** Popover outer arrow fallback color
@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);
//== Labels
//
//##
//** Default label background color
@label-default-bg: @gray-light;
//** Primary label background color
@label-primary-bg: @brand-primary;
//** Success label background color
@label-success-bg: @brand-success;
//** Info label background color
@label-info-bg: @brand-info;
//** Warning label background color
@label-warning-bg: @brand-warning;
//** Danger label background color
@label-danger-bg: @brand-danger;
//** Default label text color
@label-color: #fff;
//** Default text color of a linked label
@label-link-hover-color: #fff;
//== Modals
//
//##
//** Padding applied to the modal body
@modal-inner-padding: 15px;
//** Padding applied to the modal title
@modal-title-padding: 15px;
//** Modal title line-height
@modal-title-line-height: @line-height-base;
//** Background color of modal content area
@modal-content-bg: #fff;
//** Modal content border color
@modal-content-border-color: transparent;
//** Modal content border color **for IE8**
@modal-content-fallback-border-color: #999;
//** Modal backdrop background color
@modal-backdrop-bg: #000;
//** Modal backdrop opacity
@modal-backdrop-opacity: .5;
//** Modal header border color
@modal-header-border-color: transparent;
//** Modal footer border color
@modal-footer-border-color: @modal-header-border-color;
@modal-lg: 900px;
@modal-md: 600px;
@modal-sm: 300px;
//== Alerts
//
//## Define alert colors, border radius, and padding.
@alert-padding: 15px;
@alert-border-radius: @border-radius-base;
@alert-link-font-weight: bold;
@alert-success-bg: @state-success-bg;
@alert-success-text: @state-success-text;
@alert-success-border: @state-success-border;
@alert-info-bg: @state-info-bg;
@alert-info-text: @state-info-text;
@alert-info-border: @state-info-border;
@alert-warning-bg: @state-warning-bg;
@alert-warning-text: @state-warning-text;
@alert-warning-border: @state-warning-border;
@alert-danger-bg: @state-danger-bg;
@alert-danger-text: @state-danger-text;
@alert-danger-border: @state-danger-border;
//== Progress bars
//
//##
//** Background color of the whole progress component
@progress-bg: #f5f5f5;
//** Progress bar text color
@progress-bar-color: #fff;
//** Variable for setting rounded corners on progress bar.
@progress-border-radius: @border-radius-base;
//** Default progress bar color
@progress-bar-bg: @brand-primary;
//** Success progress bar color
@progress-bar-success-bg: @brand-success;
//** Warning progress bar color
@progress-bar-warning-bg: @brand-warning;
//** Danger progress bar color
@progress-bar-danger-bg: @brand-danger;
//** Info progress bar color
@progress-bar-info-bg: @brand-info;
//== List group
//
//##
//** Background color on `.list-group-item`
@list-group-bg: #fff;
//** `.list-group-item` border color
@list-group-border: #ddd;
//** List group border radius
@list-group-border-radius: @border-radius-base;
//** Background color of single list items on hover
@list-group-hover-bg: #f5f5f5;
//** Text color of active list items
@list-group-active-color: @component-active-color;
//** Background color of active list items
@list-group-active-bg: @component-active-bg;
//** Border color of active list elements
@list-group-active-border: @list-group-active-bg;
//** Text color for content within active list items
@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
//** Text color of disabled list items
@list-group-disabled-color: @gray-light;
//** Background color of disabled list items
@list-group-disabled-bg: @gray-lighter;
//** Text color for content within disabled list items
@list-group-disabled-text-color: @list-group-disabled-color;
@list-group-link-color: #555;
@list-group-link-hover-color: @list-group-link-color;
@list-group-link-heading-color: #333;
//== Panels
//
//##
@panel-bg: #fff;
@panel-body-padding: 15px;
@panel-heading-padding: 10px 15px;
@panel-footer-padding: @panel-heading-padding;
@panel-border-radius: @border-radius-base;
//** Border color for elements within panels
@panel-inner-border: #ddd;
@panel-footer-bg: #f5f5f5;
@panel-default-text: @gray-dark;
@panel-default-border: #ddd;
@panel-default-heading-bg: #f5f5f5;
@panel-primary-text: #fff;
@panel-primary-border: @brand-primary;
@panel-primary-heading-bg: @brand-primary;
@panel-success-text: #fff;
@panel-success-border: @state-success-border;
@panel-success-heading-bg: @brand-success;
@panel-info-text: #fff;
@panel-info-border: @state-info-border;
@panel-info-heading-bg: @brand-info;
@panel-warning-text: #fff;
@panel-warning-border: @state-warning-border;
@panel-warning-heading-bg: @brand-warning;
@panel-danger-text: #fff;
@panel-danger-border: @state-danger-border;
@panel-danger-heading-bg: @brand-danger;
//== Thumbnails
//
//##
//** Padding around the thumbnail image
@thumbnail-padding: 4px;
//** Thumbnail background color
@thumbnail-bg: @body-bg;
//** Thumbnail border color
@thumbnail-border: #ddd;
//** Thumbnail border radius
@thumbnail-border-radius: @border-radius-base;
//** Custom text color for thumbnail captions
@thumbnail-caption-color: @text-color;
//** Padding around the thumbnail caption
@thumbnail-caption-padding: 9px;
//== Wells
//
//##
@well-bg: #f9f9f9;
@well-border: transparent;
//== Badges
//
//##
@badge-color: #fff;
//** Linked badge text color on hover
@badge-link-hover-color: #fff;
@badge-bg: @gray-light;
//** Badge text color in active nav link
@badge-active-color: @link-color;
//** Badge background color in active nav link
@badge-active-bg: #fff;
@badge-font-weight: normal;
@badge-line-height: 1;
@badge-border-radius: 10px;
//== Breadcrumbs
//
//##
@breadcrumb-padding-vertical: 8px;
@breadcrumb-padding-horizontal: 15px;
//** Breadcrumb background color
@breadcrumb-bg: #f5f5f5;
//** Breadcrumb text color
@breadcrumb-color: #ccc;
//** Text color of current page in the breadcrumb
@breadcrumb-active-color: @gray-light;
//** Textual separator for between breadcrumb elements
@breadcrumb-separator: "/";
//== Carousel
//
//##
@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
@carousel-control-color: #fff;
@carousel-control-width: 15%;
@carousel-control-opacity: .5;
@carousel-control-font-size: 20px;
@carousel-indicator-active-bg: #fff;
@carousel-indicator-border-color: #fff;
@carousel-caption-color: #fff;
//== Close
//
//##
@close-font-weight: normal;
@close-color: #000;
@close-text-shadow: none;
//== Code
//
//##
@code-color: #c7254e;
@code-bg: #f9f2f4;
@kbd-color: #fff;
@kbd-bg: #333;
@pre-bg: #f5f5f5;
@pre-color: @gray-dark;
@pre-border-color: #ccc;
@pre-scrollable-max-height: 340px;
//== Type
//
//##
//** Horizontal offset for forms and lists.
@component-offset-horizontal: 180px;
//** Text muted color
@text-muted: @gray-light;
//** Abbreviations and acronyms border color
@abbr-border-color: @gray-light;
//** Headings small color
@headings-small-color: @gray-light;
//** Blockquote small color
@blockquote-small-color: @gray-light;
//** Blockquote font size
@blockquote-font-size: (@font-size-base * 1.25);
//** Blockquote border color
@blockquote-border-color: @gray-lighter;
//** Page header border color
@page-header-border-color: @gray-lighter;
//** Width of horizontal description list titles
@dl-horizontal-offset: @component-offset-horizontal;
//** Point at which .dl-horizontal becomes horizontal
@dl-horizontal-breakpoint: @grid-float-breakpoint;
//** Horizontal line color.
@hr-border: @gray-lighter;

View File

@@ -0,0 +1,21 @@
.table i {
padding-top: 6px;
}
img.loading {
width: 25px;
}
.welcome table {
display: none;
width: 100%;
}
input {
margin-left: 5px;
margin-top: 8px;
}
.panel-body {
overflow: auto;
}

View File

@@ -0,0 +1,71 @@
.parcoords svg, .parcoords canvas {
font-size: 12px;
position: absolute;
}
.parcoords > canvas {
pointer-events: none;
}
.parcoords text.label {
font: 100%;
font-size: 12px;
cursor: drag;
}
.parcoords rect.background {
fill: transparent;
}
.parcoords rect.background:hover {
fill: rgba(120,120,120,0.2);
}
.parcoords .resize rect {
fill: rgba(0,0,0,0.1);
}
.parcoords rect.extent {
fill: rgba(255,255,255,0.25);
stroke: rgba(0,0,0,0.6);
}
.parcoords .axis line, .parcoords .axis path {
fill: none;
stroke: #222;
shape-rendering: crispEdges;
}
.parcoords canvas {
opacity: 1;
-moz-transition: opacity 0.3s;
-webkit-transition: opacity 0.3s;
-o-transition: opacity 0.3s;
}
.parcoords canvas.faded {
opacity: 0.25;
}
.parcoords {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: white;
}
/* data table styles */
.parcoords .row, .parcoords .header {
clear: left; font-size: 12px; line-height: 18px; height: 18px;
margin: 0px;
}
.parcoords .row:nth-child(odd) {
background: rgba(0,0,0,0.05);
}
.parcoords .header {
font-weight: bold;
}
.parcoords .cell {
float: left;
overflow: hidden;
white-space: nowrap;
width: 100px; height: 18px;
}
.parcoords .col-0 {
width: 180px;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
// from http://bl.ocks.org/3687826
module.exports = function(config) {
var columns = [];
var dg = function(selection) {
if (columns.length == 0) columns = d3.keys(selection.data()[0][0]);
// header
selection.selectAll(".header")
.data([true])
.enter().append("div")
.attr("class", "header")
var header = selection.select(".header")
.selectAll(".cell")
.data(columns);
header.enter().append("div")
.attr("class", function(d,i) { return "col-" + i; })
.classed("cell", true)
selection.selectAll(".header .cell")
.text(function(d) { return d; });
header.exit().remove();
// rows
var rows = selection.selectAll(".row")
.data(function(d) { return d; })
rows.enter().append("div")
.attr("class", "row")
rows.exit().remove();
var cells = selection.selectAll(".row").selectAll(".cell")
.data(function(d) { return columns.map(function(col){return d[col];}) })
// cells
cells.enter().append("div")
.attr("class", function(d,i) { return "col-" + i; })
.classed("cell", true)
cells.exit().remove();
selection.selectAll(".cell")
.text(function(d) { return d; });
return dg;
};
dg.columns = function(_) {
if (!arguments.length) return columns;
columns = _;
return this;
};
return dg;
};

62
caravel/assets/vendor/pygments.css vendored Normal file
View File

@@ -0,0 +1,62 @@
.codehilite .hll { background-color: #ffffcc }
.codehilite { background: #f8f8f8; }
.codehilite .c { color: #408080; font-style: italic } /* Comment */
.codehilite .err { border: 1px solid #FF0000 } /* Error */
.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
.codehilite .o { color: #666666 } /* Operator */
.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
.codehilite .gd { color: #A00000 } /* Generic.Deleted */
.codehilite .ge { font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #FF0000 } /* Generic.Error */
.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #00A000 } /* Generic.Inserted */
.codehilite .go { color: #808080 } /* Generic.Output */
.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.codehilite .gs { font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.codehilite .gt { color: #0040D0 } /* Generic.Traceback */
.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #B00040 } /* Keyword.Type */
.codehilite .m { color: #666666 } /* Literal.Number */
.codehilite .s { color: #BA2121 } /* Literal.String */
.codehilite .na { color: #7D9029 } /* Name.Attribute */
.codehilite .nb { color: #008000 } /* Name.Builtin */
.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.codehilite .no { color: #880000 } /* Name.Constant */
.codehilite .nd { color: #AA22FF } /* Name.Decorator */
.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.codehilite .nf { color: #0000FF } /* Name.Function */
.codehilite .nl { color: #A0A000 } /* Name.Label */
.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
.codehilite .nv { color: #19177C } /* Name.Variable */
.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
.codehilite .mf { color: #666666 } /* Literal.Number.Float */
.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.codehilite .sx { color: #008000 } /* Literal.String.Other */
.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
.codehilite .vc { color: #19177C } /* Name.Variable.Class */
.codehilite .vg { color: #19177C } /* Name.Variable.Global */
.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@@ -0,0 +1,146 @@
/**
* jQuery Select2 Sortable
* - enable select2 to be sortable via normal select element
*
* author : Vafour
* modified : Kevin Provance (kprovance)
* inspired by : jQuery Chosen Sortable (https://github.com/mrhenry/jquery-chosen-sortable)
* License : GPL
*/
(function ($) {
$.fn.extend({
select2SortableOrder: function () {
var $this = this.filter('[multiple]');
$this.each(function () {
var $select = $(this);
// skip elements not select2-ed
if (typeof ($select.data('select2')) !== 'object') {
return false;
}
var $select2 = $select.siblings('.select2-container');
var sorted;
// Opt group names
var optArr = [];
$select.find('optgroup').each(function(idx, val) {
optArr.push (val);
});
$select.find('option').each(function(idx, val) {
var groupName = $(this).parent('optgroup').prop('label');
var optVal = this;
if (groupName === undefined) {
if (this.value !== '' && !this.selected) {
optArr.push (optVal);
}
}
});
sorted = $($select2.find('.select2-choices li[class!="select2-search-field"]').map(function () {
if (!this) {
return undefined;
}
var id = $(this).data('select2Data').id;
return $select.find('option[value="' + id + '"]')[0];
}));
sorted.push.apply(sorted, optArr);
$select.children().remove();
$select.append(sorted);
});
return $this;
},
select2Sortable: function () {
var args = Array.prototype.slice.call(arguments, 0);
var $this = this.filter('[multiple]'),
validMethods = ['destroy'];
if (args.length === 0 || typeof (args[0]) === 'object') {
var defaultOptions = {
bindOrder: 'formSubmit', // or sortableStop
sortableOptions: {
placeholder: 'ui-state-highlight',
items: 'li:not(.select2-search-field)',
tolerance: 'pointer'
}
};
var options = $.extend(defaultOptions, args[0]);
// Init select2 only if not already initialized to prevent select2 configuration loss
if (typeof ($this.data('select2')) !== 'object') {
$this.select2();
}
$this.each(function () {
var $select = $(this)
var $select2choices = $select.siblings('.select2-container').find('.select2-choices');
// Init jQuery UI Sortable
$select2choices.sortable(options.sortableOptions);
switch (options.bindOrder) {
case 'sortableStop':
// apply options ordering in sortstop event
$select2choices.on("sortstop.select2sortable", function (event, ui) {
$select.select2SortableOrder();
});
$select.on('change', function (e) {
$(this).select2SortableOrder();
});
break;
default:
// apply options ordering in form submit
$select.closest('form').unbind('submit.select2sortable').on('submit.select2sortable', function () {
$select.select2SortableOrder();
});
break;
}
});
}
else if (typeof (args[0] === 'string')) {
if ($.inArray(args[0], validMethods) == -1) {
throw "Unknown method: " + args[0];
}
if (args[0] === 'destroy') {
$this.select2SortableDestroy();
}
}
return $this;
},
select2SortableDestroy: function () {
var $this = this.filter('[multiple]');
$this.each(function () {
var $select = $(this)
var $select2choices = $select.parent().find('.select2-choices');
// unbind form submit event
$select.closest('form').unbind('submit.select2sortable');
// unbind sortstop event
$select2choices.unbind("sortstop.select2sortable");
// destroy select2Sortable
$select2choices.sortable('destroy');
});
return $this;
}
});
}(jQuery));

View File

@@ -1,4 +1,5 @@
.viz_bignumber g.axis text {
.big_number g.axis text,
.big_number_total g.axis text {
font-size: 10px;
font-weight: normal;
color: gray;
@@ -8,18 +9,21 @@
font-weight: none;
}
.viz_bignumber text.big {
.big_number text.big,
.big_number_total text.big{
stroke: black;
text-anchor: middle;
fill: black;
}
.viz_bignumber g.tick line {
.big_number g.tick line,
.big_number_total g.tick line{
stroke-width: 1px;
stroke: grey;
}
.viz_bignumber .domain {
.big_number .domain,
.big_number_total .domain{
fill: none;
stroke: black;
stroke-width: 1;

View File

@@ -0,0 +1,181 @@
// JS
var d3 = window.d3 || require('d3');
// CSS
require('./big_number.css');
var px = require('../javascripts/modules/caravel.js');
function bigNumberVis(slice) {
var div = d3.select(slice.selector);
function render() {
d3.json(slice.jsonEndpoint(), function (error, payload) {
//Define the percentage bounds that define color from red to green
if (error !== null) {
slice.error(error.responseText);
return '';
}
var fd = payload.form_data;
var json = payload.data;
var color_range = [-1, 1];
var f = d3.format(fd.y_axis_format);
var fp = d3.format('+.1%');
var width = slice.width();
var height = slice.height();
div.selectAll("*").remove();
var svg = div.append('svg');
svg.attr("width", width);
svg.attr("height", height);
var data = json.data;
var compare_suffix = ' ' + json.compare_suffix;
var v_compare = null;
var v = null;
if (data.length > 1) {
v = data[data.length - 1][1];
} else {
v = data[data.length - 1][0];
}
if (json.compare_lag > 0) {
var pos = data.length - (json.compare_lag + 1);
if (pos >= 0) {
v_compare = (v / data[pos][1]) - 1;
}
}
var date_ext = d3.extent(data, function (d) {
return d[0];
});
var value_ext = d3.extent(data, function (d) {
return d[1];
});
var margin = 20;
var scale_x = d3.time.scale.utc().domain(date_ext).range([margin, width - margin]);
var scale_y = d3.scale.linear().domain(value_ext).range([height - (margin), margin]);
var colorRange = [d3.hsl(0, 1, 0.3), d3.hsl(120, 1, 0.3)];
var scale_color = d3.scale
.linear().domain(color_range)
.interpolate(d3.interpolateHsl)
.range(colorRange).clamp(true);
var line = d3.svg.line()
.x(function (d) {
return scale_x(d[0]);
})
.y(function (d) {
return scale_y(d[1]);
})
.interpolate("basis");
//Drawing trend line
var g = svg.append('g');
g.append('path')
.attr('d', function (d) {
return line(data);
})
.attr('stroke-width', 5)
.attr('opacity', 0.5)
.attr('fill', "none")
.attr('stroke-linecap', "round")
.attr('stroke', "grey");
g = svg.append('g')
.attr('class', 'digits')
.attr('opacity', 1);
var y = height / 2;
if (v_compare !== null) {
y = (height / 8) * 3;
}
//Printing big number
g.append('text')
.attr('x', width / 2)
.attr('y', y)
.attr('class', 'big')
.attr('alignment-baseline', 'middle')
.attr('id', 'bigNumber')
.style('font-weight', 'bold')
.style('cursor', 'pointer')
.text(f(v))
.style('font-size', d3.min([height, width]) / 3.5)
.attr('fill', 'white');
//Printing big number subheader text
if (json.subheader !== null) {
g.append('text')
.attr('x', width / 2)
.attr('y', y + d3.min([height, width]) / 4.5)
.text(json.subheader)
.attr('id', 'subheader_text')
.style('font-size', d3.min([height, width]) / 16)
.style('text-anchor', 'middle')
.attr('fill', c)
.attr('stroke', c);
}
var c = scale_color(v_compare);
//Printing compare %
if (v_compare !== null) {
g.append('text')
.attr('x', width / 2)
.attr('y', (height / 16) * 12)
.text(fp(v_compare) + compare_suffix)
.style('font-size', d3.min([height, width]) / 8)
.style('text-anchor', 'middle')
.attr('fill', c)
.attr('stroke', c);
}
var g_axis = svg.append('g').attr('class', 'axis').attr('opacity', 0);
g = g_axis.append('g');
var x_axis = d3.svg.axis()
.scale(scale_x)
.orient('bottom')
.ticks(4)
.tickFormat(px.formatDate);
g.call(x_axis);
g.attr('transform', 'translate(0,' + (height - margin) + ')');
g = g_axis.append('g').attr('transform', 'translate(' + (width - margin) + ',0)');
var y_axis = d3.svg.axis()
.scale(scale_y)
.orient('left')
.tickFormat(d3.format(fd.y_axis_format))
.tickValues(value_ext);
g.call(y_axis);
g.selectAll('text')
.style('text-anchor', 'end')
.attr('y', '-7')
.attr('x', '-4');
g.selectAll("text")
.style('font-size', '10px');
div.on('mouseover', function (d) {
var div = d3.select(this);
div.select('path').transition().duration(500).attr('opacity', 1)
.style('stroke-width', '2px');
div.select('g.digits').transition().duration(500).attr('opacity', 0.1);
div.select('g.axis').transition().duration(500).attr('opacity', 1);
})
.on('mouseout', function (d) {
var div = d3.select(this);
div.select('path').transition().duration(500).attr('opacity', 0.5)
.style('stroke-width', '5px');
div.select('g.digits').transition().duration(500).attr('opacity', 1);
div.select('g.axis').transition().duration(500).attr('opacity', 0);
});
slice.done(payload);
});
}
return {
render: render,
resize: render
};
}
module.exports = bigNumberVis;

View File

@@ -0,0 +1,19 @@
.directed_force path.link {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
.directed_force circle {
fill: #ccc;
stroke: #000;
stroke-width: 1.5px;
stroke-opacity: 1;
opacity: 0.75;
}
.directed_force text {
fill: #000;
font: 10px sans-serif;
pointer-events: none;
}

View File

@@ -0,0 +1,175 @@
// JS
var d3 = window.d3 || require('d3');
// CSS
require('./directed_force.css');
/* Modified from http://bl.ocks.org/d3noob/5141278 */
function directedForceVis(slice) {
var div = d3.select(slice.selector);
var link_length = slice.data.form_data.link_length || 200;
var charge = slice.data.form_data.charge || -500;
var render = function () {
var width = slice.width();
var height = slice.height() - 25;
d3.json(slice.jsonEndpoint(), function (error, json) {
if (error !== null) {
slice.error(error.responseText);
return '';
}
var links = json.data;
var nodes = {};
// Compute the distinct nodes from the links.
links.forEach(function (link) {
link.source = nodes[link.source] || (nodes[link.source] = {
name: link.source
});
link.target = nodes[link.target] || (nodes[link.target] = {
name: link.target
});
link.value = Number(link.value);
var target_name = link.target.name;
var source_name = link.source.name;
if (nodes[target_name].total === undefined) {
nodes[target_name].total = link.value;
}
if (nodes[source_name].total === undefined) {
nodes[source_name].total = 0;
}
if (nodes[target_name].max === undefined) {
nodes[target_name].max = 0;
}
if (link.value > nodes[target_name].max) {
nodes[target_name].max = link.value;
}
if (nodes[target_name].min === undefined) {
nodes[target_name].min = 0;
}
if (link.value > nodes[target_name].min) {
nodes[target_name].min = link.value;
}
nodes[target_name].total += link.value;
});
var force = d3.layout.force()
.nodes(d3.values(nodes))
.links(links)
.size([width, height])
.linkDistance(link_length)
.charge(charge)
.on("tick", tick)
.start();
var svg = div.append("svg")
.attr("width", width)
.attr("height", height);
// build the arrow.
svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var edgeScale = d3.scale.linear()
.range([0.1, 0.5]);
// add the links and the arrows
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", "link")
.style("opacity", function (d) {
return edgeScale(d.value / d.target.max);
})
.attr("marker-end", "url(#end)");
// define the nodes
var node = svg.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.on("mouseenter", function (d) {
d3.select(this)
.select("circle")
.transition()
.style('stroke-width', 5);
d3.select(this)
.select("text")
.transition()
.style('font-size', 25);
})
.on("mouseleave", function (d) {
d3.select(this)
.select("circle")
.transition()
.style('stroke-width', 1.5);
d3.select(this)
.select("text")
.transition()
.style('font-size', 12);
})
.call(force.drag);
// add the nodes
var ext = d3.extent(d3.values(nodes), function (d) {
return Math.sqrt(d.total);
});
var circleScale = d3.scale.linear()
.domain(ext)
.range([3, 30]);
node.append("circle")
.attr("r", function (d) {
return circleScale(Math.sqrt(d.total));
});
// add the text
node.append("text")
.attr("x", 6)
.attr("dy", ".35em")
.text(function (d) {
return d.name;
});
// add the curvy lines
function tick() {
path.attr("d", function (d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" +
d.source.x + "," +
d.source.y + "A" +
dr + "," + dr + " 0 0,1 " +
d.target.x + "," +
d.target.y;
});
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
slice.done(json);
});
};
return {
render: render,
resize: render
};
}
module.exports = directedForceVis;

View File

@@ -0,0 +1,8 @@
.select2-highlighted > .filter_box {
background-color: transparent;
border: 1px caravel black;
}
.dashboard .filter_box .slice_container > div {
padding-top: 0;
}

View File

@@ -0,0 +1,82 @@
// JS
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
var d3 = window.d3 || require('d3');
// CSS
require('./filter_box.css');
require('../javascripts/caravel-select2.js');
function filterBox(slice) {
var filtersObj = {};
var d3token = d3.select(slice.selector);
var fltChanged = function () {
var val = $(this).val();
var vals = [];
if (val !== '') {
vals = val.split(',');
}
slice.setFilter($(this).attr('name'), vals);
};
var refresh = function () {
d3token.selectAll("*").remove();
var container = d3token
.append('div')
.classed('padded', true);
$.getJSON(slice.jsonEndpoint(), function (payload) {
var maxes = {};
for (var filter in payload.data) {
var data = payload.data[filter];
maxes[filter] = d3.max(data, function (d) {
return d.metric;
});
var id = 'fltbox__' + filter;
var div = container.append('div');
div.append("label").text(filter);
div.append('div')
.attr('name', filter)
.classed('form-control', true)
.attr('multiple', '')
.attr('id', id);
filtersObj[filter] = $('#' + id).select2({
placeholder: "Select [" + filter + ']',
containment: 'parent',
dropdownAutoWidth: true,
data: data,
multiple: true,
formatResult: select2Formatter
})
.on('change', fltChanged);
}
slice.done(payload);
function select2Formatter(result, container /*, query, escapeMarkup*/) {
var perc = Math.round((result.metric / maxes[result.filter]) * 100);
var style = 'padding: 2px 5px;';
style += "background-image: ";
style += "linear-gradient(to right, lightgrey, lightgrey " + perc + "%, rgba(0,0,0,0) " + perc + "%";
$(container).attr('style', 'padding: 0px; background: white;');
$(container).addClass('filter_box');
return '<div style="' + style + '"><span>' + result.text + '</span></div>';
}
})
.fail(function (xhr) {
slice.error(xhr.responseText);
});
};
return {
render: refresh,
resize: refresh
};
}
module.exports = filterBox;

View File

@@ -0,0 +1,79 @@
.heatmap .axis text {
font: 10px sans-serif;
}
.heatmap .axis path,
.heatmap .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.heatmap svg {
}
.heatmap canvas, .heatmap img {
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
image-rendering: -webkit-optimize-contrast; /* Safari */
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
image-rendering: pixelated; /* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor; /* IE */
}
/* from d3-tip */
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
pointer-events: none;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
position: absolute;
pointer-events: none;
}
/* Northward tooltips */
.d3-tip.n:after {
content: "\25BC";
margin: -1px 0 0 0;
top: 100%;
left: 0;
text-align: center;
}
/* Eastward tooltips */
.d3-tip.e:after {
content: "\25C0";
margin: -4px 0 0 0;
top: 50%;
left: -8px;
}
/* Southward tooltips */
.d3-tip.s:after {
content: "\25B2";
margin: 0 0 1px 0;
top: -8px;
left: 0;
text-align: center;
}
/* Westward tooltips */
.d3-tip.w:after {
content: "\25B6";
margin: -4px 0 0 -1px;
top: 50%;
left: 100%;
}

View File

@@ -0,0 +1,209 @@
// JS
var $ = window.$ || require('jquery');
var px = window.px || require('../javascripts/modules/caravel.js');
var d3 = require('d3');
d3.tip = require('d3-tip'); //using window.d3 doesn't capture events properly bc of multiple instances
// CSS
require('./heatmap.css');
// Inspired from http://bl.ocks.org/mbostock/3074470
// https://jsfiddle.net/cyril123/h0reyumq/
function heatmapVis(slice) {
var margins = {
t: 10,
r: 10,
b: 50,
l: 60
};
function refresh() {
var width = slice.width();
var height = slice.height();
var hmWidth = width - (margins.l + margins.r);
var hmHeight = height - (margins.b + margins.t);
var fp = d3.format('.3p');
d3.json(slice.jsonEndpoint(), function (error, payload) {
var matrix = {};
if (error) {
slice.error(error.responseText);
return '';
}
var fd = payload.form_data;
var data = payload.data;
function ordScale(k, rangeBands, reverse) {
if (reverse === undefined) {
reverse = false;
}
var domain = {};
$.each(data, function (i, d) {
domain[d[k]] = true;
});
domain = Object.keys(domain).sort(function (a, b) {
return b - a;
});
if (reverse) {
domain.reverse();
}
if (rangeBands === undefined) {
return d3.scale.ordinal().domain(domain).range(d3.range(domain.length));
} else {
return d3.scale.ordinal().domain(domain).rangeBands(rangeBands);
}
}
var xScale = ordScale('x');
var yScale = ordScale('y', undefined, true);
var xRbScale = ordScale('x', [0, hmWidth]);
var yRbScale = ordScale('y', [hmHeight, 0]);
var X = 0,
Y = 1;
var heatmapDim = [xRbScale.domain().length, yRbScale.domain().length];
var color = px.color.colorScalerFactory(fd.linear_color_scheme);
var scale = [
d3.scale.linear()
.domain([0, heatmapDim[X]])
.range([0, hmWidth]),
d3.scale.linear()
.domain([0, heatmapDim[Y]])
.range([0, hmHeight])
];
var container = d3.select(slice.selector)
.style("left", "0px")
.style("position", "relative")
.style("top", "0px");
var canvas = container.append("canvas")
.attr("width", heatmapDim[X])
.attr("height", heatmapDim[Y])
.style("width", hmWidth + "px")
.style("height", hmHeight + "px")
.style("image-rendering", fd.canvas_image_rendering)
.style("left", margins.l + "px")
.style("top", margins.t + "px")
.style("position", "absolute");
var svg = container.append("svg")
.attr("width", width)
.attr("height", height)
.style("left", "0px")
.style("top", "0px")
.style("position", "absolute");
var rect = svg.append('g')
.attr("transform", "translate(" + margins.l + "," + margins.t + ")")
.append('rect')
.style('fill-opacity', 0)
.attr('stroke', 'black')
.attr("width", hmWidth)
.attr("height", hmHeight);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset(function () {
var k = d3.mouse(this);
var x = k[0] - (hmWidth / 2);
return [k[1] - 20, x];
})
.html(function (d) {
var k = d3.mouse(this);
var m = Math.floor(scale[0].invert(k[0]));
var n = Math.floor(scale[1].invert(k[1]));
if (m in matrix && n in matrix[m]) {
var obj = matrix[m][n];
var s = "";
s += "<div><b>" + fd.all_columns_x + ": </b>" + obj.x + "<div>";
s += "<div><b>" + fd.all_columns_y + ": </b>" + obj.y + "<div>";
s += "<div><b>" + fd.metric + ": </b>" + obj.v + "<div>";
s += "<div><b>%: </b>" + fp(obj.perc) + "<div>";
return s;
}
});
rect.call(tip);
var xAxis = d3.svg.axis()
.scale(xRbScale)
.tickValues(xRbScale.domain().filter(
function (d, i) {
return !(i % (parseInt(fd.xscale_interval, 10)));
}))
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yRbScale)
.tickValues(yRbScale.domain().filter(
function (d, i) {
return !(i % (parseInt(fd.yscale_interval, 10)));
}))
.orient("left");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + margins.l + "," + (margins.t + hmHeight) + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("transform", "rotate(-45)")
.style("font-weight", "bold");
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margins.l + ", 0)")
.call(yAxis);
rect.on('mousemove', tip.show);
rect.on('mouseout', tip.hide);
var context = canvas.node().getContext("2d");
context.imageSmoothingEnabled = false;
createImageObj();
// Compute the pixel colors; scaled by CSS.
function createImageObj() {
var imageObj = new Image();
var image = context.createImageData(heatmapDim[0], heatmapDim[1]);
var pixs = {};
$.each(data, function (i, d) {
var c = d3.rgb(color(d.perc));
var x = xScale(d.x);
var y = yScale(d.y);
pixs[x + (y * xScale.domain().length)] = c;
if (matrix[x] === undefined) {
matrix[x] = {};
}
if (matrix[x][y] === undefined) {
matrix[x][y] = d;
}
});
var p = -1;
for (var i = 0; i < heatmapDim[0] * heatmapDim[1]; i++) {
var c = pixs[i];
var alpha = 255;
if (c === undefined) {
c = d3.rgb('#F00');
alpha = 0;
}
image.data[++p] = c.r;
image.data[++p] = c.g;
image.data[++p] = c.b;
image.data[++p] = alpha;
}
context.putImageData(image, 0, 0);
imageObj.src = canvas.node().toDataURL();
}
slice.done();
});
}
return {
render: refresh,
resize: refresh
};
}
module.exports = heatmapVis;

View File

@@ -0,0 +1,25 @@
var $ = window.$ || require('jquery');
function iframeWidget(slice) {
function refresh() {
$('#code').attr('rows', '15');
$.getJSON(slice.jsonEndpoint(), function (payload) {
slice.container.html('<iframe style="width:100%;"></iframe>');
var iframe = slice.container.find('iframe');
iframe.css('height', slice.height());
iframe.attr('src', payload.form_data.url);
slice.done();
})
.fail(function (xhr) {
slice.error(xhr.responseText);
});
}
return {
render: refresh,
resize: refresh
};
}
module.exports = iframeWidget;

View File

@@ -0,0 +1,23 @@
var $ = window.$ || require('jquery');
function markupWidget(slice) {
function refresh() {
$('#code').attr('rows', '15');
$.getJSON(slice.jsonEndpoint(), function (payload) {
slice.container.html(payload.data.html);
slice.done();
})
.fail(function (xhr) {
slice.error(xhr.responseText);
});
}
return {
render: refresh,
resize: refresh
};
}
module.exports = markupWidget;

View File

@@ -0,0 +1,8 @@
g.caravel path {
stroke-dasharray: 5, 5;
}
.nvtooltip tr.highlight td {
font-weight: bold;
font-size: 15px !important;
}

View File

@@ -0,0 +1,221 @@
// JS
var $ = window.$ || require('jquery');
var d3 = window.d3 || require('d3');
var px = window.px || require('../javascripts/modules/caravel.js');
var nv = require('nvd3');
// CSS
require('../node_modules/nvd3/build/nv.d3.min.css');
require('./nvd3_vis.css');
function nvd3Vis(slice) {
var chart;
var render = function () {
$.getJSON(slice.jsonEndpoint(), function (payload) {
var fd = payload.form_data;
var viz_type = fd.viz_type;
var f = d3.format('.3s');
var colorKey = 'key';
nv.addGraph(function () {
switch (viz_type) {
case 'line':
if (fd.show_brush) {
chart = nv.models.lineWithFocusChart();
chart.lines2.xScale(d3.time.scale.utc());
chart.x2Axis
.showMaxMin(fd.x_axis_showminmax)
.staggerLabels(false);
} else {
chart = nv.models.lineChart();
}
// To alter the tooltip header
// chart.interactiveLayer.tooltip.headerFormatter(function(){return '';});
chart.xScale(d3.time.scale.utc());
chart.interpolate(fd.line_interpolation);
chart.xAxis
.showMaxMin(fd.x_axis_showminmax)
.staggerLabels(false);
break;
case 'bar':
chart = nv.models.multiBarChart()
.showControls(true)
.groupSpacing(0.1);
chart.xAxis
.showMaxMin(false)
.staggerLabels(true);
chart.stacked(fd.bar_stacked);
break;
case 'dist_bar':
chart = nv.models.multiBarChart()
.showControls(true) //Allow user to switch between 'Grouped' and 'Stacked' mode.
.reduceXTicks(false)
.rotateLabels(45)
.groupSpacing(0.1); //Distance between each group of bars.
chart.xAxis
.showMaxMin(false);
chart.stacked(fd.bar_stacked);
break;
case 'pie':
chart = nv.models.pieChart();
colorKey = 'x';
chart.valueFormat(f);
if (fd.donut) {
chart.donut(true);
chart.labelsOutside(true);
}
chart.labelsOutside(true);
chart.cornerRadius(true);
break;
case 'column':
chart = nv.models.multiBarChart()
.reduceXTicks(false)
.rotateLabels(45);
break;
case 'compare':
chart = nv.models.cumulativeLineChart();
chart.xScale(d3.time.scale.utc());
chart.xAxis
.showMaxMin(false)
.staggerLabels(true);
break;
case 'bubble':
var row = function (col1, col2) {
return "<tr><td>" + col1 + "</td><td>" + col2 + "</td></tr>";
};
chart = nv.models.scatterChart();
chart.showDistX(true);
chart.showDistY(true);
chart.tooltip.contentGenerator(function (obj) {
var p = obj.point;
var s = "<table>";
s += '<tr><td style="color:' + p.color + ';"><strong>' + p[fd.entity] + '</strong> (' + p.group + ')</td></tr>';
s += row(fd.x, f(p.x));
s += row(fd.y, f(p.y));
s += row(fd.size, f(p.size));
s += "</table>";
return s;
});
chart.pointRange([5, fd.max_bubble_size * fd.max_bubble_size]);
break;
case 'area':
chart = nv.models.stackedAreaChart();
chart.style(fd.stacked_style);
chart.xScale(d3.time.scale.utc());
chart.xAxis
.showMaxMin(false)
.staggerLabels(true);
break;
default:
throw new Error("Unrecognized visualization for nvd3" + viz_type);
}
if ("showLegend" in chart && typeof fd.show_legend !== 'undefined') {
chart.showLegend(fd.show_legend);
}
var height = slice.height();
height -= 15; // accounting for the staggered xAxis
chart.height(height);
slice.container.css('height', height + 'px');
if ((viz_type === "line" || viz_type === "area") && fd.rich_tooltip) {
chart.useInteractiveGuideline(true);
}
if (fd.y_axis_zero) {
chart.forceY([0, 1]);
} else if (fd.y_log_scale) {
chart.yScale(d3.scale.log());
}
if (fd.x_log_scale) {
chart.xScale(d3.scale.log());
}
var xAxisFormatter = null;
if (viz_type === 'bubble') {
xAxisFormatter = d3.format('.3s');
} else if (fd.x_axis_format === 'smart_date') {
xAxisFormatter = px.formatDate;
chart.xAxis.tickFormat(xAxisFormatter);
} else if (fd.x_axis_format !== undefined) {
xAxisFormatter = px.timeFormatFactory(fd.x_axis_format);
chart.xAxis.tickFormat(xAxisFormatter);
}
if (chart.hasOwnProperty("x2Axis")) {
chart.x2Axis.tickFormat(xAxisFormatter);
height += 30;
}
if (viz_type === 'bubble') {
chart.xAxis.tickFormat(d3.format('.3s'));
} else if (fd.x_axis_format === 'smart_date') {
chart.xAxis.tickFormat(px.formatDate);
} else if (fd.x_axis_format !== undefined) {
chart.xAxis.tickFormat(px.timeFormatFactory(fd.x_axis_format));
}
if (chart.yAxis !== undefined) {
chart.yAxis.tickFormat(d3.format('.3s'));
}
if (fd.contribution || fd.num_period_compare || viz_type === 'compare') {
chart.yAxis.tickFormat(d3.format('.3p'));
if (chart.y2Axis !== undefined) {
chart.y2Axis.tickFormat(d3.format('.3p'));
}
} else if (fd.y_axis_format) {
chart.yAxis.tickFormat(d3.format(fd.y_axis_format));
if (chart.y2Axis !== undefined) {
chart.y2Axis.tickFormat(d3.format(fd.y_axis_format));
}
}
chart.color(function (d, i) {
return px.color.category21(d[colorKey]);
});
d3.select(slice.selector).html('');
d3.select(slice.selector).append("svg")
.datum(payload.data)
.transition().duration(500)
.attr('height', height)
.call(chart);
return chart;
});
slice.done(payload);
})
.fail(function (xhr) {
slice.error(xhr.responseText);
});
};
var update = function () {
if (chart && chart.update) {
chart.update();
}
};
return {
render: render,
resize: update
};
}
module.exports = nvd3Vis;

View File

@@ -0,0 +1,92 @@
// JS
var $ = window.$ || require('jquery');
var d3 = window.d3 || require('d3');
d3.parcoords = require('../vendor/parallel_coordinates/d3.parcoords.js');
d3.divgrid = require('../vendor/parallel_coordinates/divgrid.js');
// CSS
require('../vendor/parallel_coordinates/d3.parcoords.css');
function parallelCoordVis(slice) {
function refresh() {
$('#code').attr('rows', '15');
$.getJSON(slice.jsonEndpoint(), function (payload) {
var data = payload.data;
var fd = payload.form_data;
var ext = d3.extent(data, function (d) {
return d[fd.secondary_metric];
});
ext = [ext[0], (ext[1] - ext[0]) / 2, ext[1]];
var cScale = d3.scale.linear()
.domain(ext)
.range(['red', 'grey', 'blue'])
.interpolate(d3.interpolateLab);
var color = function (d) {
return cScale(d[fd.secondary_metric]);
};
var container = d3.select(slice.selector);
var eff_height = fd.show_datatable ? (slice.height() / 2) : slice.height();
container.append('div')
.attr('id', 'parcoords_' + slice.container_id)
.style('height', eff_height + 'px')
.classed("parcoords", true);
var parcoords = d3.parcoords()('#parcoords_' + slice.container_id)
.width(slice.width())
.color(color)
.alpha(0.5)
.composite("darken")
.height(eff_height)
.data(payload.data)
.render()
.createAxes()
.shadows()
.reorderable()
.brushMode("1D-axes");
if (fd.show_datatable) {
// create data table, row hover highlighting
var grid = d3.divgrid();
container.append("div")
.datum(data.slice(0, 10))
.attr('id', "grid")
.call(grid)
.classed("parcoords", true)
.selectAll(".row")
.on({
mouseover: function (d) {
parcoords.highlight([d]);
},
mouseout: parcoords.unhighlight
});
// update data table on brush event
parcoords.on("brush", function (d) {
d3.select("#grid")
.datum(d.slice(0, 10))
.call(grid)
.selectAll(".row")
.on({
mouseover: function (d) {
parcoords.highlight([d]);
},
mouseout: parcoords.unhighlight
});
});
}
slice.done();
})
.fail(function (xhr) {
slice.error(xhr.responseText);
});
}
return {
render: refresh,
resize: refresh
};
}
module.exports = parallelCoordVis;

View File

@@ -0,0 +1,13 @@
.gridster .widget.pivot_table {
overflow: auto !important;
}
.table tr>th {
padding: 1px 5px !important;
font-size: small !important;
}
.table tr>td {
padding: 1px 5px !important;
font-size: small !important;
}

View File

@@ -0,0 +1,31 @@
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
require('datatables.net-bs');
require('./pivot_table.css');
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
module.exports = function (slice) {
var container = slice.container;
var form_data = slice.data.form_data;
function refresh() {
$.getJSON(slice.jsonEndpoint(), function (json) {
container.html(json.data);
if (form_data.groupby.length === 1) {
var table = container.find('table').DataTable({
paging: false,
searching: false
});
table.column('-1').order('desc').draw();
}
slice.done(json);
}).fail(function (xhr) {
slice.error(xhr.responseText);
});
}
return {
render: refresh,
resize: refresh
};
};

View File

@@ -0,0 +1,20 @@
.sankey .node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.sankey .node text {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.sankey .link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.sankey .link:hover {
stroke-opacity: .5;
}

View File

@@ -0,0 +1,138 @@
// CSS
require('./sankey.css');
// JS
var px = window.px || require('../javascripts/modules/caravel.js');
var d3 = window.d3 || require('d3');
d3.sankey = require('d3-sankey').sankey;
function sankeyVis(slice) {
var div = d3.select(slice.selector);
var render = function () {
var margin = {
top: 5,
right: 5,
bottom: 5,
left: 5
};
var width = slice.width() - margin.left - margin.right;
var height = slice.height() - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f");
div.selectAll("*").remove();
var svg = div.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey()
.nodeWidth(15)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
d3.json(slice.jsonEndpoint(), function (error, json) {
if (error !== null) {
slice.error(error.responseText);
return '';
}
var links = json.data;
var nodes = {};
// Compute the distinct nodes from the links.
links.forEach(function (link) {
link.source = nodes[link.source] || (nodes[link.source] = { name: link.source });
link.target = nodes[link.target] || (nodes[link.target] = { name: link.target });
link.value = Number(link.value);
});
nodes = d3.values(nodes);
sankey
.nodes(nodes)
.links(links)
.layout(32);
var link = svg.append("g").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function (d) {
return Math.max(1, d.dy);
})
.sort(function (a, b) {
return b.dy - a.dy;
});
link.append("title")
.text(function (d) {
return d.source.name + " → " + d.target.name + "\n" + formatNumber(d.value);
});
var node = svg.append("g").selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
})
.call(d3.behavior.drag()
.origin(function (d) {
return d;
})
.on("dragstart", function () {
this.parentNode.appendChild(this);
})
.on("drag", dragmove));
node.append("rect")
.attr("height", function (d) {
return d.dy;
})
.attr("width", sankey.nodeWidth())
.style("fill", function (d) {
d.color = px.color.category21(d.name.replace(/ .*/, ""));
return d.color;
})
.style("stroke", function (d) {
return d3.rgb(d.color).darker(2);
})
.append("title")
.text(function (d) {
return d.name + "\n" + formatNumber(d.value);
});
node.append("text")
.attr("x", -6)
.attr("y", function (d) {
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function (d) {
return d.name;
})
.filter(function (d) {
return d.x < width / 2;
})
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
function dragmove(d) {
d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}
slice.done(json);
});
};
return {
render: render,
resize: render
};
}
module.exports = sankeyVis;

View File

@@ -0,0 +1,49 @@
.sunburst text {
shape-rendering: crispEdges;
}
.sunburst path {
stroke: #333;
stroke-width: 0.5px;
}
.sunburst .center-label {
text-anchor: middle;
fill: #000;
pointer-events: none;
}
.sunburst .path-abs-percent {
font-size: 3.5em;
font-weight: 400;
}
.sunburst .path-cond-percent {
font-size: 2em;
}
.sunburst .path-metrics {
font-size: 1.5em;
}
.sunburst .path-ratio {
font-size: 1.2em;
}
.sunburst .breadcrumbs text {
font-weight: 600;
font-size: 1.2em;
text-anchor: middle;
fill: #000;
}
/* dashboard specific */
.dashboard .sunburst text {
font-size: 1em;
}
.dashboard .sunburst .path-abs-percent {
font-size: 2.5em;
}
.dashboard .sunburst .path-cond-percent {
font-size: 1.75em;
}
.dashboard .sunburst .path-metrics {
font-size: 1em;
}
.dashboard .sunburst .path-ratio {
font-size: 1em;
}

View File

@@ -0,0 +1,375 @@
var d3 = window.d3 || require('d3');
var px = require('../javascripts/modules/caravel.js');
var wrapSvgText = require('../javascripts/modules/utils.js').wrapSvgText;
require('./sunburst.css');
// Modified from http://bl.ocks.org/kerryrodden/7090426
function sunburstVis(slice) {
var container = d3.select(slice.selector);
var render = function () {
// vars with shared scope within this function
var margin = { top: 10, right: 5, bottom: 10, left: 5 };
var containerWidth = slice.width();
var containerHeight = slice.height();
var breadcrumbHeight = containerHeight * 0.085;
var visWidth = containerWidth - margin.left - margin.right;
var visHeight = containerHeight - margin.top - margin.bottom - breadcrumbHeight;
var radius = Math.min(visWidth, visHeight) / 2;
var colorByCategory = true; // color by category if primary/secondary metrics match
var maxBreadcrumbs, breadcrumbDims, // set based on data
totalSize, // total size of all segments; set after loading the data.
colorScale,
breadcrumbs, vis, arcs, gMiddleText; // dom handles
// Helper + path gen functions
var partition = d3.layout.partition()
.size([2 * Math.PI, radius * radius])
.value(function (d) { return d.m1; });
var arc = d3.svg.arc()
.startAngle(function (d) {
return d.x;
})
.endAngle(function (d) {
return d.x + d.dx;
})
.innerRadius(function (d) {
return Math.sqrt(d.y);
})
.outerRadius(function (d) {
return Math.sqrt(d.y + d.dy);
});
var formatNum = d3.format(".3s");
var formatPerc = d3.format(".3p");
container.select("svg").remove();
var svg = container.append("svg:svg")
.attr("width", containerWidth)
.attr("height", containerHeight);
d3.json(slice.jsonEndpoint(), function (error, rawData) {
if (error !== null) {
slice.error(error.responseText);
return '';
}
createBreadcrumbs(rawData);
createVisualization(rawData);
slice.done(rawData);
});
function createBreadcrumbs(rawData) {
var firstRowData = rawData.data[0];
maxBreadcrumbs = (firstRowData.length - 2) + 1; // -2 bc row contains 2x metrics, +extra for %label and buffer
breadcrumbDims = {
width: visWidth / maxBreadcrumbs,
height: breadcrumbHeight *0.8, // more margin
spacing: 3,
tipTailWidth: 10
};
breadcrumbs = svg.append("svg:g")
.attr("class", "breadcrumbs")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
breadcrumbs.append("svg:text")
.attr("class", "end-label");
}
// Main function to draw and set up the visualization, once we have the data.
function createVisualization(rawData) {
var tree = buildHierarchy(rawData.data);
vis = svg.append("svg:g")
.attr("class", "sunburst-vis")
.attr("transform", "translate(" + (margin.left + (visWidth / 2)) + "," + (margin.top + breadcrumbHeight + (visHeight / 2)) + ")")
.on("mouseleave", mouseleave);
arcs = vis.append("svg:g")
.attr("id", "arcs");
gMiddleText = vis.append("svg:g")
.attr("class", "center-label");
// Bounding circle underneath the sunburst, to make it easier to detect
// when the mouse leaves the parent g.
arcs.append("svg:circle")
.attr("r", radius)
.style("opacity", 0);
// For efficiency, filter nodes to keep only those large enough to see.
var nodes = partition.nodes(tree)
.filter(function (d) {
return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
});
var ext;
if (rawData.form_data.metric !== rawData.form_data.secondary_metric) {
colorByCategory = false;
ext = d3.extent(nodes, function (d) {
return d.m2 / d.m1;
});
colorScale = d3.scale.linear()
.domain([ext[0], ext[0] + ((ext[1] - ext[0]) / 2), ext[1]])
.range(["#00D1C1", "white", "#FFB400"]);
}
var path = arcs.data([tree]).selectAll("path")
.data(nodes)
.enter().append("svg:path")
.attr("display", function (d) {
return d.depth ? null : "none";
})
.attr("d", arc)
.attr("fill-rule", "evenodd")
.style("fill", function (d) {
return colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1);
})
.style("opacity", 1)
.on("mouseenter", mouseenter);
// Get total size of the tree = value of root node from partition.
totalSize = path.node().__data__.value;
}
// Fade all but the current sequence, and show it in the breadcrumb trail.
function mouseenter(d) {
var sequenceArray = getAncestors(d);
var parentOfD = sequenceArray[sequenceArray.length - 2] || null;
var absolutePercentage = (d.m1 / totalSize).toPrecision(3);
var conditionalPercentage = parentOfD ? (d.m1 / parentOfD.m1).toPrecision(3) : null;
var absolutePercString = formatPerc(absolutePercentage);
var conditionalPercString = parentOfD ? formatPerc(conditionalPercentage) : "";
var yOffsets = ["-25", "7", "35", "60"]; // 3 levels of text if inner-most level, 4 otherwise
var offsetIndex = 0;
// If metrics match, assume we are coloring by category
var metricsMatch = Math.abs(d.m1 - d.m2) < 0.00001;
gMiddleText.selectAll("*").remove();
gMiddleText.append("text")
.attr("class", "path-abs-percent")
.attr("y", yOffsets[offsetIndex++])
.text(absolutePercString + " of total");
if (conditionalPercString) {
gMiddleText.append("text")
.attr("class", "path-cond-percent")
.attr("y", yOffsets[offsetIndex++])
.text(conditionalPercString + " of parent");
}
gMiddleText.append("text")
.attr("class", "path-metrics")
.attr("y", yOffsets[offsetIndex++])
.text("m1: " + formatNum(d.m1) + (metricsMatch ? "" : ", m2: " + formatNum(d.m2)));
gMiddleText.append("text")
.attr("class", "path-ratio")
.attr("y", yOffsets[offsetIndex++])
.text((metricsMatch ? "" : ("m2/m1: " + formatPerc(d.m2 / d.m1))) );
// Reset and fade all the segments.
arcs.selectAll("path")
.style("stroke-width", null)
.style("stroke", null)
.style("opacity", 0.7);
// Then highlight only those that are an ancestor of the current segment.
arcs.selectAll("path")
.filter(function (node) {
return (sequenceArray.indexOf(node) >= 0);
})
.style("opacity", 1)
.style("stroke-width", "2px")
.style("stroke", "#000");
updateBreadcrumbs(sequenceArray, absolutePercString);
}
// Restore everything to full opacity when moving off the visualization.
function mouseleave(d) {
// Hide the breadcrumb trail
breadcrumbs.style("visibility", "hidden");
gMiddleText.selectAll("*").remove();
// Deactivate all segments during transition.
arcs.selectAll("path").on("mouseenter", null);
//gMiddleText.selectAll("*").remove();
// Transition each segment to full opacity and then reactivate it.
arcs.selectAll("path")
.transition()
.duration(200)
.style("opacity", 1)
.style("stroke", null)
.style("stroke-width", null)
.each("end", function () {
d3.select(this).on("mouseenter", mouseenter);
});
}
// Given a node in a partition layout, return an array of all of its ancestor
// nodes, highest first, but excluding the root.
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
// Generate a string that describes the points of a breadcrumb polygon.
function breadcrumbPoints(d, i) {
var points = [];
points.push("0,0");
points.push(breadcrumbDims.width + ",0");
points.push(breadcrumbDims.width + breadcrumbDims.tipTailWidth + "," + (breadcrumbDims.height / 2));
points.push(breadcrumbDims.width+ "," + breadcrumbDims.height);
points.push("0," + breadcrumbDims.height);
if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
points.push(breadcrumbDims.tipTailWidth + "," + (breadcrumbDims.height / 2));
}
return points.join(" ");
}
function updateBreadcrumbs(sequenceArray, percentageString) {
var g = breadcrumbs.selectAll("g")
.data(sequenceArray, function (d) {
return d.name + d.depth;
});
// Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g");
entering.append("svg:polygon")
.attr("points", breadcrumbPoints)
.style("fill", function (d) {
return colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1);
});
entering.append("svg:text")
.attr("x", (breadcrumbDims.width + breadcrumbDims.tipTailWidth) / 2)
.attr("y", breadcrumbDims.height / 4)
.attr("dy", "0.35em")
.attr("class", "step-label")
.text(function (d) { return d.name; })
.call(wrapSvgText, breadcrumbDims.width, breadcrumbDims.height / 2);
// Set position for entering and updating nodes.
g.attr("transform", function (d, i) {
return "translate(" + i * (breadcrumbDims.width + breadcrumbDims.spacing) + ", 0)";
});
// Remove exiting nodes.
g.exit().remove();
// Now move and update the percentage at the end.
breadcrumbs.select(".end-label")
.attr("x", (sequenceArray.length + 0.5) * (breadcrumbDims.width + breadcrumbDims.spacing))
.attr("y", breadcrumbDims.height / 2)
.attr("dy", "0.35em")
.text(percentageString);
// Make the breadcrumb trail visible, if it's hidden.
breadcrumbs.style("visibility", null);
}
function buildHierarchy(rows) {
var root = {
name: "root",
children: []
};
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
var m1 = Number(row[row.length - 2]);
var m2 = Number(row[row.length - 1]);
var levels = row.slice(0, row.length - 2);
if (isNaN(m1)) { // e.g. if this is a header row
continue;
}
var currentNode = root;
for (var j = 0; j < levels.length; j++) {
var children = currentNode.children || [];
var nodeName = levels[j];
// If the next node has the name "0", it will
var isLeafNode = (j >= levels.length - 1) || levels[j+1] === 0;
var childNode;
if (!isLeafNode) {
// Not yet at the end of the sequence; move down the tree.
var foundChild = false;
for (var k = 0; k < children.length; k++) {
if (children[k].name === nodeName) {
childNode = children[k];
foundChild = true;
break;
}
}
// If we don't already have a child node for this branch, create it.
if (!foundChild) {
childNode = {
name: nodeName,
children: []
};
children.push(childNode);
}
currentNode = childNode;
} else if (nodeName !== 0) {
// Reached the end of the sequence; create a leaf node.
childNode = {
name: nodeName,
m1: m1,
m2: m2
};
children.push(childNode);
}
}
}
function recurse(node) {
if (node.children) {
var sums;
var m1 = 0;
var m2 = 0;
for (var i = 0; i < node.children.length; i++) {
sums = recurse(node.children[i]);
m1 += sums[0];
m2 += sums[1];
}
node.m1 = m1;
node.m2 = m2;
}
return [node.m1, node.m2];
}
recurse(root);
return root;
}
};
return {
render: render,
resize: render
};
}
module.exports = sunburstVis;

Some files were not shown because too many files have changed in this diff Show More