Compare commits

..

1 Commits
0.8.9 ... 0.2.0

Author SHA1 Message Date
Maxime Beauchemin
61c667f3cc Preparing pypi package 2015-09-05 13:43:16 -07:00
251 changed files with 18271 additions and 21823 deletions

View File

@@ -1 +0,0 @@
repo_token: eESbYiv4An6KEvjpmguDs4L7YkubXbqn1

22
.gitignore vendored
View File

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

View File

@@ -1,23 +0,0 @@
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,23 +0,0 @@
language: python
python:
- "2.7"
- "3.4"
- "3.5"
cache:
directories:
- $HOME/.wheelhouse/
before_install:
- npm install -g npm@'>=2.7.1'
install:
- pip wheel -w $HOME/.wheelhouse -f $HOME/.wheelhouse .
- pip install --find-links=$HOME/.wheelhouse --no-index .
- pip install -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

View File

@@ -1,279 +0,0 @@
## Change Log
### 0.8.7 (2016/04/14 05:45 +00:00)
- [e5fabf3](https://github.com/airbnb/caravel/commit/e5fabf39df1b0fadc8b3bac02e21592cd61c3196) Adjusting positioning in the examples (@mistercrunch)
- [eb5a417](https://github.com/airbnb/caravel/commit/eb5a41728edc46dbcf837a78a7229a8129ed4dbf) Change the size of the column datasource_name in datasource creation … (#345) (@gyzmau)
- [91a3594](https://github.com/airbnb/caravel/commit/91a3594be34c18ea9a7b008b5f3a42149295a5e3) Fixing the thumbs and the galery (#346) (@mistercrunch)
- [52ebdc5](https://github.com/airbnb/caravel/commit/52ebdc50170a695b0490048ad02f3762bc187e97) add treemap (#344) (@andrewhn)
- [5cadd67](https://github.com/airbnb/caravel/commit/5cadd6794cfb6c70f54e968b9e82b2c991f5ea5b) Allowing to specify schema for tables (#330) (@mistercrunch)
- [0a94b36](https://github.com/airbnb/caravel/commit/0a94b36d3d371771561aabf5a3943379a0c5cfbb) Adding version subcommand to CLI (#329) (@mistercrunch)
- [21b3a5f](https://github.com/airbnb/caravel/commit/21b3a5f1990a06e9e555c1b296503b10f2851fc4) [big_number*] fixing a few bugs (#342) (@mistercrunch)
- [a76ccf4](https://github.com/airbnb/caravel/commit/a76ccf462de01ec8f4c2a7134ef0be9e76d998f1) [welcome page] shows the most recently updated items first (#343) (@mistercrunch)
- [8fe5790](https://github.com/airbnb/caravel/commit/8fe5790ec35b00f2f86df8ac4ab7444601ddc539) Don't die on malformed json in the extras field. Give feedback to user (#338) (@deniszgonjanin)
- [1e08b3e](https://github.com/airbnb/caravel/commit/1e08b3e8c589fc70d7cd4a14a5a9de49e2a93a45) add tooltips to sankey (#341) (@williaster)
- [77828b6](https://github.com/airbnb/caravel/commit/77828b630ab0f151c0377b6d1304c39e1cfdf65a) [bugfix] druid granularity form field should be select2_freeform (@mistercrunch)
- [af417b6](https://github.com/airbnb/caravel/commit/af417b6b58b4b4de4885d7d5ae16dd12626df401) Adding expression column description in the CRUD (@mistercrunch)
- [3d1fc99](https://github.com/airbnb/caravel/commit/3d1fc99353557aa42c14e760e01774fd624d7805) Adding not in docs about connecting to dbs over SSL (@mistercrunch)
- [1dd4165](https://github.com/airbnb/caravel/commit/1dd416570a3b4f5d431135459e9049e3eaf8f3a8) Json dumps iso date for Table view (#328) (@mistercrunch)
- [54fb76e](https://github.com/airbnb/caravel/commit/54fb76e68066257120a5056ca09f9a48fef797ec) Getting the SQL view back in a working state (#327) (@mistercrunch)
- [74975a1](https://github.com/airbnb/caravel/commit/74975a1606123c00f337b1b04b3594e962808275) Getting error messages to show up on the interactive debugger (@mistercrunch)
- [6d0b576](https://github.com/airbnb/caravel/commit/6d0b5767b3a74b23bf248fcfc2cd270233af95a9) Include connection parameters in call to Test Connection for a new database (#326) (@deniszgonjanin)
- [9ac979a](https://github.com/airbnb/caravel/commit/9ac979a336f0532d2323b3b37e1d1d2706e46216) Tweaks for the doc's gallery (@mistercrunch)
- [f32ebee](https://github.com/airbnb/caravel/commit/f32ebeeb989fe5332350ea2eb3b2c6c518495603) Fixing the way tables overflow in dashboard view (#310) (@mistercrunch)
- [807d686](https://github.com/airbnb/caravel/commit/807d68631273a5a9f0e9c460cdedf9da19370153) Showing thumbsnails when switching viz (#313) (@mistercrunch)
- [5b82249](https://github.com/airbnb/caravel/commit/5b822492c884c9b7c366f7d02c685eb1b7efc976) Linting to 99% (#317) (@mistercrunch)
- [c6da811](https://github.com/airbnb/caravel/commit/c6da8117b7d827f98984126d656470d93c9adc8f) Adding missing dep to dev-reqs.txt (@mistercrunch)
- [a9af6b1](https://github.com/airbnb/caravel/commit/a9af6b1b9697ad2f5c8808555f0f83b6fb83a3dc) Fix for undefined inner_time_filter on missing granularity in models.SqlaTable (#309) (@antbell)
- [fe045ad](https://github.com/airbnb/caravel/commit/fe045ad076d2c7d3810feb49dda84170e1595b6b) New viz: box plot (#312) (@andrewhn)
- [f8e5d30](https://github.com/airbnb/caravel/commit/f8e5d30e2eb4ef7c7d3312dc57d45bafe4c390cc) Revert previous css commit (@mistercrunch)
- [bfd1c87](https://github.com/airbnb/caravel/commit/bfd1c8711bf3de1218eb2f091c013b15d02a883c) Forcing widget overflow to be visible (@mistercrunch)
- [542b66e](https://github.com/airbnb/caravel/commit/542b66ef6800a7256ea307445536b0f6b85992e6) Giving credit where credit is due (#307) (@mistercrunch)
- [866e00d](https://github.com/airbnb/caravel/commit/866e00d78cf90a0022f9cfa21d098784e5d27c04) Detecting loops in Sankeys (#271) (@mistercrunch)
- [a3dcb0f](https://github.com/airbnb/caravel/commit/a3dcb0f309bf8c8036ce844c750053e35244b437) closes #292 (#304) (@mistercrunch)
- [25831f0](https://github.com/airbnb/caravel/commit/25831f00339b11f152b2f65904bb3fa9d9af05d0) Making prod web server run by default (@mistercrunch)
- [b47ca78](https://github.com/airbnb/caravel/commit/b47ca785c7c068d6ba5985fb25efcd4c0e565a15) Preserve order of breakdowns in bar_dist (#302) (@amancevice)
- [ef992b6](https://github.com/airbnb/caravel/commit/ef992b64491465455799cfe74210312273f7f55e) Fix week and month Time grain in MySQL (#297) (@prihoda)
- [fdcedd0](https://github.com/airbnb/caravel/commit/fdcedd097f4e39173935923123eeb994f02dd469) Adding edit link to datasource in explore view (#303) (@mistercrunch)
- [9a02c88](https://github.com/airbnb/caravel/commit/9a02c88afa56f1b1fc6515308e2400811409d8bd) Adding link to docs on navbar, re-indent (@mistercrunch)
- [b2de935](https://github.com/airbnb/caravel/commit/b2de935411ea2f77d9a4172f17864c90fac70bb6) Add OS dependencies link in development env docs (#300) (@lerrua)
- [ef64884](https://github.com/airbnb/caravel/commit/ef64884e532f2ff09a54cb4bc60a52e8534d95a6) [heatmap] fix bug to display this view properly in dashboards. fix bug to display their d3-tip tooltips in dashboards. don't show empty tooltips on heatmap. update logic for margins so they fit dynamically based on label size. (#301) (@williaster)
- [0afa5d2](https://github.com/airbnb/caravel/commit/0afa5d2cbaf1f4e009d81fe9c117f28178f3cbba) Added FAQ and db dependencies to docs (@mistercrunch)
- [eff0beb](https://github.com/airbnb/caravel/commit/eff0beb195b85f831d14e147a6dbecceb02dbc4e) Optimizing import statements for better readability and to avoid unused, excessive and duplicating imports in the project. (#294) (@sid88in)
- [2972122](https://github.com/airbnb/caravel/commit/2972122f40780a5d0f56e5037311764fb7e46781) Adding link to Strata slides (@mistercrunch)
### 0.8.6 (2016/04/07 21:26 +00:00)
- [d933a21](https://github.com/airbnb/caravel/commit/d933a2121608de06946850792c059ce26be7b473) Prettyfying an image in the docs (@mistercrunch)
- [c5dead4](https://github.com/airbnb/caravel/commit/c5dead4791b9d1444c0f42e4c34790160c63bbb6) v0.8.6 (@mistercrunch)
- [59169bf](https://github.com/airbnb/caravel/commit/59169bfc96a5dd682f551a42def9623aaa1e0b4c) Merge pull request #212 from airbnb/big_number_total (@michellethomas)
- [bcca840](https://github.com/airbnb/caravel/commit/bcca840f01547399a56c5273b006b2711d3df171) Adding from __future__ imports (#288) (@mistercrunch)
- [90a3b9f](https://github.com/airbnb/caravel/commit/90a3b9f2c4ab2b8bf2888852bbacfd53afeaf85a) Update INTHEWILD.md (@mherr)
- [a37e431](https://github.com/airbnb/caravel/commit/a37e4311508810f09e144bd7667a24e822e1e2c5) Adding _images to .gitignore (@mistercrunch)
- [bf38c71](https://github.com/airbnb/caravel/commit/bf38c714a51ac3a32ccc4ba73e4868ae5b8a103e) Adding missing images (@mistercrunch)
- [6b0b03e](https://github.com/airbnb/caravel/commit/6b0b03e0092bb90c783c2e67c898152bb01cb3e1) Fix localhost link in installation docs (@jules2689)
- [8556b09](https://github.com/airbnb/caravel/commit/8556b098f9a152b2497938dbf1ca41742dbd3aff) Enable Time Grain Option for Redshift (@mistercrunch)
- [d122b37](https://github.com/airbnb/caravel/commit/d122b37f5d182cd2bdbbf500ff7a1ac0b761d2e3) Add python-pip to the install docs (@jules2689)
- [1756c27](https://github.com/airbnb/caravel/commit/1756c279302f4df08cf1242fe3fec570d548240b) Adding upgrade instructions to docs (@mistercrunch)
- [7867267](https://github.com/airbnb/caravel/commit/786726760848e72abe9bb67d629ae805e3a171fa) SqlAlchemy -> SQLAlchemy in README.md (@AaronCritchley)
- [92d5886](https://github.com/airbnb/caravel/commit/92d588694b82e18dbbd458144582ca59a8248d0b) Improving the Installation docs (@mistercrunch)
- [d10eaec](https://github.com/airbnb/caravel/commit/d10eaeccc916f665e0538a799cd34be4c9983ac4) Adding a Gallery to the docs (@mistercrunch)
- [c2bb49f](https://github.com/airbnb/caravel/commit/c2bb49fec567c72f9752f99db783225787d87eb6) Fix 4e6a06bad7a8_init.py migration script to work with Postgres (@greens231)
- [062f2b8](https://github.com/airbnb/caravel/commit/062f2b81cf56e5c49453691fe800db2de8753e61) Datasource dropdown in Explore view (@mistercrunch)
- [65e72d0](https://github.com/airbnb/caravel/commit/65e72d0d075d158c6f4a934e04bfa90ce29ed0ee) Csv download improvements (@andrewhn)
- [3457276](https://github.com/airbnb/caravel/commit/345727635e23f71c39e2afeec4e07115b941730e) Adding y_axis_format to DistributionBarViz (@mistercrunch)
- [c2baa53](https://github.com/airbnb/caravel/commit/c2baa53b060cda4352582d238f53369e3f7773d0) bugfix datatables move to new package (@mistercrunch)
- [3175882](https://github.com/airbnb/caravel/commit/31758827aeeea65063f4a92d7a86a0ce993dde25) + button on Slice list view redirects to Table view with alert (@mistercrunch)
- [81de51b](https://github.com/airbnb/caravel/commit/81de51bf6ff772c3f44c2022e1f170c506c3d5b7) Minor tweaks (@mistercrunch)
- [0d1f27d](https://github.com/airbnb/caravel/commit/0d1f27dbc1a622fb0e40cb0fa872340349477d03) add postgres grains (@andrewhn)
- [c728288](https://github.com/airbnb/caravel/commit/c7282882d564889d90e334cefddc8b42bbb22dd9) Fixing the pagination display on welcome (@mistercrunch)
- [f9d04e8](https://github.com/airbnb/caravel/commit/f9d04e8a7269455e21a0ad13fc235b5f3f01777e) Fixed refresh_datasource redirect (@mistercrunch)
- [bf2e804](https://github.com/airbnb/caravel/commit/bf2e8043313cf31ef0a1f79df4902aef8c5f0b12) Removed trailing coma in Database.extra default (@mistercrunch)
- [c349b0a](https://github.com/airbnb/caravel/commit/c349b0a1c1059863cf27d3c0651986ba1330a045) Fixed link url in docs (@mistercrunch)
- [4d640b5](https://github.com/airbnb/caravel/commit/4d640b5a3d159e6d184fb6cdc6e605c356bf35d5) [fix] panel overflowing on welcome page (@mistercrunch)
- [380c3f0](https://github.com/airbnb/caravel/commit/380c3f0c7559a8137570a525b72b1488fe0854bb) Using boostrap panels for form fieldsets in explore view (@mistercrunch)
- [e3e8202](https://github.com/airbnb/caravel/commit/e3e8202c98ba925f2677f12d3c068635d2fb026a) clear element before redrawing sankey (@andrewhn)
- [8898444](https://github.com/airbnb/caravel/commit/889844407f1fd90821f108cb9c505dd7ff5c86e1) Adding extra options to deeper configure sqlalchemy (@mistercrunch)
- [f1830c3](https://github.com/airbnb/caravel/commit/f1830c36cf4cf97bccadbd9a9afa99f12a67d115) A better welcome page (@mistercrunch)
- [92f73b6](https://github.com/airbnb/caravel/commit/92f73b67ca1c6f486961962c796128f38320c3b8) Move window.alert() calls to bootstrap modals. Also log errors to console. (@williaster)
- [9c1af66](https://github.com/airbnb/caravel/commit/9c1af66ba425ce4d353c722af39a6b6cfdfd08ff) Fix ignored SQL where clauses (@skje)
- [2b31ab4](https://github.com/airbnb/caravel/commit/2b31ab498b4187a000f3c5a480831d59f8486e73) [hotfix] fixing json endpoint (@mistercrunch)
- [034fd07](https://github.com/airbnb/caravel/commit/034fd077e1215366c59742be5475abdc3bad1292) Doc formating fix (@mistercrunch)
- [ca44432](https://github.com/airbnb/caravel/commit/ca4443247e0e97d0466efa5876286967b490805e) Prettyfying the Caravel on README (@mistercrunch)
- [6f96252](https://github.com/airbnb/caravel/commit/6f96252e45f1e318902833c9622ab3d6e57555fd) A logo on the navbar (@mistercrunch)
- [0b93fd3](https://github.com/airbnb/caravel/commit/0b93fd373d2a9a1b5a6b844de112351c4a825218) [hotfix] hashing unicode in py3 (@mistercrunch)
- [c3789d5](https://github.com/airbnb/caravel/commit/c3789d53b4b071e6f076a9dbe7137d9b0a565b52) Removing duplicate get_table in fetch_metadata (@Jimexist)
- [aec3c0b](https://github.com/airbnb/caravel/commit/aec3c0b3580da23a767c0a83608170f8a89ce704) Fixing bug when datasource has been deleted (@mistercrunch)
- [ef45c20](https://github.com/airbnb/caravel/commit/ef45c205585f101b25f1610e9c1327b783518a9f) Hash cache keys to avoid too keys being too long. Resolves #240 (@karel1980)
- [10ab678](https://github.com/airbnb/caravel/commit/10ab678fc6e2257bb2a71220f8714a110fc8ba83) Finishing up the tutorial (@mistercrunch)
- [87fb40a](https://github.com/airbnb/caravel/commit/87fb40ae2655a28c32197a01541a57f7d4bc3634) Bumping version of npm up (@mistercrunch)
- [d245fb9](https://github.com/airbnb/caravel/commit/d245fb91b509810232118bd3f6ddf371687038c3) travis tweaks (@mistercrunch)
- [c60032a](https://github.com/airbnb/caravel/commit/c60032accefba2fbf64814a8e680368f990fc16e) Pillow with a capital P (@mistercrunch)
- [d2f5190](https://github.com/airbnb/caravel/commit/d2f51900f1853e6c40152407651f3baf298e4cde) Adding a tutorial (@mistercrunch)
- [93405dc](https://github.com/airbnb/caravel/commit/93405dc23a3056da63bbf4d15ec33e6576f7f20a) Clarify SQLALCHEMY_DATABASE_URI in the docs (@mistercrunch)
- [dafdb51](https://github.com/airbnb/caravel/commit/dafdb51f350778ba26684c3ccbc91c44a444897b) Adding Caravel Docker link to README (@mistercrunch)
- [2d0fdf7](https://github.com/airbnb/caravel/commit/2d0fdf7e59ab88651a914835a685cfee61ad68aa) Adding a CHANGELOG.md (@mistercrunch)
### 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 Github
Report bugs through Gihub
If you are reporting a bug, please include:
@@ -28,10 +28,14 @@ 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
Caravel could always use better documentation,
whether as part of the official Caravel docs,
Airflow could always use better documentation,
whether as part of the official Airflow docs,
in docstrings, `docs/*.rst` or even on the web as blog posts or
articles.
@@ -47,136 +51,40 @@ If you are proposing a feature:
- Remember that this is a volunteer-driven project, and that
contributions are welcome :)
## Latest Documentation
## Latests Documentation
[API Documentation](http://pythonhosted.com/caravel)
## Setting up a Python development environment
Check the [OS dependencies](http://airbnb.io/caravel/installation.html#os-dependencies) before follows these steps.
# fork the repo on github and then clone it
# alternatively you may want to clone the main repo but that won't work
# so well if you are planning on sending PRs
# git clone git@github.com:airbnb/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 the `caravel/assets/` 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
```
[API Documentation](http://pythonhosted.com/airflow)
## 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.

View File

@@ -1,11 +0,0 @@
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,8 +0,0 @@
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 *

193
README.md
View File

@@ -1,112 +1,125 @@
Caravel
Panoramix
=========
<img src="http://i.imgur.com/H0Kyvyi.jpg" style="border-radius: 20px; box-shadow:5px 5px 5px gray;" alt="Caravel" width="500"/>
[![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
Panoramix is a data exploration platform designed to be visual, intuitive
and interactive.
[this project used to be named **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
Buzz Phrases
------------
![img](http://i.imgur.com/JRbTnTx.png)
![img](http://i.imgur.com/4wRtxwb.png)
Caravel
---------
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**.
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 Caravel to stay blazing fast while
slicing and dicing large, realtime datasets
* Analytics at the speed of thought!
* Instantaneous learning curve
* Realtime analytics when querying [Druid.io](http://druid.io)
* Extentsible to infinity
![img](http://i.imgur.com/aOaH0ty.png)
Database Support
----------------
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).
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
ORM that is compatible with
[many external databases](http://docs.sqlalchemy.org/en/rel_1_0/core/engines.html).
What is Druid?
What's 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.*
Panoramix
---------
Panoramix's main goal is to make it easy to slice, dice and visualize data
out of Druid. It empowers its user to perform **analytics
at the speed of thought**.
Installation & Configuration
----------------------------
Panoramix started as a hackathon project at Airbnb in while running a POC
(proof of concept) on using Druid.
[See in the documentation](http://airbnb.io/caravel/installation.html)
Panoramix provides:
* A way to query intuitively a Druid dataset, allowing for grouping, filtering
limiting and defining a time granularity
* Many charts and visualization to analyze your data, as well as a flexible
way to extend the visualization capabilities
* An extensible, high granularity security model allowing intricate rules
on who can access which features, and integration with major
authentication providers (through Flask AppBuiler)
* A simple semantic layer, allowing to control how Druid datasources 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
More screenshots
----------------
![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 1](https://hub.docker.com/r/kochalex/caravel/)
[Docker image 2](https://hub.docker.com/r/amancevice/caravel/) (community contributed)
* [Slides from Strata (March 2016)](https://drive.google.com/open?id=0B5PVE0gzO81oOVJkdF9aNkJMSmM)
Tip of the Hat
--------------
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 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
Installation
------------
Interested in contributing? Casual hacking? Check out [Contributing.MD](https://github.com/airbnb/caravel/blob/master/CONTRIBUTING.md)
Follow these few simple steps to install Panoramix
```
# Install panoramix
pip install panoramix
# Create an admin user
fabmanager create-admin --app panoramix
# Start the web server
panoramix
```
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

58
TODO.md
View File

@@ -1,53 +1,7 @@
# TODO
List of TODO items for Caravel
## 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
* 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!)
* in/notin filters autocomplete (druid)
## New viz
* Maps that use geocodes
* Time animated scatter plots
* Horizon charts
* Calendar heatmap
* Chord diagram
* ...
## Community
* Turorial vids
* in/notin filters autocomplete
* DRUID: Allow for post aggregations (ratios!)
* compare time ranges
* csv export out of table view
* Save / bookmark / url shortener
* SQL: Find a way to manage granularity

View File

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

3
babel/babel.cfg Normal file
View File

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

1
babel/messages.pot Normal file
View File

@@ -0,0 +1 @@

View File

@@ -1,55 +0,0 @@
"""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, redirect
from flask.ext.appbuilder import SQLA, AppBuilder, IndexView
from flask.ext.appbuilder.baseviews import expose
from flask.ext.cache import Cache
from flask.ext.migrate import Migrate
from caravel import version
VERSION = version.VERSION_STRING
APP_DIR = os.path.dirname(__file__)
CONFIG_MODULE = os.environ.get('CARAVEL_CONFIG', 'caravel.config')
# Logging configuration
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(name)s:%(message)s')
logging.getLogger().setLevel(logging.DEBUG)
app = Flask(__name__)
app.config.from_object(CONFIG_MODULE)
if not app.debug:
# In production mode, add log handler to sys.stderr.
app.logger.addHandler(logging.StreamHandler())
app.logger.setLevel(logging.INFO)
db = SQLA(app)
cache = Cache(app, config=app.config.get('CACHE_CONFIG'))
migrate = Migrate(app, db, directory=APP_DIR + "/migrations")
class MyIndexView(IndexView):
@expose('/')
def index(self):
return redirect('/caravel/welcome')
appbuilder = AppBuilder(
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 caravel import config, views # noqa

View File

@@ -1,82 +0,0 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
error = (
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM8OI++=~~~~~~=+?IODMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMD$~~~~~~~~~~~~~~~~~~~~~~~=$MMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMN8?:~~~~~~~~~~~~~~~~~~~~~~~~~~=+8NMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMO=~~~~~~~~~~~~~~~~~+I??~~~~~~~~~~~~~+DMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMNI~~~~~~~~~~~~~~~~~~IIIII=~~~~~~~~~~~~~~=NMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMM+=~~~~~~~~~~~~~~~~~~~=III+~~~~~~~~~~~~~~~~~?8MMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMM?~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+++=~~~~8MMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMI=~~~~~~~~~~~~~~~~~~~~~~~~~III?I~~~~~~~~,:++++++~~8MMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMN7~~~~~~~~~~~~~~~~==+=~~~~~~=IIIII~~~~~~:. ..:=++=~=MMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMO=~~~~~~~~~~~~~~~~+++=~~~~~~~~??I?I~~~~~~. ...,~~~~IMMMMMMMMMMMMM\n"+
"MMMMMMMMMMM~~~~~~~~~~~~~~~~~+++:,~~~~~~~~~~~?=~~~~~:. ..~~~~~OMMMMMMMMMMMM\n"+
"MMMMMMMMM$=~~~~~~~~~~~~~~~=++:.. ..~~~~~~~~~~~~~~~~,. . . :~~~~~OMMMMMMMMMMM\n"+
"MMMMMMMMM~~~~~~~~~~~~~~~~+++,. .~~~~~~~~~~~~~~~.. .. . .~~~~~=OMMMMMMMMMM\n"+
"MMMMMMMM?~~~~~~~~~~~~~~~=+~. .~~~~~~~~~~~~~~. ,MMMMM,=~~~~~~NMMMMMMMMM\n"+
"MMMMMMMN~~~~~~~~~~~~~~~~~,. .,~~~~~~~~~~~~~.. ZMMM,+Z:~~~~~~$MMMMMMMMM\n"+
"MMMMMM8?~~~~~~~~~~~~~~~~~.. ..~~~~~~~~~~~~~:. DMMM,+D~~~~~~~~IMMMMMMMM\n"+
"MMMMMMI~~~~~~~~~~~~~~~~~~.. :MMMO~~~~~~~~~~~~~~~,.. ?MMMMMI~~~~~~~~~MMMMMMMM\n"+
"MMMMMM=~~~~~~~~~~~~~~~~~~.. MMM+=M:~~~~~~~~~~~~~:. .:IM$~~~~~~~~~~~8MMMMMMM\n"+
"MMMMMD~~~~~~~~~~~~~~~~~~~:. MMM:,M:~~~~~~~~~~~~~~~.......:~~~~~~~~~~$MMMMMMM\n"+
"MMMMMI~~~~~~~~~~~~~~~~~~~~, MMMMMM~~~~~~~~~~~~~~~~~~,..:~~~~~~~~~~~~+MMMMMMM\n"+
"MMMMD+~~~~~~~~~~~~~~~~~~~~~. $MMMM$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=MMMMMMM\n"+
"MMMM8~~~~~~~~~~~~~~~~~~~~~~:. . .:~~~~~~,..:. .=~~~~~~~~~~~~~~~~~~~~MMMMMMM\n"+
"MMMMO~~~~~~~~~~~~~~~~~~~~~~~:, .:~~~~~=8.. .+ . =8ZI~~~~~~~~~~~~~~~~=MMMMMMM\n"+
"MMMMZ=~~~~~~~~~~~~~~~~~~~~~~~~:,,,:~~~~~~IZ8:. .O....888?~~~~~~~~~~~~~~~+MMMMMMM\n"+
"MMMMO=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~?888=...I~I88888O?~~~~~~~~~~~~~~7MMMMMMM\n"+
"MMMMO~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Z888OO88888888888O?~~~~~~~~~~~~~OMMMMMMM\n"+
"MMMMD+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=8888888888888888888~~~~~~~~~~~~+MMMMMMMM\n"+
"MMMMM7~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~?8888888888888888888?~~~~~~~~~~=$MMMMMMMM\n"+
"MMMMMD~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=$8888888888888888888O~~~~~~~~~~8MMMMMMMMM\n"+
"MMMMMN=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Z88888888888888888ZZ7=~~~~~~~~?MMMMMMMMMM\n"+
"MMMMMMZ=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Z88888888Z7I===~~~~~~~~~~~~~=OMMMMMMMMMMM\n"+
"MMMMMMN$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=$88888O7?=~~~~~~~~~~~~~~~~~~OMMMMMMMMMMMM\n"+
"MMMMMMMM?~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~I8OZ+~~~~~~~~~~~~~~~~~~~~=DMMMMMMMMMMMMMM\n"+
"MMMMMMMM8=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+$+=~~~~~~~~~~~~~~~~~~~~+MMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMD7~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=$DMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMM?~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=$OMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMD7=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ZMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMZ7=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~78MMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMM8OI=~~~~~~~~~~~~~~~~~~~=+?ZDNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMNDZ7?++~=~==~+?IONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"+
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM")
stacktrace="""
-------------------------------------------------------------------------------------------------------
=======================================================================================================
-------------------------------------------------------------------------------------------------------
___ ___ ___
( ) ( ) ( )
.--. | |_ .---. .--. | | ___ | |_ ___ .-. .---. .--. .--.
/ _ \ ( __) / .-, \ / \ | | ( ) ( __) ( ) \ / .-, \ / \ / \\
. .' `. ; | | (__) ; | | .-. ; | | ' / | | | ' .-. ; (__) ; | | .-. ; | .-. ;
| ' | | | | ___ .'` | | |(___) | |,' / | | ___ | / (___) .'` | | |(___) | | | |
_\_`.(___) | |( ) / .'| | | | | . '. | |( ) | | / .'| | | | | |/ |
( ). '. | | | | | / | | | | ___ | | `. \ | | | | | | | / | | | | ___ | ' _.'
| | `\ | | ' | | ; | ; | | '( ) | | \ \ | ' | | | | ; | ; | | '( ) | .'.-.
; '._,' ' ' `-' ; ' `-' | ' `-' | | | \ . ' `-' ; | | ' `-' | ' `-' | ' `-' /
'.___.' `.__. `.__.'_. `.__,' (___ ) (___) `.__. (___) `.__.'_. `.__,' `.__.'
-------------------------------------------------------------------------------------------------------
=======================================================================================================
-------------------------------------------------------------------------------------------------------
"""
boat = """\
+ +
)`.).
)``)``) .~~
).-'.-')|)
|-).-).-'_'-/
~~~\ `o-o-o' /~~~~
~~~'---.____/~~~"""

View File

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

View File

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

View File

@@ -1,234 +0,0 @@
{
"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 }]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -1,5 +0,0 @@
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

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

View File

@@ -1,298 +0,0 @@
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');
require('../stylesheets/dashboard.css');
var Dashboard = function (dashboardData) {
var dashboard = $.extend(dashboardData, {
filters: {},
init: function () {
this.initDashboardView();
this.firstLoad = true;
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);
}
});
this.slices = sliceObjects;
this.refreshTimer = null;
this.startPeriodicRender(0);
},
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);
},
stopPeriodicRender: function () {
if (this.refreshTimer) {
clearTimeout(this.refreshTimer);
this.refreshTimer = null;
}
},
startPeriodicRender: function (interval) {
this.stopPeriodicRender();
var dash = this;
var maxRandomDelay = Math.min(interval * 0.2, 5000);
var refreshAll = function () {
dash.slices.forEach(function (slice) {
var force = !dash.firstLoad;
setTimeout(function () {
slice.render(force);
},
//Randomize to prevent all widgets refreshing at the same time
maxRandomDelay * Math.random());
});
dash.firstLoad = false;
};
var fetchAndRender = function () {
refreshAll();
if (interval > 0) {
dash.refreshTimer = setTimeout(function () {
fetchAndRender();
}, interval);
}
};
fetchAndRender();
},
refreshExcept: function (slice_id) {
var immune = this.metadata.filter_immune_slices || [];
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_interval").on("change", function () {
var interval = $(this).find('option:selected').val() * 1000;
dashboard.startPeriodicRender(interval);
});
$('#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

@@ -1,366 +0,0 @@
// 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('../stylesheets/explore.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);
}
function formatViz(viz) {
var url = '/static/assets/images/viz_thumbnails/' + viz.id + '.png';
var no_img = '/static/assets/images/noimg.png';
return $(
'<img class="viz-thumb-option" src="' + url + '" onerror="this.src=\'' + no_img + '\';">' +
'<span>' + viz.text + '</span>'
);
}
$(".select2").select2({
dropdownAutoWidth: true
});
$(".select2Sortable").select2({
dropdownAutoWidth: true
});
$(".select2-with-images").select2({
dropdownAutoWidth: true,
dropdownCssClass: "bigdrop",
formatResult: formatViz
});
$(".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

@@ -1,18 +0,0 @@
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

@@ -1,383 +0,0 @@
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',
box_plot: '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',
treemap: 'treemap.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) {
if (!s) { return; }
// 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;
var slice = this;
$(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.css('height', this.height());
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.css('height', this.height());
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

@@ -1,80 +0,0 @@
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

@@ -1,106 +0,0 @@
var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
var showModal = require('./modules/utils.js').showModal;
require('./caravel-select2.js');
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');
require('../stylesheets/sql.css');
$(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

@@ -1,13 +0,0 @@
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

@@ -1,70 +0,0 @@
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, modelView, orderCol, order) {
// Builds a dataTable from a flask appbuilder api endpoint
var url = '/' + modelView.toLowerCase() + '/api/read';
url += '?_oc_' + modelView + '=' + orderCol;
url += '&_od_' + modelView +'=' + order;
$.getJSON(url, 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', 'changed_on', 'desc');
modelViewTable('#slice_table', 'SliceAsync', 'changed_on', 'desc');
});

View File

@@ -1,78 +0,0 @@
{
"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

@@ -1,202 +0,0 @@
body {
margin: 0px !important;
}
.emph {
font-weight: bold;
}
.alert.alert-danger > .debugger {
color: red;
}
.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;
}
.disabledButton {
pointer-events: none;
}
.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;
}
img.viz-thumb-option {
width: 100px;
border: 1px solid gray;
margin-right: 5px;
border-radius: 5px;
}
.select2-drop.bigdrop .select2-results {
max-height: 700px;
}
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

@@ -1,47 +0,0 @@
.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;
position: absolute;
}
.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 */
}

View File

@@ -1,9 +0,0 @@
.widget {
position: relative;
}
.slice_container {
position: absolute;
left: 0;
top: 0;
}

View File

@@ -1,616 +0,0 @@
// 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

@@ -1,5 +0,0 @@
// 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

@@ -1,881 +0,0 @@
// 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

@@ -1,41 +0,0 @@
.topsql {
height: 250px;
}
.dataTables_filter {
padding-top: 5px;
padding-right: 5px;
}
.bordered {
padding: 0px 0px;
border: 1px solid grey;
border-radius: 5px;
background-color: #EEE;
}
div.alert {
padding: 5px;
margin: 0px;
}
.metadata {
overflow: auto;
width: 300px;
height: 100px;
}
.fillup {
width: 100%;
height: 100%;
}
.fillheight {
height: 100%;
}
.interactions {
padding-bottom: 10px;
}
#results {
overflow: auto;
font-size: 12px;
margin-bottom: 5px;
}
table tbody tr td {
padding: 1px 4px;
font-size: small;
}

View File

@@ -1,21 +0,0 @@
.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

@@ -1,71 +0,0 @@
.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

@@ -1,59 +0,0 @@
// 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;
};

View File

@@ -1,62 +0,0 @@
.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

@@ -1,146 +0,0 @@
/**
* 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,30 +0,0 @@
.big_number g.axis text,
.big_number_total g.axis text {
font-size: 10px;
font-weight: normal;
color: gray;
fill: gray;
text-anchor: middle;
alignment-baseline: middle;
font-weight: none;
}
.big_number text.big,
.big_number_total text.big{
stroke: black;
text-anchor: middle;
fill: black;
}
.big_number g.tick line,
.big_number_total g.tick line{
stroke-width: 1px;
stroke: grey;
}
.big_number .domain,
.big_number_total .domain{
fill: none;
stroke: black;
stroke-width: 1;
}

View File

@@ -1,187 +0,0 @@
// 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 '';
}
div.html(''); //reset
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 (fd.viz_type === 'big_number') {
v = data[data.length - 1][1];
} else {
v = data[0][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");
var g = svg.append('g');
var y = height / 2;
//Printing big number
g.append("g").attr("class", "digits")
.attr('opacity', 1)
.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');
if (fd.viz_type === 'big_number') {
//Drawing trend line
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);
if (v_compare !== null) {
y = (height / 8) * 3;
}
//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.selectAll('path').transition().duration(500).attr('opacity', 1)
.style('stroke-width', '2px');
div.selectAll('g.digits').transition().duration(500).attr('opacity', 0.1);
div.selectAll('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.selectAll('g.digits').transition().duration(500).attr('opacity', 1);
div.selectAll('g.axis').transition().duration(500).attr('opacity', 0);
});
}
slice.done(payload);
});
}
return {
render: render,
resize: render
};
}
module.exports = bigNumberVis;

View File

@@ -1,19 +0,0 @@
.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

@@ -1,175 +0,0 @@
// 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

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

View File

@@ -1,82 +0,0 @@
// 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

@@ -1,88 +0,0 @@
.heatmap .slice_container {
position: relative;
top: 0;
left: 0;
height: 100%;
}
.heatmap .axis text {
font: 10px sans-serif;
text-rendering: optimizeLegibility;
}
.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;
z-index: 1000;
}
/* 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

@@ -1,234 +0,0 @@
// 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) {
function refresh() {
var margin = {
top: 10,
right: 10,
bottom: 35,
left: 35
};
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;
// Dynamically adjusts based on max x / y category lengths
function adjustMargins(data, margins) {
var pixelsPerCharX = 4.5; // approx, depends on font size
var pixelsPerCharY = 6.8; // approx, depends on font size
var longestX = 1;
var longestY = 1;
var datum;
for (var i = 0; i < data.length; i++) {
datum = data[i];
longestX = Math.max(longestX, datum.x.length || 1);
longestY = Math.max(longestY, datum.y.length || 1);
}
margins.left = Math.ceil(Math.max(margins.left, pixelsPerCharY * longestY));
margins.bottom = Math.ceil(Math.max(margins.bottom, pixelsPerCharX * longestX));
}
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);
}
}
adjustMargins(data, margin);
var width = slice.width();
var height = slice.height();
var hmWidth = width - (margin.left + margin.right);
var hmHeight = height - (margin.bottom + margin.top);
var fp = d3.format('.3p');
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);
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", margin.left + "px")
.style("top", margin.top + "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(" + margin.left + "," + margin.top + ")")
.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 s = "";
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];
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>";
tip.style("display", null);
} else {
// this is a hack to hide the tooltip because we have map it to a single <rect>
// d3-tip toggles opacity and calling hide here is undone by the lib after this call
tip.style("display", "none");
}
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(" + margin.left + "," + (margin.top + hmHeight) + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("transform", "rotate(-45)");
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.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;

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