Compare commits

..

549 Commits

Author SHA1 Message Date
Maxime Beauchemin
1493650d0c 0.28.0rc3 2018-08-21 10:19:40 -07:00
Maxime Beauchemin
524a15372d 0.28.0rc3 2018-08-21 10:18:22 -07:00
Maxime Beauchemin
50042af25d [bug] 'an error has ooccured' when saving datasource (#5683)
The check_ownership was failing when Alpha user was saving a datasource
from the datasource editor.
2018-08-21 10:10:44 -07:00
hitdemo
5e5360fc11 make some text localizable, mainly in dashboard, explore, datasource editor, webpage title (#5685) 2018-08-21 10:10:09 -07:00
Sumedh Sakdeo
0fbda33c68 Handling bigquery dialect when previewing data (#5655)
* Handling bigquery dialect when previewing data

* review comments

* lint
2018-08-20 22:04:22 -07:00
Maxime Beauchemin
2d23ae1065 [bugfix] df is None breaks df.empty check (#5657) 2018-08-20 17:01:03 -07:00
Krist Wongsuphasawat
683edc377e Refactor Chord vis (#5671)
* refactor Chord vis

* Add PropTypes

* change module.exports to export default
2018-08-20 17:00:25 -07:00
Beto Dealmeida
fef39a7878 Fix time filter in cache (#5681) 2018-08-20 16:37:19 -07:00
Krist Wongsuphasawat
cdd348ab94 Minor improvements to SQL Lab UI (#5662)
* Remove "for"

* add space

* Separate control to select table from database and schema.

* Adjust schema displays

* Fix caret and arrow position in Select and Tab

* Reduce space after caret in tab header

* Use translator

* Align icons in the pop-up menu in Sql Lab

* Add new table in front of the list (so it will appear on top)

* shorten message

* reduce line
2018-08-19 22:43:00 -07:00
Beto Dealmeida
4c5142d969 Filter out null locations by default (#5642)
* Filter out null locations by default

* Move exception to better place

* Add unit test

* Return columns in order for test and readibility
2018-08-19 16:04:01 -07:00
Hugh A. Miles II
dd5e0ba70b Update CONTRIBUTING.md (#5668) 2018-08-19 15:42:09 -07:00
Chris Williams
3d15d910af [sqllab] call out transient state of tabs to users (#5652) 2018-08-17 17:44:56 -07:00
Maxime Beauchemin
0a1aa6dd50 [bugfix] TypeError: adhocMetric.comparator.join is not a function (#5661)
Somehow we have a "IN" filter where the filter is a string, not an
array. While this may need to get fixed upstream as well, this prevents
the explore view from completely crashing.

Side note: this function looked somewhat brittle, I'm assuming it's used to keep
the free form SQL tab in sync and not used to generate the actual SQL
being executed.
2018-08-17 15:53:04 -07:00
Yongjie Zhao
5a4b70dad7 Fix checkbox is fails When disable Druid datasource (#5645) 2018-08-16 23:54:27 -07:00
Junda Yang
97acfc7f17 fix multilayer viz backend error (#5649) 2018-08-16 23:52:39 -07:00
Sumedh Sakdeo
cc9324ae8b handle exception and set dtype value to JSON, when column type JSON (#5644)
* handle exception and set dtype value to JSON, when column type JSON

* review comment

* only when we handle exception
2018-08-16 20:04:08 -07:00
timifasubaa
4ff5686e0c make filters use security manager (#5567)
* make filters use security manager

* remove the superset short-circuit
2018-08-16 14:17:41 -07:00
michellethomas
32b3d00825 Updating yarn.lock for the vx upgrade (#5648) 2018-08-16 13:16:52 -07:00
michellethomas
2e0418034f Upgrading vx responsive to fix ResizeObserver issue (#5647) 2018-08-16 11:17:22 -07:00
michellethomas
492ad6c49a use_slice_data in slice_json calls (#5643) 2018-08-16 09:35:34 -07:00
Sumedh Sakdeo
5966a674e5 Explore View Perf Fix (#5637) 2018-08-15 12:27:08 -07:00
michellethomas
bf0afef7a9 Fix form data issue switching viz types (#5100)
* Fixing issue with extra params in formData

* Pass in param use_slice_data to decide whether to use slice data

* Fixing core_tests to not use explore_json overrides
2018-08-15 11:25:06 -07:00
John Bodley
4e3b2e7cbc [title] Fix issue with non-string names in series title (#5433) 2018-08-15 09:35:44 -07:00
Sumedh Sakdeo
c9bd5a6167 Fetch a batch of rows from bigquery (#5632)
* Fetch a batch of rows from bigquery

* unused const

* review comments
2018-08-14 21:44:04 -07:00
John Bodley
46f89f4516 [bubble] Fixing ad-hoc metric labels (#5630) 2018-08-14 17:11:40 -07:00
Maxime Beauchemin
d601ff4747 Tackling late-arriving comments from #5186 (#5626) 2018-08-14 16:30:50 -07:00
Maxime Beauchemin
be04c98cd3 [sql lab] always use NullPool (#5612)
I think that the only place where we want db connection pooling would be
to talk to the metadata database. SQL Lab should close its connections
and never pool them.
Given that each Gunicorn worker will create its own pool that can lead
to way too many connections opened.

closes https://github.com/apache/incubator-superset/issues/4666
2018-08-14 16:27:13 -07:00
Conglei
2171ffb630 [bug fix] Fixed forced percentage format on tooltips and bubble chart tooltips format. (#5631)
* fixed forced percentage format on tooltip and correct reflection on bubble chart tooltip format

* re-trigger build
2018-08-14 16:04:24 -07:00
Maxime Beauchemin
4c2be71e83 [bugfix] TIMESTAMP not detected as date (#5629)
* [bugfix] TIMESTAMP not detected as date

* minor tweak
2018-08-14 13:01:28 -07:00
Hugh A. Miles II
85a6da19ee Fix annotation_json endpoint (#5621)
* fix annotation_json endpoint

* add time back

* set db to None

* change if condition

* remove prop

* add guard for to_dttm

* linting
2018-08-14 11:40:14 -07:00
Grace Guo
9f6ac0898e [Dashobard]Fix bad merge (#5624) 2018-08-14 10:56:45 -07:00
Krist Wongsuphasawat
1d7f4f282e [bugfix] line_multi chart crashed on chosen (#5568) (#5572)
* Fix bug for line_multi

* refactor forEach to map

* reorder fields

* fix issue with datasource
2018-08-14 10:48:21 -07:00
Jillian Rowe
a39dfb9ff9 Add additional heatmap schemas (#5549)
* got skeleton started

* added d3-scale-chromatic to package.json

* got hex values instead of calling from a function

* got rid of d3-scale-chromatic - no longer needed

* added schemas to controls

* damn editor broken some line spacing

* commit

* fix style issues

* whyyyyy won't this build

* whyyyyy won't this build

* damn typo

* hahaha got editor to deal with style configs

* no i guess i didn't

* gotta get them all

* again

* trying to get docker build ot work

* updated installation docs with some osx instructions

* restoring yarn.lock not sure why it changed

* trying to fix indent

* trying again

* CODE STYLE CHANGES WORK

* removing some colors that are too close to white

* human readable labels for names

* human readable labels for names
2018-08-13 23:37:17 -07:00
Beto Dealmeida
763eeca75a No exception on no data (#5597)
* No exception on no data

* Remove unreachable exception
2018-08-13 22:33:29 -07:00
Beto Dealmeida
5c1d906976 Add option to run query with ctrl+enter (#5622) 2018-08-13 21:43:57 -07:00
Krist Wongsuphasawat
536478e96d [feature] Allow min/max value for the sparkline in time series table (#5603)
* Allow min/max value for the sparkline in time series table

* show bound lines

* User can choose to show y-axis bounds

* show label for the bounds

* compute necessary padding for the bound label

* extract sparkline code to another component

* can show y-axis in sparkline without setting bounds

* reorder option rows
2018-08-13 16:19:19 -07:00
John Bodley
e0c02be14e [dashboards] Increasing position_json to MEDIUMTEXT for MySQL (#5618) 2018-08-13 14:52:59 -07:00
John Bodley
2685ab4f1f [fix] Enforcing main dttm column (#5584) 2018-08-13 13:54:55 -07:00
hitdemo
50981dbc69 make some text localizable (#5611) 2018-08-12 20:47:55 -07:00
Narcissus7
7d61eea604 fix cal_heatmap tips location error (#5480) (#5587)
* fix cal_heatmap tips location error

* fix graph-legend
2018-08-12 20:44:54 -07:00
John Bodley
d1ef81f102 [ad-hoc filters] Fixing legacy conversion (#5589) 2018-08-10 10:22:06 -07:00
Maxime Beauchemin
f4aaad7945 Merge branch 'master' into 0.28 2018-08-09 14:49:31 -07:00
Maxime Beauchemin
682ca3874e [sql lab - explore flow] make sure groupby is empty (#5596) 2018-08-09 14:48:36 -07:00
Grace Guo
21bf8d9f8f [bug]Fix load_examples dashboard version key name (#5592) 2018-08-09 13:09:14 -07:00
Maxime Beauchemin
f4b45f07c3 [sql lab] visualization flow to detect unaliased columns (#5579)
* [sql lab] visualization flow to detect unaliased columns

* Addressing comments
2018-08-09 13:04:09 -07:00
Maxime Beauchemin
a8f4849911 [table editor] disable 'Sync table metadata' button for Superset views (#5580)
This was a bit tricky since there's a bug in react-bootstrap that make
it tricky to show a tooltip on a disabled button.
2018-08-09 10:53:25 -07:00
Beto Dealmeida
222b79df7e Template dashboard (#5550)
* Template dashboard

* Fix MySQL test

* Model for user attributes

* Redirect to welcome dash

* Fix lint

* Add missing file

* Add migration script

* Fix lint

* Fix more lint
2018-08-07 17:39:15 -07:00
Octavian
39ff9deb57 update python3 version for testing to 3.6 (#5562)
* update python version for testing to 3.6

* CONTRIBUTING.md states pull requests should work on py27, py36+

* CONTRIBUTING.md states pull requests should work on py27 and py36
2018-08-07 13:22:19 -07:00
Conglei
ad469c72ad Fixed the wrong icon for Source -> Table (#5574) 2018-08-06 17:27:48 -07:00
Krist Wongsuphasawat
39acd9ff7d remove deep-equal and use _.isEqual instead (#5573) 2018-08-06 17:26:06 -07:00
Maxime Beauchemin
05d4d8a70f 0.28.0rc1 2018-08-06 16:28:45 -07:00
Maxime Beauchemin
68ba63fcd9 Implement a React-based table editor (#5186)
* A React table editor

* addressing comments

* Fix SelectAsyncControl error on clear

* fix tests

* more corrections

* Removed <strong>
2018-08-06 15:30:13 -07:00
Krist Wongsuphasawat
aa14bac5c7 Add option for BigNumber to not start y-axis at 0 (#5552)
* Add option to not start y-axis at 0

* Update language to positive.
2018-08-06 14:32:29 -07:00
Maxime Beauchemin
b7f9dabc44 A collection of small bug fixes on master (#5561) 2018-08-06 08:36:06 -07:00
hitdemo
f5ad661441 remove uneccessary comma (#5564) 2018-08-04 09:20:01 -07:00
Maxime Beauchemin
89b7ca0623 Remove function since_until_to_time_range (#5560)
It's taken care of earlier in the pipeline with legacy.update_time_range
2018-08-03 15:34:03 -07:00
Maxime Beauchemin
9331cf79b5 [sql lab] allow EXPlAIN queries (#5558)
* [sql lab] allow EXPlAIN queries

closes https://github.com/andialbrecht/sqlparse/issues/421

* typo
2018-08-03 15:33:33 -07:00
Grace Guo
faf35b0daa convert position to v2 for Superset load_examples (#5515) 2018-08-03 15:28:12 -07:00
Maxime Beauchemin
51bd17d6f6 Improve URLs for Chart and Dashboard ModelViews (#5544)
* Improve URLs for Chart and Dashboard ModelViews

Prior to this, the ModelView for Chart and Dashboard would be
at `/slicemodelview/list/` and `/dashboardmodelview/list/`.

Now we have cleaner URLs at `/chart/list/` and `/dashboard/list/`

* Fix unrelated js lint

* addressing comments
2018-08-03 12:46:48 -07:00
timifasubaa
1e155663a7 permissions bug fixes (#5559) 2018-08-03 12:08:00 -07:00
Maxime Beauchemin
8014709b1a [bugfix] time filter on dashboard view (#5546)
Charts using the old since/until time filtering form_data format would
only work in the Explore view, not on the dashboard view. This fixes
that.
2018-08-03 11:29:34 -07:00
Grace Guo
2e2c9806b2 Reduce dashboard position_json data size (#5543) 2018-08-03 10:55:08 -07:00
Ville Brofeldt
e1f4db8e24 Match viz dataframe column case to form_data fields for Snowflake, Oracle and Redshift (#5487)
* Add function to fix dataframe column case

* Fix broken handle_nulls method

* Add case sensitivity option to dedup

* Refactor function definition and call location

* Remove added blank line

* Move df column rename logit to db_engine_spec

* Remove redundant variable

* Update comments in db_engine_specs

* Tie df adjustment to db_engine_spec class attribute

* Fix dedup error

* Linting

* Check for db_engine_spec attribute prior to adjustment

* Rename case sensitivity flag

* Linting

* Remove function that was moved to db_engine_specs

* Get metrics names from utils

* Remove double import and rename dedup variable
2018-08-03 09:53:56 -07:00
Jay Lindquist
aa9b30cf55 Re-add dashboard short links (#5398)
* Re-add dashboard short links

* Make the short link available to all users
* Include filters in the short link for dashboards

* Remove duplicate key causing linter error

* Change URL Short link button into a menu item with Modal

* Split out tests, bind URL short link in constructor
2018-08-03 09:22:39 -07:00
ekasitk
0aff8659d8 Add Thailand country map (#5554) 2018-08-03 08:15:38 -07:00
Krist Wongsuphasawat
9d95c4cc32 remove js packages that are not referenced in js code (#5514) 2018-08-02 11:45:58 -07:00
Nuno Beires
0786913fa6 Portuguese translation (#4874)
* Create message.po

* Add files via upload

* Update config.py

* Update config.py

* portuguese translation - messages.json

po2json

* Update message.po

* Add files via upload

* Add files via upload
2018-08-02 11:00:31 -07:00
Maxime Beauchemin
fe6846b8db [sql lab] simplify the visualize flow (#5523)
* [sql lab] simplify the visualize flow

The "visualize flow" linking SQL Lab to the "explore view" has never
worked so great for people, here's a list of issues:

* it's not really clear to users that their query is wrapped as a
subquery, and the explore view runs queries on top of it

* lint + fix tests

* Addressing comments
2018-08-02 10:52:38 -07:00
Krist Wongsuphasawat
1b9e5d4174 Update BigNumber design (#5469)
support toggling trend line

experiment using svg to measure size instead of canvas

refactor BigNumber with chart sticked to the bottom

made header line stick to bottom and css adjustment

remove commented code

fix svg text size estimation

remove unused code and round dimensions

handle missing getbbox

remove vx/text from dependency

ensure svg deletion after measurement

add comment to css file.

Add `positive` and `negative` class based on diff.

Add default props.

rename variable

accept container as argument and remove redundant font family

refactor visutils for consistent api

update xy-chart

update xy-chart to alpha1.0

fix pointseries

remove points

update yarn.lock

[4c9c01d7] update xy-chart version

remove unused import
2018-08-02 10:34:36 -07:00
Ville Brofeldt
906dcd84a9 Replace metadata refresh stacktrace with danger flash (#5536)
* Replace stacktrace with danger flash

* Group successful and failed refreshes and fix typos

* Fix linting
2018-08-01 23:10:47 -07:00
timifasubaa
4bf69a7260 fix superset error message flow (#5540) 2018-08-01 15:36:58 -07:00
Jeffrey Wang
1a9c4592dc Include README in MANIFEST (#5531) 2018-08-01 15:07:53 -07:00
JamshedRahman
9831730351 Annotation Styles for Time Series Annotations (#5437) 2018-08-01 11:54:03 -07:00
michellethomas
b564aa43dc Stop pretty printing dashboard json (#5538) 2018-08-01 11:26:02 -07:00
John Bodley
e52518c3cd [ad-hoc filters] Remove legacy split in /explore (#5533) 2018-08-01 09:21:15 -07:00
John Bodley
e7d05127d1 [get_df] Updating multi-statement logic (#5517) 2018-07-31 14:52:03 -07:00
michellethomas
8c822f1e9b Adding 364 days to time compare option (#5521) 2018-07-31 14:49:13 -07:00
John Bodley
47e3c41f5e [ad-hoc filters] Fixing issue with legacy filters (#5525) 2018-07-31 13:52:20 -07:00
Beto Dealmeida
2d8101b05f Fix time shift (#5529)
* Fix freeform multi select control

* Improve old code

* Fix lint
2018-07-31 13:26:06 -07:00
Ville Brofeldt
c1e6c68a3e Add time grain blacklist and addons to config.py (#5380)
* Add interim grains

* Refactor and add blacklist

* Change PT30M to PT0.5H

* Linting

* Linting

* Add time grain addons to config.py and refactor engine spec logic

* Remove redundant import and clean up config.py

* Fix bad rebase

* Implement changes proposed by @betodealmeida

* Revert removal of name from Grain

* Linting
2018-07-30 23:44:30 -07:00
The Alchemist
37c9b0b119 added clickhouse as supported db (#5522)
I believe clickhouse is supported now since #1844 was merged
2018-07-30 23:34:43 -07:00
timifasubaa
9e67445c68 hotfix - pass link not error message (#5512)
* hotfix - pass link not error message

* nit
2018-07-30 15:29:36 -07:00
Jeffrey Wang
b77d6e9cb1 Set max width for tooltips (#5504) 2018-07-30 11:03:42 -07:00
Vishal Jagtap
8fd8d73613 Fixed the issue of Zambia country map. (#5516)
- Previously after selecting option, got error "Uncaught TypeError: Cannot read property 'length' of undefined"
- Updated the appropriate geojson.
2018-07-30 09:15:32 -07:00
timifasubaa
3b6cafc82f allow security manager provide error message (#5500) 2018-07-27 14:39:25 -07:00
Grace Guo
daf21169ca set default layout for new added charts (#5425) 2018-07-27 11:59:32 -07:00
Vishal Jagtap
d373178451 Added India in country map visualizaion. (#5459)
- Added option to select "India".
- Added india.geojson upto state level.
2018-07-27 09:50:02 -07:00
mmuru
213fb649e6 Fix 5479 - unicode columns issue. (#5508) 2018-07-27 09:49:08 -07:00
Maxime Beauchemin
cd55998d63 Improve hive/pyhive error message regex (#5502) 2018-07-27 08:31:37 -07:00
Grace Guo
723bbe46e2 Remove dashboard transition related config (#5505) 2018-07-26 22:30:29 -07:00
Maxime Beauchemin
6f87552bc2 [sqllab] fix unexpected keyword argument 'ignore_nan' (#5490) 2018-07-26 15:20:48 -07:00
Maxime Beauchemin
94cb20cf96 Apply SQL_QUERY_MUTATOR to explore & dashboard (#5493)
* Apply SQL_QUERY_MUTATOR kn explore & dashboard

* Add unit test
2018-07-26 15:20:23 -07:00
Maxime Beauchemin
e22fcb9abf [sql lab] fix Hive 'Transport' not open issue (#5494) 2018-07-26 15:18:49 -07:00
Maxime Beauchemin
41286b7545 [sql lab] extract Hive error messages (#5495)
* [sql lab] extract Hive error messages

So pyhive returns an exception object with a stringified thrift error
object. This PR uses a regex to extract the errorMessage portion of that
string.

* Unit test
2018-07-26 15:17:55 -07:00
JamshedRahman
54fba0f39c Visualization Unicode bug fix (#5387)
* Visualization Unicode bug fix

* Fix the build (#5403)

The travis build has been failing for 2 reasons recently
* pylint takes > 10 minutes without outputing
* bad merge confict auto resolve in controls.jsx

* Visualization Unicode bug fix
2018-07-26 13:18:35 -07:00
Grace Guo
7ff02c0050 [migration] bug fix in dashboard migration (bebcf3fed1fe_) (#5497)
fix a bug in handle empty rows
2018-07-26 13:15:09 -07:00
Yoon
3df82d9da6 Modify Athena connection description (#5492) 2018-07-25 23:12:14 -07:00
Beto Dealmeida
dfb6147715 Remove is-react dep (#5478) 2018-07-25 11:02:50 -07:00
Grace Guo
3f2fc8f413 retire dashboard v1 (js and python) (#5418) 2018-07-24 15:23:30 -07:00
Grace Guo
fd2d4b0e58 Migrate dashboard positions data from v1 to v2 format (#5463)
* Migrate dashboard positions data from v1 to v2 format

* UPDATING.md

* rebase onto master
2018-07-24 15:14:11 -07:00
John Bodley
bfcc3a633b [migration] Fix migration 3dda56f1c (#5471) 2018-07-24 14:05:00 -07:00
timifasubaa
bea0a0aa15 fix migration 3dda56f1c (#5468)
* fix migration 3dda56f1c

* add isodate to setup.py:
2018-07-23 16:27:41 -07:00
Maxime Beauchemin
fee5023269 Move flake8-related packages deps to reqs-dev.txt (#5460)
* Move flake8-related packages deps to reqs-dev.txt

My VIM which is integrated with flake8 wouldn't match the output from
travis and would often miss things related to the flake8 plugins
installed using Tox.

By moving this to requirements-dev.txt, we can expect developers would
have the proper configuration locally and get matching results with
Travis when running flake8 or in their IDEs if its integrated with
flake8..

* merging migratinos

* sorting packages

* Specify folder for flake8 processing

* pin pycodestyle==2.3.1

* merge db migrations
2018-07-23 12:29:21 -07:00
Maxime Beauchemin
a11e47f694 Add row_limit control to line chart (#5426)
Somehow it's not possible to set the row_limit for a line chart,
resulting to a 10k cap in our environment. In some cases the user may
want more than that.
2018-07-23 11:54:12 -07:00
Ville Brofeldt
a165aec822 Fix broken dedup and remove redundant db_spec logic (#5467)
* Fix broken dedup and remove redundant db_spec logic

* Add test case
2018-07-23 10:41:38 -07:00
Maxime Beauchemin
971e9f0993 Fix the build by merging both db migrations heads (#5464) 2018-07-23 09:43:09 -07:00
John Bodley
7fcc2af68f [sql] Correct SQL parameter formatting (#5178) 2018-07-21 12:01:26 -07:00
Maxime Beauchemin
6e7b5879be Clarify title when importing a table (#5454)
The flow to import a table definition in Superset is confusing, user may
think they are creating a table or what not. This makes the flow a bit
more clear.
2018-07-21 10:39:41 -07:00
George
0d5443e392 Add week granularity for Clickhouse (#5455) 2018-07-21 09:53:21 -07:00
Andre Lesa
c545fdf589 Added Zambia geojson up to district level. (#5436) 2018-07-20 15:46:41 -07:00
gbates101
90decbc5db Migrated to click (#5410)
* Migrate flask_script to the Flask built-in click.

Flask 0.11 is the built-in integration of the click command line interface.
Flask-Migrate support for the new Flask CLI based on Click after Release 2.0.0.

* Resolved merge conflicts.

* Fixed issue introduced from bad merge.

* Fixed flake8 errors, added build to excluded flake8 stuff.

* * Moved the FlaskGroup declaration to the driver script.
* Moved shell context definition to cli.py
* Switched shell context definition to use decorator.
* Moved create_app definition to cli.py
* Fixed InvocationError with a wrapped function

* Added extra newlines between functions

* Removed flask-script dependency.
2018-07-20 15:26:33 -07:00
Ville Brofeldt
670b145b1e Add Snowflake connection string instructions (#5443) 2018-07-20 15:19:18 -07:00
Beto Dealmeida
83e1e2c0fe Time filter fixes (#5448)
* Fixes for the new time filter

* Fix dashboard

* Trigger tests
2018-07-20 15:15:33 -07:00
timifasubaa
41447e8b3b remove limiting at the display level (#5413) 2018-07-19 17:36:03 -07:00
Vishal Jagtap
6441f69271 Typo fixes in viz.py and CONTRIBUTING.md (#5432) 2018-07-19 16:45:56 -07:00
Maxime Beauchemin
99ce7b79fa Add pylint back as a tox env (#5416) 2018-07-18 15:55:01 -07:00
Maxime Beauchemin
5be0e69d1b Avoid expensive select_star on dashboard bootstrap data (#5424)
The dashboard page bootstrap data currently attempts to generate the
`SELECT` statement with column name details for each table represented
in the dash. This means it calls the database(s) and waits for column
details prior to returning any HTML.

This makes the default select_star property generate a simple
`SELECT *` with no column details instead, which doesn't require
interogating the DBs.
2018-07-18 15:54:47 -07:00
Vishal Jagtap
b0b04b319b Fixed typos in currently modified files (#5419) 2018-07-18 08:32:47 -07:00
timifasubaa
7f8eaee18d allow selection of dbs where csv can be uploaded to (#5393) 2018-07-17 15:38:16 -07:00
Maxime Beauchemin
73ec526913 Fix db migration 3dda56f1c4c6 (#5415) 2018-07-17 15:30:18 -07:00
Chris Williams
8b7aaec19d [webpack 4] third time's the charm ;) (#5370)
* [perf] add webpack 4 + SplitChunks + lazy load visualizations (#5240)

* [webpack] setup lazy loading for all visualizations

* [lazy-load] push renderVis function to <Chart /> state

* no mapbox token

* [lazy loading] use native webpack import func to fix chunk names, add babel-plugin-syntax-dynamic-import, fix rebase bug.

* fix geojson import, undefined t, and fix async css bug

* [lazy load] actually add babel-plugin-syntax-dynamic-import

* [webpack] working dev version of webpack v4

* [webpack 4] fix url issues, use mini-css-extract-plugin and webpack-assets-manifest plugins

* [webpack 4] use splitchunks for all files, update templates to multi-file entrypoints

* [webpack 4] multiple theme entry files for markup vis css, don't uglify mapbox

* [webpack 4] lint python manifest changes, update yarn lock.

* [webpack 4] fix tests with babel-plugin-dynamic-import-node

* [webpack 4] only use 'dynamic-import-node' plugin in tests, update <Chart /> vis promise when vis type changes

* [webpack 4] clean up package.json and yarn.lock after rebase

* [webpack 4] lint?

* [webpack 4] lint for real

* [webpack 4][istanbul] ignore visualizations/index.js

* [webpack 4] fix rebase bug, update dashboard/deprecated/chart/Chart.jsx to use vis promises.

* [webpack 4] lint and test

* [webpack 4] yarn.lock
2018-07-17 13:55:03 -07:00
Beto Dealmeida
75cf5e198f Fix time filter in dashboard v2 (#5412) 2018-07-17 13:38:33 -07:00
Chris Williams
7670e0c565 allow 7 tabs, remove 'slice_' prefix in logs (#5411) 2018-07-17 13:20:19 -07:00
Beto Dealmeida
7b4e6c7455 Time shift difference (#5177)
* Allow different comparisons when using time shift

* Remove test code

* Remove lead/trail NaN and improve code

* Add headers/subheader

* Update yarn

* Migration script

* Fix migration

* Small fixes

* Trigger tests

* Fix lint

* Fix javascript
2018-07-16 16:30:11 -07:00
timifasubaa
f8a6e09220 [sqllab] Fix sqllab limit regex issue with sqlparse (#5295)
* include items after limit to the modified query

* use sqlparse
2018-07-16 15:27:30 -07:00
Beto Dealmeida
c445ef8c43 Explore to SQL Lab (#5101)
* WIP

* Working version

* Clean code

* Fix lint

* Fix unit test; show only for sqla

* Working on UX

* Dropdown working 66%

* Working but needs CSS

* Fixed table

* Fix lint

* Fix unit test

* Fix languages path

* Fixes

* Fix Javascript lint
2018-07-16 15:00:48 -07:00
Maxime Beauchemin
48317fd8f9 [big_number] tooltip shows in the wrong place (#5404) 2018-07-16 14:59:14 -07:00
Beto Dealmeida
4fa416347d Make time filter more usable (#4981)
* Initial work

* WIP

* WIP

* Working

* WIP

* Still WIP

* Frontend done

* Working version

* Migration working

* Migration working

* Fix freeform rerender

* Remove jquery

* Fix filter

* Unit tests and lint

* Fix py.test

* Improve unit tests

* Ensure freeform is computed at init

* Fix lint

* Trying to fix pyfreeze error

* Remove freezegun

* Address comments

* Use tabs instead of pills

* Regroup options

* WIP

* Change type when clicking calendar

* Fix CSS

* Fix JS lint
2018-07-16 14:27:40 -07:00
Grace Guo
0d10cc569d [Table Viz] columns not match with group_by control (#5329) 2018-07-16 14:06:29 -07:00
Maxime Beauchemin
709f056445 [bugfix] make MetricsControl work with DECK visualizations (#5376)
* [bugfix] make MetricsControl work with DECK visualizations

* Add unit tests
2018-07-16 13:42:07 -07:00
Hugh A. Miles II
e79bb92a40 Add IS NOT NULL and IS NULL as filter options (#5375)
* wip

* disable value selector on IS NOT NULL or NOT NULL

* remove this
2018-07-16 13:29:55 -07:00
Maxime Beauchemin
996304aba9 Make Pypi upload support markdown (#5352)
Moving to using Twine to upload to pypi and fixing up the markdown
support so that the page on Pypi looks like the README on Github.

This has been tested on the 0.26 branch starting 0.26.3
2018-07-16 12:27:57 -07:00
Ville Brofeldt
bd475879a4 Fix display limit in sql lab (#5392)
* Fix display limit in sql lab

* Add redundant variable from config.py

* Fix test config

* Change to SQL_MAX_ROW

* Remove last remaining occurence of DISPLAY_SQL_MAX_ROW
2018-07-16 11:58:21 -07:00
Maxime Beauchemin
2eeff2ae0b Fix the build (#5403)
The travis build has been failing for 2 reasons recently
* pylint takes > 10 minutes without outputing
* bad merge confict auto resolve in controls.jsx
2018-07-16 11:46:13 -07:00
timifasubaa
22b7c2db62 quote hive column names (#5368) 2018-07-13 15:51:16 -07:00
Chris Williams
19ac6e1231 get rid of global notify (#5355)
* [toasts] get rid of notify globals, refactor messageToasts for use by entire app

* [remove notify] use arrow func in ajax call

* fix lint + tests

* actually fix tests from messageToast refactor

* add 'test:one' npm script

* debugger

* [toasts] convert bootstrap flash messages to toasts in explore + sqllab

* [toasts][tests] import from right file
2018-07-12 11:50:25 -07:00
Maxime Beauchemin
f9352af80e [pie] improvements to pie charts (#5236)
Pie chart was using `limit` instead of `row_limit` which didn't work.

Also set a lower default limit to 25 to prevent the chart from getting
super crowded.

Unrelated drive-by fix of setting "percentage metric" to default to `[]`
2018-07-12 10:33:11 -04:00
Maxime Beauchemin
0ca426a6fa Set control 'percent_metrics's default to [] (#5357) 2018-07-12 10:32:00 -04:00
JamshedRahman
cafde1536f Adding Druid Time Granularities (#5379)
* Adding Druid Time Granularities

* fixed a linter error
2018-07-12 10:19:50 -04:00
Hugh A. Miles II
cd2414b19e Set ignore NaN as true for TableViz (#5371)
* set ignore NaN as true for TableViz

* linting
2018-07-11 11:20:45 -04:00
Grace Guo
6b15592dd0 [dashboard] should use forceV2Edit property name (#5362) 2018-07-08 22:11:24 -07:00
Grace Guo
a17f7141b7 [dashboard] Fix save issue at Force_V2_Edit mode (#5360) 2018-07-06 20:52:56 -07:00
Maxime Beauchemin
7222c6f0f2 CHANGELOG entry for 0.25.0 to 0.26.0 (#5334) 2018-07-06 21:49:49 -04:00
timifasubaa
28ba5a9ddb use schema form field in upload csv (#5303) 2018-07-06 09:46:53 -07:00
John Bodley
c1187e0eaa [cache] Adding description for a zero cache timeout (#5354) 2018-07-06 09:24:21 -07:00
Yu Xiao
7158fb1e9d added a 'no_trend_line' option (#5356)
* added a 'no_trend_line' option

* added missing comma
2018-07-06 10:09:25 -04:00
aaronbannin
252cba20de impala support for epoch timestamps (#5349) 2018-07-04 19:25:58 -04:00
EvelynTurner
ad9103f5ba [Bug fix] Divide by 1000.000 in epoch_ms_to_dttm() to not lose precision in Presto (#5211)
* Fix how the annotation layer interpretes the timestamp string without timezone info; use it as UTC

* [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data

* [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data

* Fixed indentation

* Fix the key string value in case series.key is a string

* Fix the key string value in case series.key is a string

* [Bug fix] Divide by 1000.000 in epoch_ms_to_dttm() to not lose precision in Presto

* [Bug fix] Divide by 1000.000 in epoch_ms_to_dttm() to not lose precision in Presto
2018-07-04 19:19:57 -04:00
Ville Brofeldt
6fee0587ee Implement rolling api introduced in pandas 0.18 (#5328)
* Implement new rolling api introduced in pandas 0.18

* Bump pandas to 0.23.1

* Add 0.18 requirement in setup.py

* Require >=0.18.0, not just 0.18
2018-07-04 18:04:57 -04:00
Minh Mai
059b64dad7 normalize column names for Redshift (#5337) 2018-07-04 17:30:37 -04:00
Riccardo Magliocchetti
81bd5cc4c3 A couple of setup.py fixes (#5338)
* setup: fix long description read in python2

* setup: fix git_get_sha in python3

Fix #5317
2018-07-04 17:04:39 -04:00
Zachary Friedman
976e815a6e RST formatting fix for Installation docs (#5346) 2018-07-04 17:03:41 -04:00
Zachary Friedman
6f4a2e3505 Fix typo in Start with Docker (#5348) 2018-07-04 17:02:03 -04:00
John Bodley
72d815c0f9 [cache] Allowing zero cache-timeout (#5315) 2018-07-02 15:32:21 -07:00
Maxime Beauchemin
16d26336c4 Fix flaky unit test - remove 'Markup' object in data (#5313)
example of the failed test
https://travis-ci.org/apache/incubator-superset/jobs/397891630
2018-07-01 20:13:37 -07:00
Maxime Beauchemin
885d7791a0 [bugfix] README encoding-related UnicodeDecodeError on setup.py (#5309)
Seeing UnicodeDecodeError on our build system running py3.6, though I
couldn't reproduce on my local 3.6. This fix addresses the issue.
2018-07-01 08:57:14 -07:00
fly-high-bj
bfa9ffff3c Update core.py (#5320)
With Python 3.7.0, 'async' and 'await' become reserved words, which cause invalid syntax error when running core.py. Renamed 'async' var to 'async_'
2018-07-01 08:49:56 -07:00
Grace Guo
ad05700b6b [dashboard fix]Fix copy_dash unit test (#5323) 2018-07-01 08:47:57 -07:00
Hugh A. Miles II
089037f1aa [DeckGL] Raise error with null values (#5302)
* raise errors with null values

* linting

* linting some more

* use get

* change ordering

* linting
2018-06-30 16:07:23 -07:00
Kshira Saagar
df5ce50e80 Adding THE ICONIC to the list (#5305)
Adding THE ICONIC to list of companies using Superset. Big fans of Superset and use it for all our operational reporting!
2018-06-28 09:58:56 -07:00
Maxime Beauchemin
777d876a52 Improve database type inference (#4724)
* Improve database type inference

Python's DBAPI isn't super clear and homogeneous on the
cursor.description specification, and this PR attempts to improve
inferring the datatypes returned in the cursor.

This work started around Presto's TIMESTAMP type being mishandled as
string as the database driver (pyhive) returns it as a string. The work
here fixes this bug and does a better job at inferring MySQL and Presto types.
It also creates a new method in db_engine_specs allowing for other
databases engines to implement and become more precise on type-inference
as needed.

* Fixing tests

* Adressing comments

* Using infer_objects

* Removing faulty line

* Addressing PrestoSpec redundant method comment

* Fix rebase issue

* Fix tests
2018-06-27 21:35:12 -07:00
Chris Williams
04fc1d1089 [dashboard v2] add MissingChart component in the case that chart component has no slice definition, add tests. (#5296) 2018-06-27 11:20:10 -07:00
Grace Guo
17b4298401 [dashobard fix]: fix validation check for default_filters (#5297) 2018-06-27 11:00:50 -07:00
John Bodley
117507cf31 [get_df] Fix datetime conversion (#5274) 2018-06-27 09:09:42 -07:00
Jeffrey Wang
fb988fee2e Pin boto3 to 1.4.7 (#5290) 2018-06-27 08:55:47 -07:00
Grace Guo
4ee984c6de [dashboard fix] force refresh charts under tabs (#5291) 2018-06-26 17:46:28 -07:00
Chris Williams
05a39b395a fix sqllab <Loading /> css, fix double AddSliceCard margin and drag border (#5293)
* fix sqllab <Loading /> css, fix double AddSliceCard margin and drag border

* [dashboard v2] improve cached visual indicator, add last fetched messaging

* [dashboard v2] fix ctrl + cmd + z + UndoRedoKeylisteners
2018-06-26 16:47:41 -07:00
timifasubaa
b0eee129e9 add more precise types to hive table from csv (#5267) 2018-06-25 16:12:01 -07:00
timifasubaa
bd24f854c9 specify hve namespace for tables (#5268) 2018-06-25 12:04:27 -07:00
Chris Williams
c065319508 [wip] dashboard builder v2 (#4528)
* [dashboard builder] Add dir structure for dashboard/v2, simplified Header, split pane, Draggable side panel

[grid] add <DashboardGrid />, <ResizableContainer />, and initial grid components.

[grid] gridComponents/ directory, add fixtures/ directory and test layout, add <Column />

[grid] working grid with gutters

[grid] design tweaks and polish, add <Tabs />

[header] add gradient header logo and favicon

[dnd] begin adding dnd functionality

[dnd] add util/isValidChild.js

[react-beautiful-dnd] iterate on dnd until blocked

[dnd] refactor to use react-dnd

[react-dnd] refactor to use composable <DashboardComponent /> structure

[dnd] factor out DashboardComponent, let components render dropInidcator and set draggableRef, add draggable tabs

[dnd] refactor to use redux, add DashboardComponent and DashboardGrid containers

[dragdroppable] rename horizontal/vertical => row/column

[builder] refactor into HoverMenu, add WithPopoverMenu

[builder] add editable header and disableDragDrop prop for Dragdroppable's

[builder] make tabs editable

[builder] add generic popover dropdown and header row style editability

[builder] add hover rowStyle dropdown, make row styles editable

[builder] add some new component icons, add popover with delete to charts

[builder] add preview icons, add popover menu to rows.

[builder] add IconButton and RowStyleDropdown

[resizable] use ResizableContainer instead of DimensionProvider, fix resize and delete bugs

[builder] fix bug with spacer

[builder] clean up, header.size => header.headerSize

[builder] support more drag/drop combinations by wrapping some components in rows upon drop. fix within list drop index. refactor some utils.

[builder][tabs] fix broken add tab button

[dashboard builder] don't pass dashboard layout to all dashboard components, improve drop indicator logic, fix delete component pure component bug

[dnd] refactor drop position logic

* fix rebase error, clean up css organization and use @less vars

* [dashboard-builder] add top-level tabs + undo-redo (#4626)

* [top-level-tabs] initial working version of top-level tabs

* [top-level-tabs] simplify redux and disable ability to displace top-level tabs with other tabs

* [top-level-tabs] improve tab drag and drop css

* [undo-redo] add redux undo redo

* [dnd] clean up dropResult shape, add new component source id + type, use css for drop indicator instead of styles and fix tab indicators.

* [top-level-tabs] add 'Collapse tab content' to delete tabs button

* [dnd] add depth validation to drag and drop logic

* [dashboard-builder] add resize action, enforce minimum width of columns, column children inherit column size when necessary, meta.rowStyle => meta.background, add background to columns

* [dashboard-builder] make sure getChildWidth returns a number

* [dashboard builder] static layout + toasts (#4763)

* [dashboard-builder] remove spacer component

* [dashboard-builder] better transparent indicator, better grid gutter logic, no dragging top-level tabs, headers are multiples of grid unit, fix row height granularity, update redux state key dashboard => dashboardLayout

* [dashboard-builder] don't blast column child dimensions on resize

* [dashboard-builder] ResizableContainer min size can't be smaller than size, fix row style, role=none on WithPopoverMenu container

* [edit mode] add edit mode to redux and propogate to all <DashboardComponent />s

* [toasts] add Toast component, ToastPresenter container and component, and toast redux actions + reducers

* [dashboard-builder] add info toast when dropResult overflows parent

* [dashboard builder] git mv to src/ post-rebase

* Dashboard builder rebased + linted (#4849)

* define dashboard redux state

* update dashboard state reducer

* dashboard layout converter + grid render

* builder pane + slice adder

* Dashboard header + slice header controls

* fix linting

* 2nd code review comments

* [dashboard builder] improve perf (#4855)

* address major perf + css issues

[dashboard builder] fix dashboard filters and some css

[dashboard builder] use VIZ_TYPES, move stricter .eslintrc to dashboard/, more css fixes

[builder] delete GridCell and GridLayout, remove some unused css. fix broken tabs.

* [builder] fix errors post-rebase

* [builder] add support for custom DragDroppable drag layer and add AddSliceDragPreview

* [AddSliceDragPreview] fix type check

* [dashboard builder] add prettier and update all files

* [dashboard builder] merge v2/ directory int dashboard/

* [dashboard builder] move component/*Container => containers/*

* add sticky tabs + sidepane, better tabs perf, better container hierarchy, better chart header (#4893)

* dashboard header, slice header UI improvement

* add slider and sticky

* dashboard header, slice header UI improvement

* make builder pane floating

* [dashboard builder] add sticky top-level tabs, refactor for performant tabs

* [dashboard builder] visually distinct containers, icons for undo-redo, fix some isValidChild bugs

* [dashboard builder] better undo redo <> save changes state, notify upon reaching undo limit

* [dashboard builder] hook up edit + create component actions to saved-state pop.

* [dashboard builder] visual refinement, refactor Dashboard header content and updates into layout for undo-redo, refactor save dashboard modal to use toasts instead of notify.

* [dashboard builder] refactor chart name update logic to use layout for undo redo, save slice name changes on dashboard save

* add slider and sticky

* [dashboard builder] fix layout converter slice_id + chartId type casting, don't change grid size upon edit (perf)

* [dashboard builder] don't set version key in getInitialState

* [dashboard builder] make top level tabs addition/removal undoable, fix double sticky tabs + side panel.

* [dashboard builder] fix sticky tabs offset bug

* [dashboard builder] fix drag preview width, css polish, fix rebase issue

* [dashboard builder] fix side pane labels and hove z-index

* Markdown for dashboard (#4962)

* fix dashboard server-side unit tests (#5009)

* Dashboard save button (#4979)

* save button

* fix slices list height

* save custom css

* merge save-dash changes from dashboard v1
https://github.com/apache/incubator-superset/pull/4900
https://github.com/apache/incubator-superset/pull/5051

* [dashboard v2] check for default_filters before json_loads-ing them (#5064)

[dashboard v2] check for default_filters before json-loads-ing them

* [dashboard v2] fix bugs from rebase

* [dashboard v2] tests! (#5066)

* [dashboard v2][tests] add tests for newComponentFactory, isValidChild, dropOverflowsParent, and dnd-reorder

* [dashboard v2][tests] add tests for componentIsResizable, findParentId, getChartIdsFromLayout, newEntitiesFromDrop, and getDropPosition

* [dashboard v2][tests] add mockStore, mockState, and tests for DragDroppable, DashboardBuilder, DashboardGrid, ToastPresenter, and Toast

* [dashboard builder][tests] separate files for state tree fixtures, add ChartHolder, Chart, Divider, Header, Row tests and WithDragDropContext helper

* [dashboard v2][tests] fix dragdrop context with util/getDragDropManager, add test for menu/* and resizable/*, and new components

* [dashboard v2][tests] fix and re-write Dashboard tests, add getFormDataWithExtraFilters_spec

* [dashboard v2][tests] add reducer tests, fix lint error

* [dashboard-v2][tests] add actions/dashboardLayout_spec

* [dashboard v2] fix some prop bugs, open side pane on edit, fix slice name bug

* [dashboard v2] fix slice name save bug

* [dashboard v2] fix lint errors

* [dashboard v2] fix filters bug and add test

* [dashboard v2] fix getFormDataWithExtraFilters_spec

* [dashboard v2] logging updates (#5087)

* [dashboard v2] initial logging refactor

* [dashboard v2] clean up logger

* [logger] update explore with new log events, add refresh dashboard + refresh dashboard chart actions

* [logging] add logger_spec.js, fix reducers/dashboardState_spec + gridComponents/Chart_spec

* [dashboard v2][logging] refactor for bulk logging in python

* [logging] tweak python, fix and remove dup start_offset entries

* [dashboard v2][logging] add dashboard_first_load event

* [dashboard v2][logging] add slice_ids to dashboard pane load event

* [tests] fix npm test script

* Fix: update slices list when add/remove multiple slices (#5138)

* [dashboard v2] add v1 switch (#5126)

* [dashboard] copy all dashboard v1 into working v1 switch

* [dashboard] add functional v1 <> v2 switch with messaging

* [dashboard] add v2 logging to v1 dashboard, add read-v2-changes link, add client logging to track v1 <> v2 switches

* [dashboard] Remove default values for feedback url + v2 auto convert date

* [dashboard v2] fix misc UI/UX issues

* [dashboard v2] fix Markdown persistance issues and css, fix copy dash title, don't enforce shallow hovering with drop indicator

* [dashboard v2] improve non-shallow drop target UX, fix Markdown drop indicator, clarify slice adder filter/sort

* [dashboard v2] delete empty rows on drag or delete events that leave them without children, add test

* [dashboard v2] improve v1<>v2 switch modals, add convert to v2 badge in v1, fix unsaved changes issue in preview mode, don't auto convert column child widths for now

* [dashboard v2][dnd] add drop position cache to fix non-shallow drops

* [dashboard] fix test script with glob instead of recurse, fix tests, add temp fix for tab nesting, ignore v1 lint errors

* [dashboard] v2 badge style tweaks, add back v1 _set_dash_metadata for v1 editing

* [dashboard] fix python linting and tests

* [dashboard] lint tests

* add slice from explore view (#5141)

* Fix dashboard position row data (#5131)

* add slice_name to markdown

(cherry picked from commit 14b01f1)

* set min grid width be 1 column

* remove empty column

* check total columns count <= 12

* scan position data and fix rows

* fix dashboard url with default_filters

* [dashboard v2]  better grid drop ux, fix tab bugs 🐛 (#5151)

* [dashboard v2] add empty droptarget to dashboard grid for better ux and update test

* [dashboard] reset tab index upon top-level tab deletion, fix findparentid bug

* [dashboard] update v1<>v2 modal link for tracking

* Fix: Should pass slice_can_edit flag down (#5159)

* [dash builder fix] combine markdown and slice name, slice picker height (#5165)

* combine markdown code and markdown slice name

* allow dynamic height for slice picker cell

* add word break for long datasource name

* [fix] new dashboard state (#5213)

* [dashboard v2] ui + ux fixes (#5208)

* [dashboard v2] use <Loading /> throughout, small loading gif, improve row/column visual hierarchy, add cached data pop

* [dashboard v2] lots of polish

* [dashboard v2] remove markdown padding on edit, more opaque slice drag preview, unsavedChanges=true upon moving a component, fix initial load logging.

* [dashboard v2] gray loading.gif, sticky header, undo/redo keyboard shortcuts, fix move component saved changes update, v0 double scrollbar fix

* [dashboard v2] move UndoRedoKeylisteners into Header, render only in edit mode, show visual feedback for keyboard shortcut, hide hover menu in top-level tabs

* [dashboard v2] fix grid + sidepane height issues

* [dashboard v2] add auto-resize functionality, update tests. cache findParentId results.

* [dashboard v2][tests] add getDetailedComponentWidth_spec.js

* [dashboard v2] fix lint

* [fix] layout converter fix (#5218)

* [fix] layout converter fix

* add changed_on into initial sliceEntity data

* add unit tests for SliceAdder component

* remove old fixtures file

* [dashboard v2] remove webpack-cli, fresh yarn.lock post-rebase

* [dashboard v2] lint javascript

* [dashboard v2] fix python tests

* [Fix] import/export dash in V2 (#5273)

* [dashboard v2] add markdown tests (#5275)

* [dashboard v2] add Markdown tests

* [dashboard v2][mocks] fix markdown mock
2018-06-25 09:17:22 -07:00
John Bodley
ca5cc672ca [metric] Fixing ad-hoc metric for dual-line chart (#5271) 2018-06-22 14:31:43 -07:00
John Bodley
7de50238a4 [druid] Adding verbose_name to editable columns (#5249) 2018-06-21 22:15:06 -07:00
Hugh A. Miles II
d4672dbfb7 make sure there is a val to be set for existing filters (#5257) 2018-06-21 22:00:50 -07:00
Maxime Beauchemin
e1618ddddb Fix edge case around NaN values (#4964) 2018-06-21 18:10:04 -07:00
Maxime Beauchemin
b344056932 [bugfix] add support for numeric nodes in Sankey (#5154)
* [bugfix] add support for numeric nodes in Sankey

closes https://github.com/apache/incubator-superset/issues/5142

* lint
2018-06-21 18:09:08 -07:00
Maxime Beauchemin
5a716e9925 [bugfix] get word_cloud to support complex metrics (#5248) 2018-06-21 18:04:56 -07:00
Gabe Lyons
2f274328ed fixing regex displaying as undefined in the pill (#5266) 2018-06-21 18:01:31 -07:00
Maxime Beauchemin
73295f25a3 Bump pydruid to 0.4.4 (#5262) 2018-06-21 17:42:44 -07:00
timifasubaa
0e5293b9be Update db_engine_specs.py (#5264) 2018-06-21 16:01:34 -07:00
Chris Williams
15c8e5bfa9 [timeseries table] use verbose date in tooltip by default (#5263) 2018-06-21 13:34:49 -07:00
michellethomas
eb676519ba Moving homogenize_types to after no data exception (#5214) 2018-06-20 17:31:23 -07:00
Grace Guo
13cbf80fb3 [Explore] Handle empty metrics control data (#5241) 2018-06-20 12:41:48 -07:00
Maxime Beauchemin
409ac6824a [sql lab] Fix issue around VARBINARY type in Presto (#5121)
When receiving a VARBINARY field out of Presto, it shows up as type
`bytes` out of the pyhive driver. Then the pre 3.15 version of
simplejson attempts to convert it to utf8 by default and it craps out.

I bumped to simplejson>=3.25.0 and set `encoding=None` as documented
here
https://simplejson.readthedocs.io/en/latest/#basic-usage so that we can
handle bytes on our own.
2018-06-20 12:16:59 -07:00
Jeffrey Wang
2a3d297950 Allow users to view dashboards they own (#4520)
* Allow owners to view their own dashboards

* Update docstring

* update sm variable

* Add unit test

* misc linter
2018-06-20 12:08:16 -07:00
John Bodley
62427c8b8d Revert "[perf] add webpack 4 + SplitChunks + lazy load visualizations" (#5253)
* Revert "[sqllab] Fix sql lab resolution link (#5216)"

This reverts commit 93cdf60920.

* Revert "Pin botocore version (#5184)"

This reverts commit 70679d4c93.

* Revert "Describe the use of custom OAuth2 authorization servers (#5220)"

This reverts commit a84f4304de.

* Revert "[bubble-chart] Fixing issue w/ metric names (#5237)"

This reverts commit 5c106b9a20.

* Revert "[adhoc-filters] Adding adhoc-filters to all viz types (#5206)"

This reverts commit d483ed121c.

* Revert "[perf] add webpack 4 + SplitChunks + lazy load visualizations (#5240)"

This reverts commit 1fc4ee0d3c.
2018-06-20 12:07:42 -07:00
timifasubaa
93cdf60920 [sqllab] Fix sql lab resolution link (#5216)
* pass link

* update frontend to show link differently

* nits
2018-06-19 20:33:24 -07:00
Louis-Etienne
70679d4c93 Pin botocore version (#5184)
* Pin botocore version

* Version range for botocore
2018-06-19 08:49:51 -07:00
Ricardo Peironcely
a84f4304de Describe the use of custom OAuth2 authorization servers (#5220)
As Superset extends flask SecurityManager with its own implementation, it's not obvious how to connect Superset with OAuth2 authorization servers that are not covered under flask.
2018-06-19 08:48:48 -07:00
John Bodley
5c106b9a20 [bubble-chart] Fixing issue w/ metric names (#5237) 2018-06-18 15:50:49 -07:00
John Bodley
d483ed121c [adhoc-filters] Adding adhoc-filters to all viz types (#5206) 2018-06-18 15:43:18 -07:00
Chris Williams
1fc4ee0d3c [perf] add webpack 4 + SplitChunks + lazy load visualizations (#5240)
* [webpack] setup lazy loading for all visualizations

* [lazy-load] push renderVis function to <Chart /> state

* no mapbox token

* [lazy loading] use native webpack import func to fix chunk names, add babel-plugin-syntax-dynamic-import, fix rebase bug.

* fix geojson import, undefined t, and fix async css bug

* [lazy load] actually add babel-plugin-syntax-dynamic-import

* [webpack] working dev version of webpack v4

* [webpack 4] fix url issues, use mini-css-extract-plugin and webpack-assets-manifest plugins

* [webpack 4] use splitchunks for all files, update templates to multi-file entrypoints

* [webpack 4] multiple theme entry files for markup vis css, don't uglify mapbox

* [webpack 4] lint python manifest changes, update yarn lock.

* [webpack 4] fix tests with babel-plugin-dynamic-import-node

* [webpack 4] only use 'dynamic-import-node' plugin in tests, update <Chart /> vis promise when vis type changes

* [webpack 4] clean up package.json and yarn.lock after rebase

* [webpack 4] lint?

* [webpack 4] lint for real

* [webpack 4][istanbul] ignore visualizations/index.js
2018-06-18 15:28:13 -07:00
Grace Guo
480ddfc7ad [CRUD] disable user change slices from dashboardmodelview (#5217) 2018-06-18 15:08:03 -07:00
John Bodley
d7d5327ef7 [CRUD] Improving performance by disabling editing Associated Chart] (#5238) 2018-06-18 14:33:13 -07:00
Grace Guo
0509d7aefd [Explore] Enable Rich tooltip by default (#5215) 2018-06-18 10:45:31 -07:00
Riccardo Magliocchetti
c670621012 setup: improve description (#5226)
* setup: improve description

* setup: use README.md as long_description

As pypy.io now should render markdown.
2018-06-18 08:42:48 -07:00
Maxime Beauchemin
c89933d870 [sql lab] quote schema and table name (#5195)
fixes https://github.com/apache/incubator-superset/issues/4595
2018-06-18 08:42:08 -07:00
Ville Brofeldt
ccf211036d Bump Celery to 4.2.0 (#5222)
* Downgrade celery and kombu

* Remove kombu from requirements.txt

* Pin kombu at 4.1.0

* Bump celery to 4.2.0
2018-06-18 08:19:07 -07:00
Riccardo Magliocchetti
00fad1cbf9 README: update Maieutical Labs url (#5227) 2018-06-18 08:14:12 -07:00
Chris Williams
7b49b6c2de Revert "[webpack] setup lazy loading for all visualizations" (#5219)
* Revert "[explore] fix autocomplete on verbose names (#5204)"

This reverts commit d5ebc430c2.

* Revert "[webpack] setup lazy loading for all visualizations (#4727)"

This reverts commit de0aaf42ed.
2018-06-15 17:23:57 -07:00
Maxime Beauchemin
d5ebc430c2 [explore] fix autocomplete on verbose names (#5204)
* [explore] fix autocomplete on verbose names

Currently when searching for metrics or groupbys, the autocomplete
search functionality only matches based on the metric_name, though in
some cases the verbose_name is displayed and disregarded for search
purposes.

Also another issue is that not all pre-defined metrics show up in the
drop down which is confusing. Users may have simple metrics for which
they setup a nice verbose name and/or description and expect to see
those in the dropdown.

This PR addresses it for metric and column-related dropdowns.

* Add unit test
2018-06-15 15:56:05 -07:00
Chris Williams
de0aaf42ed [webpack] setup lazy loading for all visualizations (#4727)
* [webpack] setup lazy loading for all visualizations

* [lazy-load] push renderVis function to <Chart /> state

* no mapbox token

* [lazy loading] use native webpack import func to fix chunk names, add babel-plugin-syntax-dynamic-import, fix rebase bug.

* fix geojson import, undefined t, and fix async css bug

* [lazy load] actually add babel-plugin-syntax-dynamic-import

* [webpack] working dev version of webpack v4

* [webpack 4] fix url issues, use mini-css-extract-plugin and webpack-assets-manifest plugins

* [webpack 4] use splitchunks for all files, update templates to multi-file entrypoints

* [webpack 4] multiple theme entry files for markup vis css, don't uglify mapbox

* [webpack 4] lint python manifest changes, update yarn lock.

* [webpack 4] fix tests with babel-plugin-dynamic-import-node

* [webpack 4] only use 'dynamic-import-node' plugin in tests, update <Chart /> vis promise when vis type changes

* [webpack 4] clean up package.json and yarn.lock after rebase

* [webpack 4] lint?

* [webpack 4] lint for real
2018-06-14 18:29:05 -07:00
John Bodley
8cdc9cad9c [pie-chart] Restricting query to single metric (#5203) 2018-06-14 18:14:13 -07:00
michellethomas
b60ac5f160 Fixing issue with table viz for table with no metrics (#5205) 2018-06-14 17:15:00 -07:00
timifasubaa
4b7a14de77 Merge pull request #5194 from timifasubaa/pass_error_link_separately
pass error message separately
2018-06-14 12:01:45 -07:00
Timi Fasubaa
7fa5559a66 remove resolution link prop 2018-06-14 11:32:50 -07:00
timifasubaa
66ffcb665a Merge pull request #5118 from michellethomas/add_metrics_control_sort_by
Adding the MetricsControl to the timeseries_limit_metric field
2018-06-14 10:38:32 -07:00
Grace Guo
585dbe6638 fix Formula type annotation, it doesn't show up since #4630 (#5181) 2018-06-14 10:12:29 -07:00
Maxime Beauchemin
a1095437bc Introduce class attr BaseViz.enforce_numerical_metrics (#5176) 2018-06-13 22:45:03 -07:00
Maxime Beauchemin
30111bf3fd Repoint .istambul.yml to the right location (#5187)
Never did this when I renamed the folder. `npm run cover` currently
doesn't generate a proper coverage report, this fixes it
2018-06-13 22:22:39 -07:00
Timi Fasubaa
7a107fac62 pass_error_message_separately 2018-06-13 21:43:48 -07:00
timifasubaa
6e37d3f882 Merge pull request #5190 from timifasubaa/fix_null_metrics
[bugfix] form_data - fix empty metrics
2018-06-13 17:53:42 -07:00
Michelle Thomas
b380a57c91 Fixing sortby adhoc metrics for table viz 2018-06-13 17:51:17 -07:00
Timi Fasubaa
95bb1753ab fix empty metrics 2018-06-13 14:13:05 -07:00
michellethomas
d6846d96ff Adding column only if it doesn't already exist (#5179) 2018-06-13 11:49:43 -07:00
Yuance.Li
7f30b48955 fetch datasources from broker endpoint when refresh new datasources (#5183)
* fetch datasources from broker endpoint when refresh new datasources

* remove get_base_coordinator_url as out of use

* add broker_endpoint in get_test_cluster_obj
2018-06-13 08:10:58 -07:00
John Bodley
502b617310 [migrations] Cleaning up migration logic (#5167) 2018-06-12 12:10:53 -07:00
John Bodley
52a933ffb8 [migrations] Cleanup recent migrations (#5155) 2018-06-12 12:10:41 -07:00
michellethomas
280200f834 Fixing tooltip displaying metrics in heatmap (#5055) 2018-06-11 17:14:02 -07:00
Tresdon Jones
3de79b69d0 Fix bullet chart rendering (#5108)
* Fix bullet chart rendering

* Fix code style errors
2018-06-11 16:40:29 -07:00
Maxime Beauchemin
a3477abf7e Pin FAB and bump a bunch of JS libs (#5122) 2018-06-10 21:43:37 -07:00
Xiao Hanyu
0a276ff75d Init docker for local development environment. (#4193)
This commit will try to dockerize superset in local development
environment.

The basic design is:
- Enable superset, redis and postgres service instead of using sqlite,
  just want to simulate production environment settings
- Use environment variables to config various app settings. It's easy to
  run and config superset to any environment if we use environment than
  traditional config files
- For local development environment, we just expose postgres and redis
  to local host machine thus you can connect local port via `psql` or
  `redis-cli`
- Wrap start up command in a standard `docker-entrypoint.sh`, and use
  `tail -f /dev/null` combined with manually `superset runserver -d` to
  make sure that code error didn't cause the container to fail.
- Use volumes to share code between host and container, thus you can use
  your favourite tools to modify code and your code will run in
  containerized environment
- Use volumes to persistent postgres and redis data, and also
  `node_modules` data.
  - If we don't cache `node_modules` in docker volume, then every time
    run docker build, the `node_modules` directory, will is about 500 MB
    large, will be sent to docker daemon, and make the build quite slow.
- Wrap initialization commands to a single script `docker-init.sh`

After this dockerize setup, any developers who want to contribute to
superset, just follow three easy steps:

```
git clone https://github.com/apache/incubator-superset/
cd incubator-superset
cp contrib/docker/{docker-build.sh,docker-compose.yml,docker-entrypoint.sh,docker-init.sh,Dockerfile} .
cp contrib/docker/superset_config.py superset/
bash -x docker-build.sh
docker-compose up -d
docker-compose exec superset bash
bash docker-init.sh
```
2018-06-09 21:26:41 -07:00
John Bodley
7d1c035658 [druid] Fixing Druid version check (#5028) 2018-06-08 16:55:15 -07:00
Maxime Beauchemin
915e6e9d40 Restore translations as of 459cb701fb (#5156) 2018-06-08 14:05:50 -07:00
Gabe Lyons
b53b240710 [Explore][Adhoc Metrics/ Filters] disabled message for custom sql tab in druid (#5162)
* added disabled message for custom sql tab on druid datasources

* Update AdhocFilterEditPopover.jsx

Fixing indentation.

* Update AdhocMetricEditPopover.jsx

Fixing indent.

* Update AdhocFilterEditPopover.jsx

Fixing indentation.

* Update AdhocMetricEditPopover.jsx

Fixing indentation.
2018-06-07 16:16:46 -07:00
John Bodley
1b4406db3f [migration] Adding migration to remove empty in/not-in filters (#5161) 2018-06-07 15:48:53 -07:00
Gabe Lyons
5b35f75cbf empty lists are invalid comparators (#5160) 2018-06-07 15:02:43 -07:00
Beto Dealmeida
57e125688f Improve time shift (#5140)
* Improve time shift color and pattern

* Revert change

* Fix js unit test

* Move code to better place, add unit test

* Move classed code to backend

* Remove console.log

* Remove 1 hour time compare

* Remove unused import
2018-06-06 20:40:55 -07:00
John Bodley
0545d11a22 [migrations] Fix time grain SQLA (#5135) 2018-06-06 16:56:39 -07:00
timifasubaa
0abbc98630 pin kombu dependency (#5150) 2018-06-06 14:29:08 -07:00
John Bodley
f102eab33c [crud] Improving performance (#5136) 2018-06-05 17:24:19 -07:00
Xiao Hanyu
b71f551493 Optimize presto SQL Lab query performance. (#5132)
By stop polling when presto query already finished.

When user make queries to Presto via SQL Lab, presto will run the query
and then it can return all data back to superset in one shot.

However, the default implementation of superset has enabled a default
polling for presto to:

- Get the fancy progress bar
- Get the data back when the query finished.

However, the polling implementation of superset is not right.

I've done a profiling with a table of 1 billion rows, here're some data:

- Total number of rows: 1.02 Billion
- SQL Lab query limit: 1 million
- Output Data: 1.5 GB
- Superset memory consumed: about 10-20 GB
- Time: 7 minutes to finish in Presto, takes additional 15 minutes for
  superset to get and store data.

The problems with default issue is, even if presto has finished the
query (7 minutes with above profiling), superset still do lots of wasted
polling, in above profiling, superset sent about 540 polling in total,
and at half of the polling is not necessary.

Part of the simplied polling response:

```
{
  "infoUri": "http://10.65.204.39:8000/query.html?20180525_042715_03742_nza9u",
  "id": "20180525_042715_03742_nza9u",
  "nextUri": "http://10.65.204.39:8000/v1/statement/20180525_042715_03742_nza9u/11",
  "stats": {
    "state": "FINISHED",
    "queuedSplits": 21701,
    "progressPercentage": 35.98264191882267,
    "elapsedTimeMillis": 1029,
    "nodes": 116,
    "completedSplits": 15257,
    "scheduled": true,
    "wallTimeMillis": 2571904,
    "peakMemoryBytes": 0,
    "processedBytes": 40825519532,
    "processedRows": 47734066,
    "queuedTimeMillis": 0,
    "queued": false,
    "cpuTimeMillis": 849228,
    "rootStage": {
      "state": "FINISHED",
      "queuedSplits": 0,
      "nodes": 1,
      "totalSplits": 17,
      "processedBytes": 16829644,
      "processedRows": 11495,
      "completedSplits": 17,
      "stageId": "0",
      "done": true,
      "cpuTimeMillis": 69,
      "subStages": [
        {
          "state": "CANCELED",
          "queuedSplits": 21701,
          "nodes": 116,
          "totalSplits": 42384,
          "processedBytes": 40825519532,
          "processedRows": 47734066,
          "completedSplits": 15240,
          "stageId": "1",
          "done": true,
          "cpuTimeMillis": 849159,
          "subStages": [],
          "wallTimeMillis": 2570374,
          "userTimeMillis": 730020,
          "runningSplits": 5443
        }
      ],
      "wallTimeMillis": 1530,
      "userTimeMillis": 50,
      "runningSplits": 0
    },
    "totalSplits": 42401,
    "userTimeMillis": 730070,
    "runningSplits": 5443
  }
  }
}
```

Superset will terminate the polling when it finds that `nextUri`
becomes none, but actually, when `["stats"]["state"] == "FINISHED"`,
it means that presto has already finished the query and superset can stop
polling and get the data back.

After this simple optimization, we get a 2-5x performance boost for
Presto SQL Lab queries.
2018-06-05 08:56:18 -07:00
Maxime Beauchemin
d2bc4ece3e Bump celery to 4.1.1 (#5134)
* Bump celery to 4.1.1

Docs reference `celery worker --app=superset.sql_lab:celery_app
--pool=gevent -Ofair` command which seems only to work with Celery 4.1.1

* Add UPDATING.md message
2018-06-04 14:54:36 -07:00
Maxime Beauchemin
ffd65ce623 Pin FAB to 1.10.0 (#5133)
Related to
https://github.com/apache/incubator-superset/issues/5088#issuecomment-394064133
2018-06-04 09:03:30 -07:00
Tamika Tannis
dc21e0dd78 URL shortner for dashboards (#4760)
* Added support for URLShortLinkButton to work for the dashboard case

* Fix lint errors and test

* Change references to 'slice' to 'chart'.

* Add unit tests to improve coverage

* Fixing lint errors

* Refactor to make URLShortLink more generic. Remove history modification code, redirect should be handling this.

* Remove history modification code, redirect should be handling this

* Generate a shorter link without the directory, and delegate default linked to the contents of window.location

* Fix lint errors

* Fix test_shortner test to check for new pattern

* Remove usage of addHistory to manipulate explore shortlink redirection

* Address build failure and using better practices for shortlink defaults

* Fixing alphabetical order

* More syntax mistakes

* Revert explore view history changes

* Fix use of component props, & rebase
2018-06-02 11:08:43 -07:00
Michelle Thomas
47768284d0 Adding tests for adhoc metric as timeseries_limit_metric 2018-05-31 23:48:12 -07:00
Gabe Lyons
cc0942ac98 updating adhoc metric filtering (#5105) 2018-05-31 23:34:48 -07:00
Ky-Anh Huynh
556ef44fac docs: Add new Athena URI scheme awsathena+rest:// (#5112)
See also some discussions on https://github.com/laughingman7743/PyAthenaJDBC/pull/62
2018-05-31 22:19:07 -07:00
Beto Dealmeida
1d3e96bce0 Allow multiple time shifts (#5067)
* Allow multiple time shifts

* Handle old form data
2018-05-31 21:18:36 -07:00
Gabe Lyons
40fadfcb4f adding null checks to adhoc filter popover (#5111) 2018-05-31 21:00:20 -07:00
Maxime Beauchemin
28611108d7 Refactor NULL handling into method, disable for DECK.gl vizes (#5106) 2018-05-31 16:01:49 -07:00
michellethomas
ff4b103025 Fixing time table viz for adhoc metrics (#5117) 2018-05-31 13:53:26 -07:00
Michelle Thomas
6f05b48385 Adding the MetricsControl to the timeseries_limit_metric field 2018-05-31 12:52:00 -07:00
Maxime Beauchemin
4ecd95a318 [bugfix] deck.gl on druid always shows animation (#5107) 2018-05-31 11:57:53 -07:00
Gabe Lyons
f3778c3c81 fixing LIKE constant name (#5110) 2018-05-31 11:34:51 -07:00
timifasubaa
cefc206a36 Merge pull request #5023 from timifasubaa/fix_sqllab_commit
[sqllab] force limit queries only when there is no existing limit
2018-05-31 11:12:46 -07:00
Beto Dealmeida
875d0b5ad2 Override time grain in annotations (#5084) 2018-05-30 15:29:48 -07:00
timifasubaa
e8b25988e2 Merge pull request #5109 from cxmcc/patch-1
Add Lime to Superset user list.
2018-05-30 15:17:16 -07:00
Xiuming Chen
21967f40e7 Add Lime to Superset user list.
Add Lime to Superset user list.
2018-05-30 14:24:03 -07:00
Timi Fasubaa
a9d7fafd9f add tests 2018-05-30 12:50:27 -07:00
Maxime Beauchemin
f6117973e9 Bump dep on pydruid to 0.4.3 (#5098) 2018-05-30 09:15:10 -07:00
John Bodley
0511d1f38d [get_df] Adding support for multi-statement SQL (#5086) 2018-05-29 14:20:17 -07:00
谢邵虎
7dbb45e5fb add CnOvit to Superset users list (#5094) 2018-05-29 13:59:49 -07:00
Beto Dealmeida
6c3e469154 Add more time grains (#5083)
* Add more time grains

* Use FLOOR

* Fix quotes for lint
2018-05-29 12:43:48 -07:00
Maciej Bryński
ae50845843 Proper error handling in Hive Queries (#4428)
* Proper error handling in Hive Queries

* Change quotes

* Trigger checks

* Adding call to parent class

* Small fix

* Fix in method call
2018-05-29 12:42:45 -07:00
zjj
459267785f Fix python2 str() in visualization (#5093) 2018-05-29 10:33:22 -07:00
Timi Fasubaa
d38315a307 reuse_regex_logic 2018-05-25 15:07:27 -07:00
Timi Fasubaa
1aced9b562 force limit only when there is no existing limit 2018-05-25 14:54:11 -07:00
Yongjie Zhao
c18ef89034 [bugfix] fix visualization with adhocMetric (#5080)
* fix visualization with adhocMetric

* update
2018-05-25 09:48:18 -07:00
Alexander Ko
e30215c3d8 Add 24 hours refresh for dashboard (#5068)
* adding 24 hours refresh

* adding additional hours
2018-05-24 17:44:24 -07:00
Maxime Beauchemin
42d0597b90 Use a dummy version number on master (#5000)
Currently we assign release version number in release branches and
master was still pointing to some old version number from when the
process was different. We need a dummy version number that both setuptools
and npm are ok with.
2018-05-24 17:42:46 -07:00
John Bodley
3207116535 Revert "[get_df] Adding support for multi-statement SQL" (#5078) 2018-05-24 14:59:34 -07:00
michellethomas
1aaa73b548 Translate string to array for multi fields in getControlsState (#5057)
* Translate string to array for multi fields in getControlsState

* Updating format to fit on one line
2018-05-23 22:30:44 -07:00
Maxime Beauchemin
05061a73ce Fix time shift color assignements (#5065)
closes https://github.com/apache/incubator-superset/pull/4765
2018-05-23 21:30:03 -07:00
John Bodley
d322e48c57 [markup] Enable allow-forms (#5062) 2018-05-23 13:30:02 -07:00
Gabe Lyons
fa3e4e23b3 integrating dashboard filters with adhoc filters (#5056) 2018-05-23 11:46:00 -07:00
John Bodley
17d6464aa9 [get_df] Adding support for multi-statement SQL (#5060) 2018-05-23 11:40:25 -07:00
Grace Guo
4c44223234 [Dashboard] Allow Superset Alpha, Gamma users to save dashboard as a copy (#5051) 2018-05-22 15:31:37 -07:00
michellethomas
b8aeb1a825 Allow MetricsControl to aggregate on a column with an expression (#5021)
* Allow MetricsControl to aggregate on a column with an expression

* Adding test case for metrics based on columns
2018-05-22 09:58:38 -07:00
Hua Jigang
b312cdad2f fix metrics type error in pivot table viz (#5025)
transfer metrics dict label to list of string
2018-05-21 21:13:10 -07:00
Beto Dealmeida
973c661501 Rename "slice" to "chart" and update translations (#5008)
* Rename slice to chart and update translations

* Fix unit tests
2018-05-21 17:49:02 -07:00
Beto Dealmeida
459cb701fb Visualization for multiple line charts (#4819)
* Initial test

* Save

* Working version

* Use since/until from payload

* Option to prefix metric name

* Rename LineMultiLayer to MultiLineViz

* Add more styles

* Explicit nulls

* Add more x controls

* Refactor to reuse nvd3_vis

* Fix x ticks

* Fix spacing

* Fix for druid datasource

* Rename file

* Small fixes and cleanup

* Fix margins

* Add proper thumbnails

* Align yaxis1 and yaxis2 ticks

* Improve code

* Trigger tests

* Move file

* Small fixes plus example

* Fix unit test

* Remove SQL and Filter sections
2018-05-21 17:47:21 -07:00
Gabe Lyons
a746fce383 expanding simple tab (#5032) 2018-05-21 16:22:40 -07:00
Gabe Lyons
0e1fb62db2 forcing ace editor to refresh when it is shown (#5038) 2018-05-21 16:20:46 -07:00
Maxime Beauchemin
ce0011e5fc Add missing dep on contextlib2 (#5027) 2018-05-21 13:19:07 -07:00
Gabe Lyons
1c9474b4ff treating floats like doubles for druid versions lower than 11.0.0 (#5030) 2018-05-21 11:50:04 -07:00
Yongjie Zhao
9f66dae328 [bugfix] Fix ZeroDivisionError and get metrics label with percent metrics (#5026)
* Fix percent_metrics ZeroDivisionError and can not get metrics with label issue

* convert iterator to list

* get percentage metrics with get_metric_label method

* Adding tests case for expression type metrics

* Simplify expression
2018-05-20 11:10:57 -05:00
timifasubaa
5505c116ba Merge pull request #5019 from timifasubaa/fix_error_message_for_missing_datasource
fix missing datasource error message
2018-05-18 01:13:47 -07:00
timifasubaa
63115fbb87 nit 2018-05-17 23:34:12 -07:00
Timi Fasubaa
f52f7aa7cf raise exception early 2018-05-17 17:39:59 -07:00
timifasubaa
5a64b3f577 Merge pull request #5022 from mistercrunch/flask_sub_1
Fix flask<1.0.0
2018-05-16 18:26:27 -07:00
Maxime Beauchemin
2ba929ac9e Fix flask<1.0.0
Made a mistake originally, meant to flask<1.0.0
2018-05-16 18:37:14 -05:00
Arup Malakar
2bf53dad98 Make port number optional in superset for druid (#5020)
* Make port number optional in superset for druid

It appears that urllib throws error with ssl if port number is provided

```
    url = "https://example.com:443/druid/v2"

    req = urllib.request.Request(url, druid_query_str, headers)
    res = urllib.request.urlopen(req)

```

The above call fails with the following error:
```
urllib2.HTTPError: HTTP Error 404: Not Found
```

If url is set to https://example.com/druid/v2 it works, this change
makes the port number optional.

* Rewrite if/else in concisely python way
2018-05-16 17:38:00 -04:00
Timi Fasubaa
cf374efb3f fix missing datasource error message 2018-05-16 12:32:31 -07:00
Maxime Beauchemin
e72c9cded3 Fix EncryptedType error (#5007)
fixes https://github.com/apache/incubator-superset/issues/5005
2018-05-16 13:24:51 -05:00
michellethomas
c2eae96327 Fix AdhocFilterControl for single metric options (#5012) 2018-05-15 16:41:23 -07:00
Maxime Beauchemin
7b427d7ee0 Make MetricsControl the standard across visualizations (#4914)
* [WiP] make MetricsControl the standard across visualizations

This spreads MetricsControl across visualizations.

* Addressing comments

* Fix deepcopy issue using shallow copy

* Fix tests
2018-05-15 12:37:34 -05:00
Maxime Beauchemin
b839608c32 [sql lab] a better approach at limiting queries (#4947)
* [sql lab] a better approach at limiting queries

Currently there are two mechanisms that we use to enforce the row
limiting constraints, depending on the database engine:
1. use dbapi's `cursor.fetchmany()`
2. wrap the SQL into a limiting subquery

Method 1 isn't great as it can result in the database server storing
larger than required result sets in memory expecting another fetch
command while we know we don't need that.

Method 2 has a positive side of working with all database engines,
whether they use LIMIT, ROWNUM, TOP or whatever else since sqlalchemy
does the work as specified for the dialect. On the downside though
the query optimizer might not be able to optimize this as much as an
approach that doesn't use a subquery.

Since most modern DBs use the LIMIT syntax, this adds a regex approach
to modify the query and force a LIMIT clause without using a subquery
for the database that support this syntax and uses method 2 for all
others.

* Fixing build

* Fix lint

* Added more tests

* Fix tests
2018-05-14 14:44:05 -05:00
Yongjie Zhao
7a4a89b195 Update Apache Kylin dbengine with supported week/quarter grains (#4965) 2018-05-14 14:11:59 -05:00
Gabe Lyons
ce710f8c8f cleaning up the table fab view since we hide these autogenerated metrics anyway (#4992) 2018-05-14 14:09:12 -05:00
Ville Brofeldt
b391676544 Force lowercase column names for Snowflake and Oracle (#4994)
* Force lowercase column names for Snowflake and Oracle

* Force lowercase column names for Snowflake and Oracle

* Remove lowercasing of DB2 columns

* Remove DB2 lowercasing

* Fix test cases
2018-05-14 13:43:13 -05:00
timifasubaa
071c6a6c03 Merge pull request #4991 from michellethomas/fix_filter_blank_custom_sql
[Bugfix] Allowing sqlExpression to be blank
2018-05-14 11:26:08 -07:00
Maxime Beauchemin
2c5200affd [deps] force flask<=1.0.0 (#4959)
flask 1.0 came out and has backwards incompatible changes. People
are reporting that fresh install doesn't work anymore.

fixes https://github.com/apache/incubator-superset/issues/4953

We should ship a 0.25.1 with this in
2018-05-13 11:16:09 -07:00
Michelle Thomas
ad4912d601 Allowing sqlExpression to be blank 2018-05-11 16:03:17 -07:00
Gabe Lyons
7d5195aae3 expanding regex for automated columns (#4990) 2018-05-11 15:43:52 -07:00
timifasubaa
b75942daa5 Merge pull request #4977 from timifasubaa/bump_pyhive_version
bump pyhive version
2018-05-10 11:50:14 -07:00
Timi Fasubaa
6720255868 bump pyhive version 2018-05-10 11:13:44 -07:00
Gabe Lyons
a8514b267b [Explore] Adding Adhoc Filters (#4909)
* adding custom expressions to adhoc metrics

* adjusted transitions and made the box expandable

* adding adhoc filters

* adjusted based on feedback
2018-05-10 10:41:10 -07:00
grafke
8591319bde [sql lab] Use context manager for sqllab sessions (#4927)
* use session context manager

* contextlib2 added to requirements.txt

* Fixing error: Import statements are in the wrong order. from contextlib2 import contextmanager should be before import sqlalchemy

* Fixing return inside generator

* fixed C812 missing trailing comma

* E501 line too long

* fixed E127 continuation line over-indented for visual indent

* E722 do not use bare except

* reorganized imports

* added context manager contextlib2.contextmanager

* fixed import ordering
2018-05-10 10:32:31 -07:00
Ville Brofeldt
af4dd59661 Fix templating in sqla datasource (#4971)
Fix templating in sqla datasource [has migration]
2018-05-10 10:28:56 -07:00
Nicole Dominguez
94249ed20c superset/import_dashboards.html: Update title, clean up html (#4972)
* Changes "Import the dashboards." to "Import dashboards"
* Cleans up the HTML to add quotes, self close tags, etc.
* Adds a class to the `<submit>` button to utilize bootstrap style
* Remove the `<title>` tag in body as it's not vaild HTML and redundant with `{% block %}`
2018-05-09 20:42:17 -07:00
Maxime Beauchemin
918399d4e2 [bugfix] handling UTF8 in Druid dimensions (#4943) 2018-05-08 22:04:05 -07:00
jasnovak
e29beba023 Add extraction function support for Druid queries (#4740)
* add extraction fn support for Druid queries

* bump pydruid version to get extraction fn commits

* update and add tests for druid for filters with extraction fns

* conform to flake8 rules

* fix flake8 issues

* bump pyruid version for extraction function features
2018-05-08 22:00:06 -07:00
Maxime Beauchemin
75df3d0f8e CHANGELOG for 0.25.0 (#4948) 2018-05-08 08:24:54 -07:00
Yuance.Li
18e67f93de add 30 minutes support under time granularity (#4954) 2018-05-08 08:24:18 -07:00
Yuance.Li
65c4499bef Support hours in relative time range selection (#4950) 2018-05-07 23:19:08 -07:00
Maxime Beauchemin
45ffed9976 Move from deprecated flask-cache to flask-caching (#4944)
It appears the officially maintained fork of flask-cache is
flask-caching https://github.com/sh4nks/flask-caching . It is fully
compatible with flask-cache.
2018-05-07 23:18:46 -07:00
Hugh A. Miles II
374482bcde Fix naming for geojson (#4946) 2018-05-07 22:48:35 -07:00
Maxime Beauchemin
f21ba1aba7 [docs] add entry for Hive in installation.rst (#4942) 2018-05-07 15:26:19 -07:00
Maxime Beauchemin
415d1c092b [sql lab] handle query stop race condition (#4928)
fixes https://github.com/apache/incubator-superset/issues/4926

In rare cases where the query is stopped before it is started, SQL Lab
returns an unexpected string payload instead of a normal dictionary.

This aligns the process to handle the error in a homogeneous fashion.
2018-05-07 13:49:42 -07:00
Vihar Kurama
a60d577b7d Update installation.rst (#4930) 2018-05-07 13:48:41 -07:00
timifasubaa
d87504cb42 Merge pull request #4833 from timifasubaa/help_sqllab_forget_the_past
[sqllab] Help sqllab forget query history
2018-05-07 10:56:39 -07:00
Timi Fasubaa
ab958c67e6 make queries older than 6 hours timeout 2018-05-07 10:14:37 -07:00
João Marques Gomes
89333657d8 Add Portugal to country_map visualization (#4939)
* Add files via upload

* Add files via upload
2018-05-07 10:01:09 -07:00
Antoine Galataud
f5b63679e0 add Airboxlab to Superset users list (#4938) 2018-05-07 09:59:35 -07:00
Octavian
58a02bba43 Add Windsor.ai to the list of organizations (#4940) 2018-05-07 09:59:02 -07:00
Hugh A. Miles II
52a6bd1c7e rm-slices (#4899) 2018-05-05 00:05:49 +02:00
John Bodley
440fb77df5 [druid] Updating Druid refresh metadata tests (#4887) 2018-05-03 18:14:40 -07:00
jasnovak
e2d5c33638 Hide restricted ui elements, remove <br> from error message (#4900)
* hide forbidden ui elements, remove <br> from message

* add comma for flake8

* add commma for flake8

* change js variables from snake to camel case
2018-05-03 17:36:30 -07:00
Casper CY Chiang
976e43e681 Install superset in Kubernetes with helm chart (#4923)
* Add helm chart to install superset in kubernetes

* set resources into unlimited

* Add descriptions to Chart.yaml

* add an entry in docs/installation.rst
2018-05-03 17:35:38 -07:00
Yongjie Zhao
5d6e59aa8a Support Apache Kylin in EngineSpec (#4925)
* Support Apache Kylin in EngineSpec

* Fix flake8
2018-05-03 08:42:43 -07:00
Maxime Beauchemin
e213ccd438 [bufix] filtered column was removed (#4921)
if a filter is created on a chart, and the column is removed from the
dataset, you get a "&#39;NoneType&#39; object has no attribute
&#39;is_num&#39;" or something to that
effect. This fix disregards the filter.

Also error messages were HTML escaped which React does already anyways
so that's not necessary [anymore] here.
2018-05-02 15:24:44 -07:00
Maxime Beauchemin
fa4acb1bda Add doc entry for BigQuery support (#4917)
closes https://github.com/apache/incubator-superset/issues/945
2018-05-01 21:28:27 -07:00
Maxime Beauchemin
5f6a1cea47 Fix typos from linting (#4918)
Caused by https://github.com/apache/incubator-superset/pull/3847

Fixes https://github.com/apache/incubator-superset/issues/4915
2018-05-01 13:34:10 -07:00
Beto Dealmeida
13da5a8742 Fix for week_start_sunday and week_ending_saturday (#4911)
* Handle locked weeks

* Fix spelling

* Fix druid

* Clean unit tests
2018-05-01 13:27:56 -07:00
Beto Dealmeida
9c53323c93 Replace NaN/Infinity with null (#4908) 2018-05-01 11:18:19 -07:00
Maxime Beauchemin
8c94e1f710 Fix country_map visualization URL (#4913)
When moving the visualizations/ folder to src/ I missed this reference.
2018-05-01 08:50:47 -07:00
Maxime Beauchemin
e1d2150391 Add note about 0.25.0 upgrade in UPDATING.md (#4883) 2018-04-30 09:47:48 -07:00
Maxime Beauchemin
3c7feb770a Heatmap improvements (#4897)
* allow option to normalize the color distribution
* make bounds work client side (instantaneous)
* make more controls instantaneous
2018-04-30 09:36:24 -07:00
Riccardo Magliocchetti
709a71b89a requirements: bump gunicorn to 19.8.0 (#4906)
Fixes #3002
2018-04-30 08:58:02 -07:00
Riccardo Magliocchetti
31f426664c translations: rename pt_BR gettext files (#4907)
To messages.{mo,po} like for the other languages.
2018-04-30 08:57:26 -07:00
John Bodley
d533ce0967 [pylint] prepping for enabling pylint for non-errors (#4884) 2018-04-28 20:08:09 -07:00
Maxime Beauchemin
caa72675a5 Fix 'Uncaught TypeError: pe.clamp is not a function' (#4901) 2018-04-27 16:15:43 -07:00
Maxime Beauchemin
0a953714ac [sql lab] allow stoping 'pending' queries (#4896) 2018-04-27 16:10:29 -07:00
Jules
510ae84b3b remove hard code http scheme of short url #4656 (#4886)
* remove hard code http scheme of short url #4656

* remove space

* add space

* remove temp var
2018-04-27 08:41:54 -07:00
Maxime Beauchemin
f3d756016e Allow limiting rows on Pivot Table (#4891) 2018-04-27 08:35:12 -07:00
Maxime Beauchemin
3f48c005df [bugfix] temporal columns with expression fail (#4890)
* [bugfix] temporal columns with expression fail

error msg: "local variable 'literal' referenced before assignment"

Error occurs [only] when using temporal column defined as a SQL
expression.

Also noticed that examples were using `granularity` instead of using
`granularity_sqla` as they should. Fixed that here.

* Add tests
2018-04-26 21:13:52 -07:00
Ville Brofeldt
fa3da8c888 Implement Snowflake engine with supported time grains (#4882)
* Implement Snowflake engine with supported time grains

* Fix typo in second grain
2018-04-25 14:44:24 -07:00
Maxime Beauchemin
17ae9ec3a8 Move a few JS files (#4841)
* Moving JS files

* Moving pointers

* lint
2018-04-24 13:35:55 -07:00
david watson
7139f1e863 Remove spurious "has" from README (#4872)
This changes "has ships" to "ships" so it's grammatically correct. Sorry for the pedantic PR.
2018-04-24 09:44:42 -07:00
Chris Hua
7193a4719d remove DISTINCT ON statement (#4869)
unbreaks for redshift tables and output is identical
2018-04-23 17:04:36 -07:00
Conglei
2cd016f11c [axis formatting] Override the valueformat to be percentage when contribution is selected (#4866)
* force the valueformat to be percentage when contribution is selected

* remove extra empty lines

* simplied the logic by reusing some existing code
2018-04-23 10:05:29 -07:00
Hugh A. Miles II
5927e7dfe6 Refactoring on exploreReducer.js (#4836)
* refactoring on exploreReducser

* fix building json
2018-04-23 08:29:01 -07:00
Maxime Beauchemin
590e3462d6 Fix 'pip install .' (#4856)
* Fix 'pip install .'

Fix error :
> flask-appbuilder 1.10.0 has requirement Flask-SQLAlchemy==2.1,
> but you'll have flask-sqlalchemy 2.3.2 which is incompatible.
> botocore 1.10.5 has requirement python-dateutil<2.7.0,>=2.1, but you'll
> have python-dateutil 2.7.2 which is incompatible.

* remove flask-sqlalchemy==2.1 from reqs.txt
2018-04-23 08:16:22 -07:00
michellethomas
370d8a2bbe Safely passing data to d3.html (#4842) 2018-04-22 21:00:37 -07:00
Ry Walker
937a5bc85c Add Astronomer to list of organizations using Apache Superset (#4867) 2018-04-22 20:51:45 -07:00
Chris Williams
66fcf9b687 [formats] add better defaults for time + number formatting (#4843)
* [formats] add better defaults for time + number formatting

* [formatDate] add tests for concise formatDate

* [nvd3] use verbose time format in tooltips

* [number format] improve number format description

* [formats] revert to .3s defaults, tweak number format preview

* [formats] default number vis to .3s
2018-04-20 15:55:25 -07:00
John Bodley
89347172d2 [sql] Using read_sql_query instead of read_sql (#4853) 2018-04-20 14:36:20 -07:00
Peter Lubell-Doughtie
c92b56e2f6 correct config language key to pt_BR (#4854) 2018-04-19 20:43:56 -07:00
Maxime Beauchemin
e88b0b6c4c Remove obsolete TODO.md (#4850) 2018-04-19 15:52:26 -07:00
Kengo Seki
860a4d9123 [docs] minor file name and format fix for the setup document (#4844) 2018-04-19 11:34:23 -07:00
Maxime Beauchemin
a98c3cfdef Fix time granularity-related issues (#4821)
* Fixing time grain

* Add tests
2018-04-18 16:17:28 -07:00
timifasubaa
a14dc26042 ensure directory exists before saving csv file (#4829) 2018-04-18 15:01:40 -07:00
Timi Fasubaa
e47d8a59a4 help sqllab forget the past 2018-04-18 14:09:33 -07:00
Maxime Beauchemin
eac97ce9f2 [explore] proper filtering of NULLs and '' (#4651)
* [WiP] [explore] proper filtering of NULLs and ''

TODO: handling of Druid equivalents

* Unit tests

* Some refactoring

* [druid] fix 'Unorderable types' when col has nuls

Error "unorderable types: str() < int()" occurs when grouping by a
numerical Druid colummn that contains null values.

* druid/pydruid returns strings in the datafram with NAs for nulls
* Superset has custom logic around get_fillna_for_col that fills in the
NULLs based on declared column type (FLOAT here), so now we have a mixed
bag of type in the series
* pandas chokes on pivot_table or groupby operations as it cannot sorts
mixed types

The approach here is to stringify and fillna('<NULL>') to get a
consistent series.

* typo

* Fix druid_func tests

* Addressing more comments

* last touches
2018-04-17 22:26:21 -07:00
John Bodley
44c2d5bdab [setup] Dropping 3.4 and adding 3.6 (#4835)
* [setup] Dropping 3.4 and 3.6

* Update tox.ini

* Update .travis.yml
2018-04-17 21:30:12 -07:00
Maxime Beauchemin
c0db6dbb57 Moving some JS folders (#4820)
* Moving folders

* Pointing to new locations
2018-04-17 21:05:01 -07:00
John Bodley
2900ca345d [travis] Fixing environments (#4828) 2018-04-15 16:21:33 -07:00
Riccardo Magliocchetti
3b18fbf9e3 db_engine_specs: use correct sqlite week time grain (#4831)
We want the week of year %W and not the day of week %w
when using week as time grain.

Reference:
https://www.sqlite.org/lang_datefunc.html
2018-04-15 16:15:31 -07:00
Maxime Beauchemin
23a3365cd1 Update README with fresher screenshots (#4825)
* Improve screenshots in README.md

* Add border to images

* Add visualizations.png
2018-04-14 15:32:26 -07:00
Gabe Lyons
8669874ec6 [Explore] Adding custom expressions to adhoc metrics (#4736)
* adding custom expressions to adhoc metrics

* adjusted transitions and made the box expandable
2018-04-13 11:20:53 -07:00
Maxime Beauchemin
4c268ec678 [docs] many improvements to the documentation / cleanup (#4817)
* fixed RSTs so images will show up on github
* fresh screenshots on main page
* removing irrelevant portions
* moved a set of sections under 'Misc'
* rebuilt the Gallery with all screenshots
2018-04-13 10:23:27 -07:00
Riccardo Magliocchetti
daf9a3bfb5 docs: use proper dialect for redshift (#4823)
Use redshift+psycopg2 instead of the postgresql one.
2018-04-13 09:13:33 -07:00
Beto Dealmeida
fd84fd89ce RFC: add logger that logs into browser console (#4702)
* Option for logging into browser console

* Move import

* Add lint req

* Add docs, use Flask logger
2018-04-12 21:48:17 -07:00
Hugh A. Miles II
2f5cff7d9f [DeckGL] Added fixtures and Deck test (#4798)
* added fixtures and deck test

* linting

* linting

* add os.path

* remove para

* fix reference
2018-04-12 17:20:39 -07:00
Maxime Beauchemin
6fd4ff45ea Improve the calendar heatmap (#4800)
* Improve xAxis ticks, thinner bottom margin (#4756)

* Improve xAxis ticks, thinner bottom margin

* Moving utils folder

* Add isTruthy

* Addressing comments

* Set cell_padding to 0

* merging db migrations
2018-04-12 17:16:45 -07:00
Maxime Beauchemin
b04359003e Filtering out SQLLab views out of table list view by default (#4746)
* Filtering out SQLLab views out of table list view by default

This adds a `is_sqllab_view` flag in the "tables" table, and makes the
filters those out in the Tables list view.

The filter showing on top may be a bit confusing, but certainly less
than seeing lots of user generated views.

* flake

* Addressing comments
2018-04-12 13:52:47 -07:00
John Bodley
2a95d203ad [migrations] Fixing issue #4810 (#4815) 2018-04-12 10:41:36 -07:00
Maxime Beauchemin
683fb6c251 Make the bottom margin a bit taller (#4807) 2018-04-11 15:15:59 -07:00
Maxime Beauchemin
07a5f47c75 [bugfix] dedup groupby columns in Deck visualizations (#4801)
When specifying the same column twice as a `Extra Data for JS` and
`Categorical Color`, an error is issued. This addresses this issue.
2018-04-11 15:15:36 -07:00
Maxime Beauchemin
ae7e114621 [explore] set working default for MetricsControl (#4803)
The default setting which would look for either `count` first and then
any metric stopped working when we landed MetricsControl. This mimics
the previous behavior
2018-04-11 15:11:11 -07:00
John Bodley
dadc0574b8 [tests] cleaning up test configuration (#4806) 2018-04-11 14:09:20 -07:00
michellethomas
725b8f94c9 Adding tests for the time table viz (#4659) 2018-04-11 13:24:51 -07:00
hidetoshiito
e96590744f BugFix(#3658) (#4133)
* BugFix(#3658)

rollback to old version

* Update views.py
2018-04-11 13:21:54 -07:00
timifasubaa
20f46eede5 call next() the right way (#4804) 2018-04-11 13:20:14 -07:00
Hugh A. Miles II
3c29ca79ae filter recently viewed to just have explore and dashboard types (#4808) 2018-04-11 13:19:20 -07:00
Ariel Shemtov
adf9ec0bb1 adding option for multiple metrics, group by, opacity, legends (#4525) 2018-04-10 21:21:24 -07:00
John Bodley
7f1d7543d0 [logs] Dropping dt column (#4587) 2018-04-10 18:34:32 -07:00
Grace Guo
02a9e37f04 [homepage] Fix Favorites chart list (#4802) 2018-04-10 17:07:28 -07:00
John Bodley
1627fd096b [travis/tox] Restructuring configuration (#4552) 2018-04-10 15:59:44 -07:00
Maxime Beauchemin
14bf45da7c [bugfix] when num_period_compare is not set (#4799)
Fixing issues where y_axis_format is set and not num_period_compare
2018-04-10 14:49:22 -07:00
Maxime Beauchemin
1e7a294c1f Improve xAxis ticks, thinner bottom margin (#4756)
* Improve xAxis ticks, thinner bottom margin

* Moving utils folder

* Add isTruthy
2018-04-10 13:37:34 -07:00
David Hassan
64459efebd Add Ascendica Development in organizations list who use Superset (#4792)
Add Ascendica Development in organizations list who use Superset
2018-04-09 22:07:52 -07:00
Maxime Beauchemin
9bbe50f2f6 [explore] forcing .1% number format when using 'Period Ratio' (#4774) 2018-04-09 14:02:43 -07:00
Beto Dealmeida
47c085fd00 Add play slider to screengrid (#4647)
* Improved granularity parsing

* Add unit tests

* Explicit cast to int

* Screengrid play slider

* Clean code

* Refactor common code
2018-04-09 14:02:20 -07:00
John Bodley
41c158edac Rename UPDATING.MD to UPDATING.md (#4781) 2018-04-07 19:01:02 -07:00
Maxime Beauchemin
17e673ec87 [line] fix verbose names in time shift (#4765)
* [line] fix verbose names in time shift

* Addressing comments
2018-04-07 15:19:58 -07:00
Maxime Beauchemin
ee15fc8aa8 [doc] module header for controls.jsx and visTypes.jsx (#4777)
* Provide much needed module header for the controls.jsx module

* Typos
2018-04-07 12:56:29 -07:00
Maxime Beauchemin
627bdb2eb3 [dashboard] open in edit mode when adding a chart (#4772)
* [dashboard] open in edit mode when adding a chart

* Move dashboard unit tests to their own file

* fix tests

* Better URL management
2018-04-07 12:55:05 -07:00
EvelynTurner
bd2cb9aada [Bug fix] Resolving key conflicts in Timeseries Annotation Layer when key is a string (#4768)
* Fix how the annotation layer interpretes the timestamp string without timezone info; use it as UTC

* [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data

* [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data

* Fixed indentation

* Fix the key string value in case series.key is a string

* Fix the key string value in case series.key is a string
2018-04-06 16:22:20 -07:00
Maxime Beauchemin
4f2c2069f1 Improve controls layout for Table visualization (#4767) 2018-04-06 16:19:37 -07:00
Beto Dealmeida
426c34ee86 Pass granularity from backend to frontend as ISO duration (#4755)
* Add ISO duration to time grains

* Use ISO duration

* Remove debugging code

* Add module to yarn.lock

* Remove autolint

* Druid granularity as ISO

* Remove dangling comma
2018-04-06 16:19:17 -07:00
Beto Dealmeida
1a26485da4 Fix brush with annotations (#4773)
* Make annotation work with brush

* Add dispatch for events

* Fix lint

* Use xScale.clamp
2018-04-06 16:18:49 -07:00
Tamika Tannis
91366799d3 Add notes to contrib file about testing and code coverage (#4778) 2018-04-06 16:14:14 -07:00
Maxime Beauchemin
59cabe7d8f [explore] set control default for *showminmax = false (#4766)
Let's make the defaults less crowded on the axes by not showing the min
and max values on the axes (bounds)
2018-04-06 15:46:38 -07:00
DAOReady
92230b8535 Add context to templates / respect slice timeout (#4673)
* added context to templates to be able to use filters in SQL

* respect slice timeout in favor of others

* added trailing comma
2018-04-05 09:58:11 -07:00
John Bodley
df4ff05441 [druid] Excluding refreshing verbose name (#4761) 2018-04-04 17:16:53 -07:00
Maxime Beauchemin
68999b1407 [deck_multi] fixing issues with deck_multi (#4754)
* [deck_multi] fixing issues with deck_multi

* removing eslint comment
2018-04-04 16:52:14 -07:00
Maxime Beauchemin
adda30bf66 Set longer CSRF token duration (one week) (#4741)
Default is one hour (3600), also this entry makes the setting a bit more
discoverable
http://flask-wtf.readthedocs.io/en/stable/config.html?highlight=csrf
2018-04-04 15:55:32 -07:00
Maxime Beauchemin
3b7e0a951a [sql lab] preserve schema through visualize flow (#4742)
* [sql lab] preserve schema through visualize flow

https://github.com/apache/incubator-superset/pull/4696 got tangled
into refactoring views out of views/core.py and onto views/sql_lab.py

This is the same PR without the refactoring.

* Fix lint
2018-04-04 13:38:37 -07:00
fabianmenges
9a79d33e0d [BUGFIX]: JavaScripts max int is 2^53 - 1, longs are bigger (#4005)
* [BUGFIX]: Java scripts max int is 2^53 - 1 longs are bigger and frequently used as IDs this is a hacky fix.

* Keep tuple as tuple
2018-04-04 00:36:23 -07:00
Prashant
7a497e2f6b [sql_lab]Disabled run query button if sql query editor is empty (#4728)
* Disabled run query button if sql query editor is empty

* Removing unnecessary white space

* Fix failing test for sql props

* Adding sql variable into propTypes and defaultProps
2018-04-03 14:58:23 -07:00
Maxime Beauchemin
f6fe11f76e [bugfix] convert metrics to numeric in dataframe (#4726)
* [bugfix] convert metrics to numeric in dataframe

It appears sometimes the dbapi driver and pandas's read_sql fail at
returning the proper numeric types for metrics and they show up as
`object` in the dataframe. This results in "No numeric types to
aggregate" errors when trying to perform aggregations or pivoting in
pandas.

This PR looks for metrics in dataframes that are typed as "object"
and uses pandas' to_numeric to convert.

* Fix tests

* Remove all iteritems
2018-04-02 21:48:14 -07:00
Kuisong Tong
aa4173dc81 Pass timezone to Druid Query granularity (#4648)
superset appends DRUID_TZ info to intervals but not to granularity which causes one day's data return as 2 days. This fix is also pass DRUID_TZ to granularity.
2018-04-02 21:38:46 -07:00
Jeffrey Wang
8be0bde683 [BugFix] Allowing limit ordering by post-aggregation metrics (#4646)
* Allowing limit ordering by post-aggregation metrics

* don't overwrite og dictionaries

* update tests

* python3 compat

* code review comments, add tests, implement it in groupby as well

* python 3 compat for unittest

* more self

* Throw exception when get aggregations is called with postaggs

* Treat adhoc metrics as another aggregation
2018-04-02 21:37:00 -07:00
John Bodley
68bfcefb27 [flask-appbuilder] Bumping version to 1.10.0 (#4603) 2018-04-02 21:35:10 -07:00
Maxime Beauchemin
969ff0ce39 Fix deep equality logic (#4730)
* Fix deepequality logic

Zeroed-in on this while a Deck Scatter Plot chart was prompting for
refresh on-load.

I'm pretty sure using JSON.stringify as a proxy for deep equality is
wrong.

Not sure how to handle yarn.lock changes here. The changes on yarn.lock
are the result of "only" running `yarn add deep-equal`

* Adressing comments
2018-04-02 20:54:57 -07:00
Beto Dealmeida
ab7ba20009 Expose metrics to JS (#4654) 2018-04-02 17:48:56 -07:00
Gabe Lyons
1ef856e57a including auto generated avg metrics in druid (#4718) 2018-04-02 16:08:25 -07:00
Gabe Lyons
e0f541f486 easier tab closing in sqllab (#4738) 2018-04-02 14:59:08 -07:00
Maxime Beauchemin
11c9e67ebb [explore] don't prompt to 'Run Query' on viewport change (#4729) 2018-04-02 13:35:51 -07:00
Maxime Beauchemin
221b35f36d Add '.1%' to number format options (#4720) 2018-04-01 21:13:07 -07:00
Maxime Beauchemin
069d61c53f [sqllab] fix data grid's instant search function (#4717)
* [sqllab] fix data grid's instant search function

It looks like any non-string type would break the search feature.
of `FilterableTable`

* Addressing comments
2018-03-30 10:22:10 -07:00
John Bodley
b3442a7b53 [cli] Deprecating gunicorn/flower dependencies (#4451) 2018-03-30 09:28:16 -07:00
timifasubaa
e25535c693 Remove redundant has_access definition in superset (#4689)
* update has_access to has_method_access

* move has_access to sm and rename to has_method_access
2018-03-29 17:54:11 -07:00
John Bodley
d49a0e7958 [sqllab] Using app context for Celery task (#4669) 2018-03-29 16:11:23 -07:00
Maxime Beauchemin
29678680ee Use 3 letters month prefix in default date format (#4693) 2018-03-29 14:41:22 -07:00
Maxime Beauchemin
ed9a56b4ab [sql lab] ctrl-r hotkey should run latest SQL (#4719)
Turns out the SQL would only be committed to the redux store `onBlur`
event to avoid the laggy typing. The delay come from the localStorage
binding that add enough millisecs of delay to feel odd while typing.

I now store the most recent SQL in the local and use that instead.
2018-03-29 14:32:03 -07:00
Maxime Beauchemin
9ee78d16d4 Add missing perms to sql_lab role (#4714)
The SQL Lab related role that is created programmatically is missing
permissions that make SQL Lab functional.
2018-03-29 14:24:11 -07:00
Alagappan
f952ec2f06 Remove trailing '/' from Mailing list link in README file (#4709) 2018-03-29 11:12:36 -07:00
Gabe Lyons
68dec24542 [Explore] Streamlined metric definitions for SQLA and Druid (#4663)
* adding streamlined metric editing

* addressing lint issues on new metrics control

* enabling druid
2018-03-28 17:41:29 -07:00
Beto Dealmeida
7e1b6b7363 Rename no_reload (#4703) 2018-03-28 14:44:01 -07:00
michellethomas
485b0c275e Fixing label issue when columnType is null (#4700) 2018-03-27 17:54:24 -07:00
Joe Bordes
d8d860facc i18n(es_es) (#4687) 2018-03-27 17:48:42 -07:00
timifasubaa
8dd052de4b [security] Refactor security code into SupersetSecurityManager (#4565)
* move access permissions methods to security manager

* consolidate all security methods into SupersetSecurityManager

* update security method calls

* update calls from tests

* move get_or_create_main_db to utils

* raise if supersetsecuritymanager is not extended

* rename sm to security_manager
2018-03-27 16:46:02 -07:00
Maxime Beauchemin
f510956da2 Hotkeys in SQL Lab (#4680)
* Hotkeys

* Making it work in AceEditor

* Addressing comments
2018-03-27 15:54:54 -07:00
Maxime Beauchemin
deb211154d Docs on how to package a release + CHANGELOG for 0.24.0 (#4697)
* Docs on how to package a release + CHANGELOG for 0.24.0

* Addressing comments

* Add pypi perm info
2018-03-27 15:48:57 -07:00
John Bodley
f9d85bd2e1 [druid] Updating refresh logic (#4655) 2018-03-26 18:35:43 -07:00
michellethomas
52b925fee8 Fix bug with sorting columns in group by using time shift (#4683) 2018-03-26 10:55:43 -07:00
Maxime Beauchemin
336a1064d6 CRUD hints around SQL expressions (#4645)
* CRUD hints around SQL expressions

* Addressing comment
2018-03-26 09:44:37 -07:00
Ville Brofeldt
4ec82582c6 Preprocess SQL Lab query prior to checking syntax (#4686)
Syntax checking doesn't work if jinja templates haven't been prerendered.
Also remove unreachable return statement. Fixes #4288.
2018-03-26 09:42:33 -07:00
Maxime Beauchemin
097a37a1a1 Fix up the Lyft color scheme (#4684)
Previous color scheme had too few colors, some with light tones
and wasn't hooked up to the array.
2018-03-26 09:33:45 -07:00
Hugh A. Miles II
9abc5c724f Add lyftColor to the game 💯 (#4682)
* add lyftColor to the game 💯

* fix json
2018-03-23 18:02:29 -07:00
timifasubaa
00cab7e107 add yarn lock info to contributing.md (#4679) 2018-03-23 15:31:47 -07:00
Riccardo Magliocchetti
76394d3f8f forms: make csv import parse dates accepts a list of columns (#4639)
Instead of a boolean which has way less chances to work. While
at it add a proper label for the "con" field.

Fixes #4637
2018-03-23 14:16:02 -07:00
timifasubaa
f11cde9eb8 add yarn.lock (#4674) 2018-03-23 14:14:00 -07:00
Maxime Beauchemin
b24a6fd4b5 Fix setup.py, comma makes download_url a tuple (#4676) 2018-03-23 11:21:19 -07:00
EvelynTurner
73f7f817d3 [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data (#4630)
* Fix how the annotation layer interpretes the timestamp string without timezone info; use it as UTC

* [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data

* [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data

* Fixed indentation
2018-03-22 23:10:40 -07:00
Alexander T
d427f6a322 Update messages.po (#4670) 2018-03-22 17:47:15 -07:00
yanyu
b9965230df fix: epoch_s and epoch_ms to date time (#4664) 2018-03-22 08:13:38 -07:00
Beto Dealmeida
ec069676fd Better default for MAPBOX_API_KEY (#4660) 2018-03-21 17:13:09 -07:00
Jeffrey Wang
33aa976e3d Cache the query string (#4633)
* Cache the query string

* misc linter
2018-03-21 13:13:36 -07:00
Maxime Beauchemin
fc47729233 [sql lab] search to use fist&last name instead of username (#4628)
In our environment username are not readable coming out of oauth, so
we'd rather use first&last when available.
2018-03-19 22:16:17 -07:00
Maxime Beauchemin
1435840e38 Set filter_select_enabled default to True for Druid (#4608) 2018-03-19 22:15:43 -07:00
Maxime Beauchemin
8942436ece [examples] let's not use 'date' as a col name (#4555)
'date' is a reserved word in most database
2018-03-19 22:15:19 -07:00
Maxime Beauchemin
ed9867c0cc Use 'count' as the default metric when available (#4606)
* Use 'count' as the default metric when available

Count is a much better default than the current behavior which is to use
whatever the first metric in the list happens to be.

* Addressing nits
2018-03-19 21:51:51 -07:00
michellethomas
5c98f5642b Fix sqllab numpy array (#4629)
* Fixing error with sqllab numpy array

* Adding tests for failing sqllab data type
2018-03-19 11:43:04 -07:00
Beto Dealmeida
ba9379b949 Only show overlay if container is set (#4601)
* Pass width in props

* Only load overlay if container is set
2018-03-19 11:23:19 -07:00
Maxime Beauchemin
83f8f98ae3 [cosmetic] removing table border in ModelView list (#4638) 2018-03-19 11:02:40 -07:00
Hugh A. Miles II
e9b5b1a305 part1 (#4641) 2018-03-19 11:02:03 -07:00
michellethomas
97afcd5809 Adding to list of generated-members to fix pylint errors (#4632)
* Adding to list of generated-members

* Updating to ignore-classes sqlalchemy scoped_session
2018-03-16 16:20:25 -07:00
michellethomas
3f1dfb3173 Adding column type label to dropdowns (#4566)
* Adding column type label to dropdowns

* Changing the style of column type label

* Adding tests for ColumnTypeLabel

* Adding tests for time and fixing if statement order

* Changing location of ColumnTypeLabel tests

* Updating ColumnTypeLabel structure
2018-03-16 14:19:09 -07:00
John Bodley
6875868cf6 Merge pull request #4627 from mistercrunch/fix_run_extra
Move run_extra_queries outsize of BaseViz init
2018-03-16 13:21:57 -07:00
Maxime Beauchemin
b906fece68 Move run_extra_queries outsize of BaseViz init 2018-03-16 10:05:15 -07:00
Maxime Beauchemin
93ec76f757 [sql lab] reduce the number of metadata calls when loading a table (#4593) 2018-03-15 17:53:34 -07:00
Beto Dealmeida
da842f113a Fix function name (#4620) 2018-03-15 17:52:30 -07:00
Beto Dealmeida
7da164d386 Remove group by from deck.gl viz (#4622) 2018-03-15 17:48:18 -07:00
Maxime Beauchemin
1e0bcba568 Allowing config flag to turn off flask-compress (#4617) 2018-03-15 17:17:04 -07:00
Chris Williams
e2bd40c89f [bug fixes] annotations <> x domains, zeros in text (#4194)
* [bugs] account for annotations in nvd3 x scale domain, fix dynamic width explore charts, allow 0 in text control

* tweak TextControl casting

* [annotations] filter separately from finding data extent
2018-03-15 15:13:24 -07:00
Grace Guo
7c5bc8d90c fix mapbox viz (#4621) 2018-03-15 15:06:41 -07:00
John Bodley
36fa6cd7df [contributing] Removing obsolete code climate reference (#4616) 2018-03-14 16:50:25 -07:00
Beto Dealmeida
7089344623 Legend for deck.gl scatterplot (#4572)
* Initial work

* Working version

* Specify legend position

* Max height with scroll

* Fix lint

* Better compatibility with nvd3

* Fix object.keys polyfill version

* Fix lint
2018-03-14 16:40:14 -07:00
Beto Dealmeida
86a03d1dc8 Show "Range Filter" by default (#4604)
* Show Range Filter by default

* Auto show brush

* Backwards compat

* Small fix
2018-03-14 16:38:47 -07:00
Gabe Lyons
3371c8bd5c overriding annotation and layers' control tab (#4609) 2018-03-14 00:05:06 -07:00
Chris Williams
95a9b046f8 [slice_json] pass slice id to get_form_data() (#4607) 2018-03-13 14:49:06 -07:00
John Bodley
4250e239a2 Merge pull request #4590 from michellethomas/fixing_double_escape_presto
Removing escape_sql so we dont double escape
2018-03-13 12:19:44 -07:00
John Bodley
4e494b264b Merge pull request #4579 from michellethomas/removing_title_label
Removing [dashboard] and [slice] titles to show name
2018-03-13 12:00:11 -07:00
John Bodley
de4409835e Merge pull request #4573 from john-bodley/john-bodley-cache-fix-datasource-uid
[cache] Ensuring that the datasource UID is defined
2018-03-13 10:55:40 -07:00
John Bodley
037c04102f Merge pull request #4602 from john-bodley/john-bodley-druid-sync-fix-filter
[druid] Adding cluster filter for refresh
2018-03-13 10:53:36 -07:00
michellethomas
1d0ec9fe6e timeseries_limit should not be required for phase 2 (#4581) 2018-03-13 09:25:14 -07:00
Michelle Thomas
882921825c Changing the title for explore pages 2018-03-12 17:59:49 -07:00
John Bodley
9604e1dd14 [druid] Adding cluster filter for refresh 2018-03-12 16:23:08 -07:00
oxydash
8951990d6e [BugFix] Resizing widgets problem #4596 (#4597) 2018-03-12 14:27:02 -07:00
John Bodley
26257d94f5 [cache] Ensuring that the datasource UID is defined 2018-03-12 09:49:32 -07:00
Hugh A. Miles II
2bc089ef8d Added new exception class and start of better exception/error handling (#4514)
* rebase and linting

* change back

* wip

* fixed broken test

* fix flake8

* fix test
2018-03-11 22:07:51 -07:00
oxydash
ff41f40721 Add ignore git @eaDir Synology directory (#4599) 2018-03-11 21:54:49 -07:00
Ville Brofeldt
ee073eee23 Add Aktia Bank in organizations list who use Superset (#4591)
PRs and #4413 and #4448 contributed while implementing Superset at Aktia.
2018-03-11 11:45:47 -07:00
Riccardo Magliocchetti
1d27fb30ff docs: fixup code blocks rendering (#4594) 2018-03-11 11:34:58 -07:00
Michelle Thomas
e1af421f0c Removing escape_sql so we dont double escape 2018-03-09 15:37:17 -08:00
Riccardo Magliocchetti
f9881101ee histograms: fixup left margin assigment (#4532) 2018-03-09 15:31:34 -08:00
Beto Dealmeida
1647004486 Return __time in Druid scan (#4504)
* Return __time in Druid scan

* use constant instead of __timestamp

* Fix lint
2018-03-09 15:28:11 -08:00
Hugh A. Miles II
c6af4882cd [sqllab] Added share button to bottom menu (#4584)
* added sharebtn

* address comments
2018-03-09 15:10:36 -08:00
Maxime Beauchemin
d522292b01 [sql lab] option to disable cross schema search (#4551)
* [sql lab] disable cross schema search

This is killing our metastore as people type it emits large
all-table-dump as they hit the keystroke. It never returns as it times
out and hammers the poor metastore.

Also some improvements around the disabling the table select on the left
panel and having the table name not be sticky.

* typo
2018-03-09 14:54:39 -08:00
Maxime Beauchemin
34a081b926 [sql lab] comment injection hook (#4585) 2018-03-09 11:27:36 -08:00
oxydash
4ffc56f1c9 [Translate] Added Full Russian Translation (#4586) 2018-03-09 11:13:37 -08:00
John Bodley
c85eea3037 Merge pull request #4582 from john-bodley/john-bodley-javascript-codecov
[code-climate] Deprecating Code Climate from JavaScript tests
2018-03-09 09:02:14 -08:00
John Bodley
3fbadd68a4 [code-climate] Deprecating Code Climate from JavaScript tests 2018-03-08 22:40:08 -08:00
Pithawat Vachiramon
b512da8002 Adding option to visualize negative values in Table view (#4570)
* Adding option to visualize negative values in Table view

* Adding option for highlighting and right aligning

* Fixed typo

* Fixed case and condition

* Formatting

* Aligning left and default changes

* Changing default
2018-03-08 18:07:49 -08:00
Michelle Thomas
402c7ddb26 Removing [dashboard] and [slice] titles to show name 2018-03-08 13:55:00 -08:00
Grace Guo
9edbd64c5d [Explore] Save custom url parameters when user save slices (#4578)
* [Explore] Save url parameters when user save slices

* remove print

(cherry picked from commit bd9ecbe)

* add unit test

(cherry picked from commit 0f350ad)

* wrapping all request params into url_params

(cherry picked from commit 17197c1)
2018-03-08 13:19:41 -08:00
EvelynTurner
42ebcaad40 Evelynturner/annotation timezone fix2 (#4550)
* Fix how the annotation layer interpretes the timestamp string without timezone info; use it as UTC

* Fix how the Interval annotation layer interpretes the timestamp string without timezone info; use it as UTC
2018-03-08 10:19:36 -08:00
André Neidert
9ad50c9d55 Basic Portuguese Brazilian Translation (#4472)
* Basic Portuguese Brazilian Translation

* removing incorrect indentation

* Correct language name

* Improving language description

* Improving flag description
2018-03-07 17:43:55 -08:00
Kyle Travis
31a995714d [bug] Fix CSV upload feature for DB with password (#4562)
* Use sqlalchemy_uri_decrypted in create_engine calls

* Update tox mysql uri

* Include mysql charset=utf8 for py2.7 in tox.ini
2018-03-07 17:42:52 -08:00
John Bodley
d494c82930 [landscape.io] Deprecating .landscape.yml (#4563) 2018-03-07 17:40:23 -08:00
John Bodley
0dfa3b99dd [requires.io] Removing obsolete requires.io link (#4564) 2018-03-07 17:39:51 -08:00
John Bodley
826d0631e0 Merge pull request #4567 from john-bodley/john-bodley-payload-error-status-code
[payload] Set status code on error rather than query status
2018-03-07 13:53:06 -08:00
John Bodley
1e8cd0e61e [payload] Set status code on error rather than query status 2018-03-07 13:26:20 -08:00
Grace Guo
369f652bfc [bug] fix shortener url (#4560)
[bug] fix shared explore url
2018-03-07 10:57:33 -08:00
Maxime Beauchemin
b63dc91cd1 Expose hook to inject database connection logic on the fly (#4505)
* Expose hook to inject database connection logic on the fly

This environment configuration setting hook allows administrators to
alter the database connection parameters on the fly based on user
information. This can be use for a variety of purposes:

* rewire a subset of users to use different database user accounts
* pass user related information to the database for logging or QoS
purposes
* ...

* Fixes
2018-03-06 22:35:46 -08:00
Maxime Beauchemin
d817b8ddbb Setting up compression using flask-compress (#4543) 2018-03-06 21:19:29 -08:00
John Bodley
ef4e5ecedf [bugfix] Fixing regression from #4500 (#4549) 2018-03-06 21:19:13 -08:00
John Bodley
01e0a2f071 [landing] Making Dashboards the first/default tab (#4553) 2018-03-06 18:49:17 -08:00
Maxime Beauchemin
2e780e4034 Removing files from MANIFEST.in (#4542) 2018-03-06 09:39:31 -08:00
John Bodley
71d7196137 Merge pull request #4533 from john-bodley/john-bodley-replace-coveralls-with-codecov
[coverage] Replacing coveralls with codecov
2018-03-06 08:00:16 -08:00
John Bodley
150768ee30 [presto] Removing patched presto (#4530) 2018-03-05 23:16:02 -08:00
John Bodley
06c5077691 [dump.rdb] Removing rouge file (#4536) 2018-03-05 23:11:40 -08:00
Luciano Arango
2c5adb6dc3 Add ScopeAI (#4541) 2018-03-05 23:11:01 -08:00
John Bodley
6e0ece76a0 Merge pull request #4534 from john-bodley/john-bodley-setup-url
[setup] Fixing repo URLs
2018-03-05 18:03:04 -08:00
John Bodley
48430a1918 Merge pull request #4500 from john-bodley/john-bodley-fix-pr-4396
[bugfix] Fixing regression introduced in #4396
2018-03-05 16:51:09 -08:00
John Bodley
b01a9bba1f [setup] Fixing URLs 2018-03-05 13:06:08 -08:00
Riku Pelkonen
007ad351cf Pass datasource as form_data param (#4538)
* Pass datasource as form_data param

* add comma after datasource

* change test to match new addSlice
2018-03-05 11:43:59 -08:00
John Bodley
4f7258aaca [coverage] Replacing coveralls with codecov 2018-03-04 13:27:26 -08:00
Ariel Shemtov
413585448e Superset issue #4512: fixing histogram (#4513)
* fixing histogram axes and colors, adding normalized and x-axis label options

* adding y-axis label option
2018-03-02 13:45:46 -08:00
EvelynTurner
41defdceaa Fix how the annotation layer interpretes the timestamp string without timezone info; use it as UTC (#4511) 2018-03-01 21:02:04 -08:00
Grace Guo
2637d3d5e2 [dashboard] (#4515) 2018-03-01 15:48:04 -08:00
Gabe Lyons
79bb54a173 chart style options get their own tab (#4482) 2018-03-01 14:24:09 -08:00
Jeffrey Wang
3a58dc7ecf Make margin width based on container width instead of slice width (#4487)
* Make width based on container width instead of slice width

* fix const var name and add comment

* Actually 30 looks good too
2018-02-28 15:48:15 -08:00
John Bodley
7440d34936 [payload] Fixing regression introducted in ##4396 2018-02-28 14:23:20 -08:00
Gabe Lyons
764a92cd10 [Explore] applying refresh chart overlay when chart is stale (#4486)
* adding refresh chart overlay when chart is out of sync with control panel

* fading the visualization when stale

* addressing comments from team on layout of UI
2018-02-28 14:19:06 -08:00
Maxime Beauchemin
849a2cecee Add https support for Druid (#4480)
* Add https support for Druid

* addressing comment
2018-02-28 10:12:17 -08:00
Maxime Beauchemin
264822b1ee Introduce an onInit method for when a new viz_type is selected (#4491)
* Introduce an onInit method for when a new viz_type is selected

This allows for clearing certain controls where/when needed. For
instance here, when loading deck_scatter, even if there was a time
granularity picked for the previous viz_type, we want to unselect it.

* making it functional
2018-02-27 22:36:52 -08:00
timifasubaa
404e2d552a fixes to csv - hive upload (#4488) 2018-02-27 22:13:06 -08:00
timifasubaa
8626793655 check for access before requesting access (#4469) 2018-02-27 17:43:37 -08:00
Maxime Beauchemin
c2b42c49c6 Change limit form 50k to 10k (#4496) 2018-02-27 16:44:02 -08:00
Maxime Beauchemin
83524f97d7 [WiP] Cleanup & fix URL scheme for the explore view (#4490)
* Improve URLs

* Fix js tests
2018-02-27 15:08:06 -08:00
Grace Guo
bcca1717f2 [dashboard] Fix JS error when position_json data is empty (#4485) 2018-02-27 10:18:32 -08:00
Hugh A. Miles II
11ea83ecf1 New Landing Page v1.0 (#4463)
* Updated welcome landing page

* fixed test and linting

* linting

* addressing comments

* fix test

* fix test

* remove unneeded var

* add magic comments
2018-02-26 17:02:41 -08:00
Gabe Lyons
56f65158a2 [Explore] highlighting run query when chart is stale on explore view (#4459)
* highlighting run query when chart is stale on explore view

* refactoring control changed code
2018-02-26 10:57:20 -08:00
Maxime Beauchemin
2932585c65 [geo] add controls for minRadiusPixels and maxRadiusPixels in deck_scatter (#4467) 2018-02-26 10:56:19 -08:00
John Bodley
d57a37e341 [flake8] Adding flake8-coding (#4477) 2018-02-25 15:06:11 -08:00
Jinyang Zhou
ff685db4d9 add organization (#4478) 2018-02-25 15:00:10 -08:00
Raffaele Spangaro
094eb71f86 [FilterBox] Make filterbox localizable (#4466)
* Make filterbox i18n

* Change double-quote to single-quote in localization function t() to pass
lint test

* Updated .po file with italian translation. New strings generated and translated via babel-extract
2018-02-25 14:58:14 -08:00
John Bodley
e112e4417c [flake8] Adding future-import check (#4476) 2018-02-23 16:42:09 -08:00
John Bodley
8aac63e74c [flake8] Fixing additional flake8 issue w/ the presence of ignore (#4474) 2018-02-23 14:46:26 -08:00
Hugh A. Miles II
cacf53c92e Pass param of limit for recent activity (#4475) 2018-02-23 14:18:06 -08:00
timifasubaa
5830846060 [hotfix] resolve utf-8 encoding issue in db migration (#4461)
* [hotfix] resolve utf-8 encoding issue in db migration

* make python string unicode

* Update e866bd2d4976_smaller_grid.py

* Update e866bd2d4976_smaller_grid.py

* rearrange the debug message

* Update e866bd2d4976_smaller_grid.py
2018-02-21 17:45:28 -08:00
Maxime Beauchemin
0eecec10cd [explore] allow URL shortner even if no slice exist (#4457)
recent regression perhaps from the PR that moved to using POST .
2018-02-21 10:35:38 -08:00
Maxime Beauchemin
a373db24f0 Allowing config flag to turn off javascript controls (#4400)
* Allowing config flag to turn off javascript controls

* lint

* one line, avoiding mutation

* Setting JS fields as readOnly
2018-02-21 08:31:07 -08:00
Beto Dealmeida
c3176579e0 Make instant controls store state in URL (#4449)
* Add to history on instant control change

* Update latestQueryFormData on render triggered

* Add new message type

* Update latestQueryFormData in UPDATE_QUERY_FORM_DATA
2018-02-20 17:08:07 -08:00
Maxime Beauchemin
d4a2f4ef36 Make npm run dev-fast the default (#4454) 2018-02-20 17:07:33 -08:00
Gabe Lyons
b60965b8fa [gitignore] Adding venv to .gitignore (#4456)
* fixing spacing issue on internationalization dropdown

* adding venv to gitignore
2018-02-20 17:07:16 -08:00
Maxime Beauchemin
5c35a2d210 A collection of bug fixes (#4444) 2018-02-20 14:41:35 -08:00
Gabe Lyons
c336fe5707 fixing spacing issue on internationalization dropdown (#4455) 2018-02-20 14:13:46 -08:00
Maxime Beauchemin
177d7c07e6 [bugfix] address issue 4206 (#4452)
closes 4206
2018-02-19 09:56:25 -08:00
Grace Guo
5768a1fe5e for 48 columns layout, adjust default size and layout for newly added slices (#4446) 2018-02-19 00:05:57 -08:00
Ville Brofeldt
d6c197f8ac Remove comments from queries in SQL Lab that break Explore view (#4413)
* Remove comments from queries in SQL Lab that break Explore view

This fixes an issue where comments on the last line of the source query comment out the closing parenthesis of the subquery.

* Add test case for SqlaTable with query with comment

This test ensures that comments in the query are removed when calling SqlaTable.get_from_clause().

* Add missing blank line class definition (PEP8)
2018-02-18 16:30:11 -08:00
m4neda
f46bb533cb fix typo. "グルプ分け可能" => "グループ分け可能" (#4450) 2018-02-17 09:25:17 -08:00
Grace Guo
15aa0c5cdd remove html tag in timeout error message (#4447) 2018-02-16 19:44:29 -08:00
Maxime Beauchemin
88e91e6d8f Improve default placeholder text on SelectControl (#4442) 2018-02-16 15:16:55 -08:00
Ville Brofeldt
dc48673647 Removed double call to ConnectorRegistry.sources (#4448)
Removing the double call didn't cause any adverse effects upon removal. If required, a comment motivating the double call should be added.
2018-02-16 15:16:25 -08:00
909 changed files with 105306 additions and 22112 deletions

View File

@@ -1,40 +0,0 @@
engines:
csslint:
enabled: false
duplication:
enabled: false
eslint:
enabled: true
checks:
import/extensions:
enabled: false
import/no-extraneous-dependencies:
enabled: false
config:
config: superset/assets/.eslintrc
pep8:
enabled: true
fixme:
enabled: false
radon:
enabled: true
checks:
Complexity:
enabled: false
ratings:
paths:
- "**.py"
- "superset/assets/**.js"
- "superset/assets/**.jsx"
exclude_paths:
- ".*"
- "**.pyc"
- "**.gz"
- "env/"
- "tests/"
- "superset/assets/images/"
- "superset/assets/vendor/"
- "superset/assets/node_modules/"
- "superset/assets/javascripts/dist/"
- "superset/migrations"
- "docs/"

View File

@@ -1 +0,0 @@
repo_token: 4P9MpvLrZfJKzHdGZsdV3MzO43OZJgYFn

13
.gitignore vendored
View File

@@ -11,6 +11,7 @@ _images
_modules
superset/bin/supersetc
env_py3
envpy3
.eggs
build
*.db
@@ -26,14 +27,24 @@ app.db
*.sqllite
.vscode
.python-version
.tox
dump.rdb
# Node.js, webpack artifacts
*.entry.js
*.js.map
node_modules
npm-debug.log*
yarn.lock
superset/assets/version_info.json
# IntelliJ
*.iml
venv
@eaDir/
# docker
/Dockerfile
/docker-build.sh
/docker-compose.yml
/docker-entrypoint.sh
/docker-init.sh

View File

@@ -1,22 +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
- superset/migrations/env.py
ignore-patterns:
- ^example/doc_.*\.py$
- (^|/)docs(/|$)

View File

@@ -65,7 +65,7 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=standarderror-builtin,long-builtin,dict-view-method,intern-builtin,suppressed-message,no-absolute-import,unpacking-in-except,apply-builtin,delslice-method,indexing-exception,old-raise-syntax,print-statement,cmp-builtin,reduce-builtin,useless-suppression,coerce-method,input-builtin,cmp-method,raw_input-builtin,nonzero-method,backtick,basestring-builtin,setslice-method,reload-builtin,oct-method,map-builtin-not-iterating,execfile-builtin,old-octal-literal,zip-builtin-not-iterating,buffer-builtin,getslice-method,metaclass-assignment,xrange-builtin,long-suffix,round-builtin,range-builtin-not-iterating,next-method-called,dict-iter-method,parameter-unpacking,unicode-builtin,unichr-builtin,import-star-module-level,raising-string,filter-builtin-not-iterating,old-ne-operator,using-cmp-argument,coerce-builtin,file-builtin,old-division,hex-method,invalid-unary-operand-type
disable=standarderror-builtin,long-builtin,dict-view-method,intern-builtin,suppressed-message,no-absolute-import,unpacking-in-except,apply-builtin,delslice-method,indexing-exception,old-raise-syntax,print-statement,cmp-builtin,reduce-builtin,useless-suppression,coerce-method,input-builtin,cmp-method,raw_input-builtin,nonzero-method,backtick,basestring-builtin,setslice-method,reload-builtin,oct-method,map-builtin-not-iterating,execfile-builtin,old-octal-literal,zip-builtin-not-iterating,buffer-builtin,getslice-method,metaclass-assignment,xrange-builtin,long-suffix,round-builtin,range-builtin-not-iterating,next-method-called,dict-iter-method,parameter-unpacking,unicode-builtin,unichr-builtin,import-star-module-level,raising-string,filter-builtin-not-iterating,old-ne-operator,using-cmp-argument,coerce-builtin,file-builtin,old-division,hex-method,invalid-unary-operand-type,missing-docstring,too-many-lines,duplicate-code
[REPORTS]
@@ -277,12 +277,12 @@ ignore-mixin-members=yes
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=numpy,pandas,alembic.op,sqlalchemy,alembic.context,flask_appbuilder.security.sqla.PermissionView.role,flask_appbuilder.Model.metadata,flask_appbuilder.Base.metadata
ignored-modules=numpy,pandas,alembic.op,sqlalchemy,alembic.context,flask_appbuilder.security.sqla.PermissionView.role,flask_appbuilder.Model.metadata,flask_appbuilder.Base.metadata,distutils
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
ignored-classes=contextlib.closing,optparse.Values,thread._local,_thread._local,sqlalchemy.orm.scoping.scoped_session
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
@@ -292,7 +292,7 @@ generated-members=
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
[VARIABLES]

View File

@@ -1,31 +1,46 @@
language: python
python:
- 2.7
- 3.6
services:
- redis-server
addons:
code_climate:
repo_token: 5f3a06c425eef7be4b43627d7d07a3e46c45bdc07155217825ff7c49cb6a470c
- mysql
- postgres
- redis-server
cache:
directories:
- $HOME/.wheelhouse/
env:
global:
- TRAVIS_CACHE=$HOME/.travis_cache/
matrix:
- TOX_ENV=flake8
- TOX_ENV=javascript
- TOX_ENV=pylint
- TOX_ENV=py34-postgres
- TOX_ENV=py34-sqlite
- TOX_ENV=py27-mysql
- TOX_ENV=py27-sqlite
- pip
matrix:
include:
- python: 2.7
env: TOXENV=flake8
- python: 2.7
env: TOXENV=py27-mysql
- python: 2.7
env: TOXENV=py27-sqlite
- python: 2.7
env: TOXENV=pylint
- python: 3.6
env: TOXENV=flake8
- python: 3.6
env: TOXENV=javascript
- python: 3.6
env: TOXENV=py36-postgres
- python: 3.6
env: TOXENV=py36-sqlite
- python: 3.6
env: TOXENV=pylint
exclude:
- python: 2.7
- python: 3.6
before_script:
- mysql -u root -e "DROP DATABASE IF EXISTS superset; CREATE DATABASE superset DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci"
- mysql -u root -e "CREATE USER 'mysqluser'@'localhost' IDENTIFIED BY 'mysqluserpassword';"
- mysql -u root -e "GRANT ALL ON superset.* TO 'mysqluser'@'localhost';"
- psql -U postgres -c "CREATE DATABASE superset;"
- psql -U postgres -c "CREATE USER postgresuser WITH PASSWORD 'pguserpassword';"
- export PATH=${PATH}:/tmp/hive/bin
install:
- pip install --upgrade pip
- pip install tox tox-travis
script: tox -e $TOX_ENV
- pip install codecov tox
script:
- tox
after_success:
- codecov

View File

@@ -1,5 +1,578 @@
## Change Log
### 0.26.0 (2018/07/03 14:13 +00:00)
- [#5315](https://github.com/apache/incubator-superset/pull/5315) [cache] Allowing zero cache-timeout (#5315) (@john-bodley)
- [#5313](https://github.com/apache/incubator-superset/pull/5313) Fix flaky unit test - remove 'Markup' object in data (#5313) (@mistercrunch)
- [#5309](https://github.com/apache/incubator-superset/pull/5309) [bugfix] README encoding-related UnicodeDecodeError on setup.py (#5309) (@mistercrunch)
- [#5320](https://github.com/apache/incubator-superset/pull/5320) Update core.py (#5320) (@fly-high-bj)
- [#5323](https://github.com/apache/incubator-superset/pull/5323) [dashboard fix]Fix copy_dash unit test (#5323) (@graceguo-supercat)
- [#5302](https://github.com/apache/incubator-superset/pull/5302) [DeckGL] Raise error with null values (#5302) (@hughhhh)
- [#5305](https://github.com/apache/incubator-superset/pull/5305) Adding THE ICONIC to the list (#5305) (@ksaagariconic)
### 0.26.0rc2 (2018/06/28 04:40 +00:00)
- [#4724](https://github.com/apache/incubator-superset/pull/4724) Improve database type inference (#4724) (@mistercrunch)
- [#5296](https://github.com/apache/incubator-superset/pull/5296) [dashboard v2] add MissingChart component in the case that chart component has no slice definition, add tests. (#5296) (@williaster)
- [#5297](https://github.com/apache/incubator-superset/pull/5297) [dashobard fix]: fix validation check for default_filters (#5297) (@graceguo-supercat)
- [#5274](https://github.com/apache/incubator-superset/pull/5274) [get_df] Fix datetime conversion (#5274) (@john-bodley)
- [#5290](https://github.com/apache/incubator-superset/pull/5290) Pin boto3 to 1.4.7 (#5290) (@jeffreythewang)
- [#5291](https://github.com/apache/incubator-superset/pull/5291) [dashboard fix] force refresh charts under tabs (#5291) (@graceguo-supercat)
- [#5293](https://github.com/apache/incubator-superset/pull/5293) fix sqllab <Loading /> css, fix double AddSliceCard margin and drag border (#5293) (@williaster)
- [#5267](https://github.com/apache/incubator-superset/pull/5267) add more precise types to hive table from csv (#5267) (@timifasubaa)
- [#5268](https://github.com/apache/incubator-superset/pull/5268) specify hve namespace for tables (#5268) (@timifasubaa)
- [#4528](https://github.com/apache/incubator-superset/pull/4528) [wip] dashboard builder v2 (#4528) (@williaster)
- [#5271](https://github.com/apache/incubator-superset/pull/5271) [metric] Fixing ad-hoc metric for dual-line chart (#5271) (@john-bodley)
- [#5249](https://github.com/apache/incubator-superset/pull/5249) [druid] Adding verbose_name to editable columns (#5249) (@john-bodley)
- [#5257](https://github.com/apache/incubator-superset/pull/5257) make sure there is a val to be set for existing filters (#5257) (@hughhhh)
- [#4964](https://github.com/apache/incubator-superset/pull/4964) Fix edge case around NaN values (#4964) (@mistercrunch)
- [#5154](https://github.com/apache/incubator-superset/pull/5154) [bugfix] add support for numeric nodes in Sankey (#5154) (@mistercrunch)
- [#5248](https://github.com/apache/incubator-superset/pull/5248) [bugfix] get word_cloud to support complex metrics (#5248) (@mistercrunch)
- [#5266](https://github.com/apache/incubator-superset/pull/5266) fixing regex displaying as undefined in the pill (#5266) (@GabeLoins)
- [#5262](https://github.com/apache/incubator-superset/pull/5262) Bump pydruid to 0.4.4 (#5262) (@mistercrunch)
- [#5264](https://github.com/apache/incubator-superset/pull/5264) Update db_engine_specs.py (#5264) (@timifasubaa)
- [#5263](https://github.com/apache/incubator-superset/pull/5263) [timeseries table] use verbose date in tooltip by default (#5263) (@williaster)
- [#5214](https://github.com/apache/incubator-superset/pull/5214) Moving homogenize_types to after no data exception (#5214) (@michellethomas)
- [#5241](https://github.com/apache/incubator-superset/pull/5241) [Explore] Handle empty metrics control data (#5241) (@graceguo-supercat)
- [#5121](https://github.com/apache/incubator-superset/pull/5121) [sql lab] Fix issue around VARBINARY type in Presto (#5121) (@mistercrunch)
- [#4520](https://github.com/apache/incubator-superset/pull/4520) Allow users to view dashboards they own (#4520) (@jeffreythewang)
- [#5253](https://github.com/apache/incubator-superset/pull/5253) Revert "[perf] add webpack 4 + SplitChunks + lazy load visualizations" (#5253) (@john-bodley)
- [#5216](https://github.com/apache/incubator-superset/pull/5216) [sqllab] Fix sql lab resolution link (#5216) (@timifasubaa)
- [#5184](https://github.com/apache/incubator-superset/pull/5184) Pin botocore version (#5184) (@ledor473)
- [#5220](https://github.com/apache/incubator-superset/pull/5220) Describe the use of custom OAuth2 authorization servers (#5220) (@ricard2k)
- [#5237](https://github.com/apache/incubator-superset/pull/5237) [bubble-chart] Fixing issue w/ metric names (#5237) (@john-bodley)
- [#5206](https://github.com/apache/incubator-superset/pull/5206) [adhoc-filters] Adding adhoc-filters to all viz types (#5206) (@john-bodley)
- [#5240](https://github.com/apache/incubator-superset/pull/5240) [perf] add webpack 4 + SplitChunks + lazy load visualizations (#5240) (@williaster)
- [#5217](https://github.com/apache/incubator-superset/pull/5217) [CRUD] disable user change slices from dashboardmodelview (#5217) (@graceguo-supercat)
- [#5238](https://github.com/apache/incubator-superset/pull/5238) [CRUD] Improving performance by disabling editing Associated Chart] (#5238) (@john-bodley)
- [#5215](https://github.com/apache/incubator-superset/pull/5215) [Explore] Enable Rich tooltip by default (#5215) (@graceguo-supercat)
- [#5226](https://github.com/apache/incubator-superset/pull/5226) setup: improve description (#5226) (@xrmx)
- [#5195](https://github.com/apache/incubator-superset/pull/5195) [sql lab] quote schema and table name (#5195) (@mistercrunch)
- [#5222](https://github.com/apache/incubator-superset/pull/5222) Bump Celery to 4.2.0 (#5222) (@villebro)
- [#5227](https://github.com/apache/incubator-superset/pull/5227) README: update Maieutical Labs url (#5227) (@xrmx)
- [#5219](https://github.com/apache/incubator-superset/pull/5219) Revert "[webpack] setup lazy loading for all visualizations" (#5219) (@williaster)
- [#5204](https://github.com/apache/incubator-superset/pull/5204) [explore] fix autocomplete on verbose names (#5204) (@mistercrunch)
- [#4727](https://github.com/apache/incubator-superset/pull/4727) [webpack] setup lazy loading for all visualizations (#4727) (@williaster)
- [#5203](https://github.com/apache/incubator-superset/pull/5203) [pie-chart] Restricting query to single metric (#5203) (@john-bodley)
- [#5205](https://github.com/apache/incubator-superset/pull/5205) Fixing issue with table viz for table with no metrics (#5205) (@michellethomas)
- [#5194](https://github.com/apache/incubator-superset/pull/5194) Merge pull request #5194 from timifasubaa/pass_error_link_separately (@timifasubaa)
- [7fa5559](https://github.com/apache/incubator-superset/commit/7fa5559a66afd7ef06bf35ad72f284f6f253d2b9) remove resolution link prop (@timifasubaa)
- [#5118](https://github.com/apache/incubator-superset/pull/5118) Merge pull request #5118 from michellethomas/add_metrics_control_sort_by (@michellethomas)
- [#5181](https://github.com/apache/incubator-superset/pull/5181) fix Formula type annotation, it doesn't show up since #4630 (#5181) (@graceguo-supercat)
- [#5176](https://github.com/apache/incubator-superset/pull/5176) Introduce class attr BaseViz.enforce_numerical_metrics (#5176) (@mistercrunch)
- [#5187](https://github.com/apache/incubator-superset/pull/5187) Repoint .istambul.yml to the right location (#5187) (@mistercrunch)
- [7a107fa](https://github.com/apache/incubator-superset/commit/7a107fac6270e6866a00b5c6e2373ea67564d310) pass_error_message_separately (@timifasubaa)
- [#5190](https://github.com/apache/incubator-superset/pull/5190) Merge pull request #5190 from timifasubaa/fix_null_metrics (@timifasubaa)
- [b380a57](https://github.com/apache/incubator-superset/commit/b380a57c91f9918e7dbc8f858df840e3ccb8d24d) Fixing sortby adhoc metrics for table viz (@michellethomas)
- [95bb175](https://github.com/apache/incubator-superset/commit/95bb1753ab3a9fef572b40d7b7762fd7b4982374) fix empty metrics (@timifasubaa)
- [#5179](https://github.com/apache/incubator-superset/pull/5179) Adding column only if it doesn't already exist (#5179) (@michellethomas)
- [#5183](https://github.com/apache/incubator-superset/pull/5183) fetch datasources from broker endpoint when refresh new datasources (#5183) (@liyuance)
- [#5167](https://github.com/apache/incubator-superset/pull/5167) [migrations] Cleaning up migration logic (#5167) (@john-bodley)
- [#5155](https://github.com/apache/incubator-superset/pull/5155) [migrations] Cleanup recent migrations (#5155) (@john-bodley)
- [#5055](https://github.com/apache/incubator-superset/pull/5055) Fixing tooltip displaying metrics in heatmap (#5055) (@michellethomas)
- [#5108](https://github.com/apache/incubator-superset/pull/5108) Fix bullet chart rendering (#5108) (@Tresdon)
- [#5122](https://github.com/apache/incubator-superset/pull/5122) Pin FAB and bump a bunch of JS libs (#5122) (@mistercrunch)
- [#4193](https://github.com/apache/incubator-superset/pull/4193) Init docker for local development environment. (#4193) (@xiaohanyu)
- [#5028](https://github.com/apache/incubator-superset/pull/5028) [druid] Fixing Druid version check (#5028) (@john-bodley)
- [#5156](https://github.com/apache/incubator-superset/pull/5156) Restore translations as of 459cb701fb2140fcce8b97a1839a9511574375c7 (#5156) (@mistercrunch)
- [#5162](https://github.com/apache/incubator-superset/pull/5162) [Explore][Adhoc Metrics/ Filters] disabled message for custom sql tab in druid (#5162) (@GabeLoins)
- [#5161](https://github.com/apache/incubator-superset/pull/5161) [migration] Adding migration to remove empty in/not-in filters (#5161) (@john-bodley)
- [#5160](https://github.com/apache/incubator-superset/pull/5160) empty lists are invalid comparators (#5160) (@GabeLoins)
- [#5140](https://github.com/apache/incubator-superset/pull/5140) Improve time shift (#5140) (@betodealmeida)
- [#5135](https://github.com/apache/incubator-superset/pull/5135) [migrations] Fix time grain SQLA (#5135) (@john-bodley)
- [#5150](https://github.com/apache/incubator-superset/pull/5150) pin kombu dependency (#5150) (@timifasubaa)
- [#5136](https://github.com/apache/incubator-superset/pull/5136) [crud] Improving performance (#5136) (@john-bodley)
- [#5132](https://github.com/apache/incubator-superset/pull/5132) Optimize presto SQL Lab query performance. (#5132) (@xiaohanyu)
- [#5134](https://github.com/apache/incubator-superset/pull/5134) Bump celery to 4.1.1 (#5134) (@mistercrunch)
- [#5133](https://github.com/apache/incubator-superset/pull/5133) Pin FAB to 1.10.0 (#5133) (@mistercrunch)
### 0.25.6 (2018/06/04 15:56 +00:00)
- [#4760](https://github.com/apache/incubator-superset/pull/4760) URL shortner for dashboards (#4760) (@ttannis)
- [4776828](https://github.com/apache/incubator-superset/commit/47768284d01453968e9b2e5aef8024110b6dc33e) Adding tests for adhoc metric as timeseries_limit_metric (@michellethomas)
- [#5105](https://github.com/apache/incubator-superset/pull/5105) updating adhoc metric filtering (#5105) (@GabeLoins)
- [#5112](https://github.com/apache/incubator-superset/pull/5112) docs: Add new Athena URI scheme awsathena+rest:// (#5112) (@icy)
- [#5067](https://github.com/apache/incubator-superset/pull/5067) Allow multiple time shifts (#5067) (@betodealmeida)
- [#5111](https://github.com/apache/incubator-superset/pull/5111) adding null checks to adhoc filter popover (#5111) (@GabeLoins)
### 0.26.0rc1 (2018/06/01 00:21 +00:00)
- [#5106](https://github.com/apache/incubator-superset/pull/5106) Refactor NULL handling into method, disable for DECK.gl vizes (#5106) (@mistercrunch)
- [#5117](https://github.com/apache/incubator-superset/pull/5117) Fixing time table viz for adhoc metrics (#5117) (@michellethomas)
- [6f05b48](https://github.com/apache/incubator-superset/commit/6f05b48385d80bc6adca3e0aa3b545d34243acfa) Adding the MetricsControl to the timeseries_limit_metric field (@michellethomas)
- [#5107](https://github.com/apache/incubator-superset/pull/5107) [bugfix] deck.gl on druid always shows animation (#5107) (@mistercrunch)
- [#5110](https://github.com/apache/incubator-superset/pull/5110) fixing LIKE constant name (#5110) (@GabeLoins)
- [#5023](https://github.com/apache/incubator-superset/pull/5023) Merge pull request #5023 from timifasubaa/fix_sqllab_commit (@timifasubaa)
- [#5084](https://github.com/apache/incubator-superset/pull/5084) Override time grain in annotations (#5084) (@betodealmeida)
- [#5109](https://github.com/apache/incubator-superset/pull/5109) Merge pull request #5109 from cxmcc/patch-1 (@cxmcc)
- [21967f4](https://github.com/apache/incubator-superset/commit/21967f40e720cfcc7d5cbe33cf5504e90c21b412) Add Lime to Superset user list. (@cxmcc)
- [a9d7faf](https://github.com/apache/incubator-superset/commit/a9d7fafd9f2dca7c569effa477e3ff3240d3032e) add tests (@timifasubaa)
- [#5098](https://github.com/apache/incubator-superset/pull/5098) Bump dep on pydruid to 0.4.3 (#5098) (@mistercrunch)
- [#5086](https://github.com/apache/incubator-superset/pull/5086) [get_df] Adding support for multi-statement SQL (#5086) (@john-bodley)
- [#5094](https://github.com/apache/incubator-superset/pull/5094) add CnOvit to Superset users list (#5094) (@xieshaohu)
- [#5083](https://github.com/apache/incubator-superset/pull/5083) Add more time grains (#5083) (@betodealmeida)
- [#4428](https://github.com/apache/incubator-superset/pull/4428) Proper error handling in Hive Queries (#4428) (@maver1ck)
- [#5093](https://github.com/apache/incubator-superset/pull/5093) Fix python2 str() in visualization (#5093) (@zjj)
- [d38315a](https://github.com/apache/incubator-superset/commit/d38315a307f7b3c2a41c63b7f654fae90183c03e) reuse_regex_logic (@timifasubaa)
- [1aced9b](https://github.com/apache/incubator-superset/commit/1aced9b56207fccc839afb5c32f9ee76aa0a6b47) force limit only when there is no existing limit (@timifasubaa)
- [#5080](https://github.com/apache/incubator-superset/pull/5080) [bugfix] fix visualization with adhocMetric (#5080) (@zhaoyongjie)
- [#5068](https://github.com/apache/incubator-superset/pull/5068) Add 24 hours refresh for dashboard (#5068) (@aok1425)
- [#5000](https://github.com/apache/incubator-superset/pull/5000) Use a dummy version number on master (#5000) (@mistercrunch)
- [#5078](https://github.com/apache/incubator-superset/pull/5078) Revert "[get_df] Adding support for multi-statement SQL" (#5078) (@john-bodley)
- [#5057](https://github.com/apache/incubator-superset/pull/5057) Translate string to array for multi fields in getControlsState (#5057) (@michellethomas)
- [#5065](https://github.com/apache/incubator-superset/pull/5065) Fix time shift color assignements (#5065) (@mistercrunch)
- [#5062](https://github.com/apache/incubator-superset/pull/5062) [markup] Enable allow-forms (#5062) (@john-bodley)
- [#5056](https://github.com/apache/incubator-superset/pull/5056) integrating dashboard filters with adhoc filters (#5056) (@GabeLoins)
- [#5060](https://github.com/apache/incubator-superset/pull/5060) [get_df] Adding support for multi-statement SQL (#5060) (@john-bodley)
- [#5051](https://github.com/apache/incubator-superset/pull/5051) [Dashboard] Allow Superset Alpha, Gamma users to save dashboard as a copy (#5051) (@graceguo-supercat)
- [#5021](https://github.com/apache/incubator-superset/pull/5021) Allow MetricsControl to aggregate on a column with an expression (#5021) (@michellethomas)
- [#5025](https://github.com/apache/incubator-superset/pull/5025) fix metrics type error in pivot table viz (#5025) (@gangh)
- [#5008](https://github.com/apache/incubator-superset/pull/5008) Rename "slice" to "chart" and update translations (#5008) (@betodealmeida)
- [#4819](https://github.com/apache/incubator-superset/pull/4819) Visualization for multiple line charts (#4819) (@betodealmeida)
- [#5032](https://github.com/apache/incubator-superset/pull/5032) expanding simple tab (#5032) (@GabeLoins)
- [#5038](https://github.com/apache/incubator-superset/pull/5038) forcing ace editor to refresh when it is shown (#5038) (@GabeLoins)
- [#5027](https://github.com/apache/incubator-superset/pull/5027) Add missing dep on contextlib2 (#5027) (@mistercrunch)
- [#5030](https://github.com/apache/incubator-superset/pull/5030) treating floats like doubles for druid versions lower than 11.0.0 (#5030) (@GabeLoins)
- [#5026](https://github.com/apache/incubator-superset/pull/5026) [bugfix] Fix ZeroDivisionError and get metrics label with percent metrics (#5026) (@zhaoyongjie)
- [#5019](https://github.com/apache/incubator-superset/pull/5019) Merge pull request #5019 from timifasubaa/fix_error_message_for_missing_datasource (@timifasubaa)
- [63115fb](https://github.com/apache/incubator-superset/commit/63115fbb879a2b67e2a701f376364c52dc49a7c9) nit (@timifasubaa)
- [f52f7aa](https://github.com/apache/incubator-superset/commit/f52f7aa7cfb9898e898ba77a07073c53627fee85) raise exception early (@timifasubaa)
### 0.25.5 (2018/05/17 19:45 +00:00)
- [#5022](https://github.com/apache/incubator-superset/pull/5022) Merge pull request #5022 from mistercrunch/flask_sub_1 (@mistercrunch)
- [2ba929a](https://github.com/apache/incubator-superset/commit/2ba929ac9e1d9e6ce7120e021e3f62ba769f8f6e) Fix flask 1.0.0 (@mistercrunch)
### 0.25.4 (2018/05/16 23:31 +00:00)
- [#5020](https://github.com/apache/incubator-superset/pull/5020) Make port number optional in superset for druid (#5020) (@amalakar)
- [cf374ef](https://github.com/apache/incubator-superset/commit/cf374efb3f8b347e912ef2174492994152fc7ddb) fix missing datasource error message (@timifasubaa)
### 0.25.3 (2018/05/16 18:25 +00:00)
- [#5007](https://github.com/apache/incubator-superset/pull/5007) Fix EncryptedType error (#5007) (@mistercrunch)
- [#5012](https://github.com/apache/incubator-superset/pull/5012) Fix AdhocFilterControl for single metric options (#5012) (@michellethomas)
- [#4914](https://github.com/apache/incubator-superset/pull/4914) Make MetricsControl the standard across visualizations (#4914) (@mistercrunch)
- [#4947](https://github.com/apache/incubator-superset/pull/4947) [sql lab] a better approach at limiting queries (#4947) (@mistercrunch)
- [#4965](https://github.com/apache/incubator-superset/pull/4965) Update Apache Kylin dbengine with supported week/quarter grains (#4965) (@zhaoyongjie)
- [#4992](https://github.com/apache/incubator-superset/pull/4992) cleaning up the table fab view since we hide these autogenerated metrics anyway (#4992) (@GabeLoins)
- [#4994](https://github.com/apache/incubator-superset/pull/4994) Force lowercase column names for Snowflake and Oracle (#4994) (@villebro)
- [#4991](https://github.com/apache/incubator-superset/pull/4991) Merge pull request #4991 from michellethomas/fix_filter_blank_custom_sql (@michellethomas)
### 0.25.1 (2018/05/14 16:07 +00:00)
- [#4959](https://github.com/apache/incubator-superset/pull/4959) [deps] force flask 1.0.0 (#4959) (@mistercrunch)
- [ad4912d](https://github.com/apache/incubator-superset/commit/ad4912d6012849eb900ac74fe05d1d3e368883c9) Allowing sqlExpression to be blank (@michellethomas)
- [#4990](https://github.com/apache/incubator-superset/pull/4990) expanding regex for automated columns (#4990) (@GabeLoins)
- [#4977](https://github.com/apache/incubator-superset/pull/4977) Merge pull request #4977 from timifasubaa/bump_pyhive_version (@timifasubaa)
- [6720255](https://github.com/apache/incubator-superset/commit/67202558681884e7a1a1f1ea2b09c629c347a320) bump pyhive version (@timifasubaa)
- [#4909](https://github.com/apache/incubator-superset/pull/4909) [Explore] Adding Adhoc Filters (#4909) (@GabeLoins)
- [#4927](https://github.com/apache/incubator-superset/pull/4927) [sql lab] Use context manager for sqllab sessions (#4927) (@grafke)
- [#4971](https://github.com/apache/incubator-superset/pull/4971) Fix templating in sqla datasource (#4971) (@villebro)
- [#4972](https://github.com/apache/incubator-superset/pull/4972) superset/import_dashboards.html: Update title, clean up html (#4972) (@sodevious)
- [#4943](https://github.com/apache/incubator-superset/pull/4943) [bugfix] handling UTF8 in Druid dimensions (#4943) (@mistercrunch)
- [#4740](https://github.com/apache/incubator-superset/pull/4740) Add extraction function support for Druid queries (#4740) (@jasnovak)
- [#4948](https://github.com/apache/incubator-superset/pull/4948) CHANGELOG for 0.25.0 (#4948) (@mistercrunch)
- [#4954](https://github.com/apache/incubator-superset/pull/4954) add 30 minutes support under time granularity (#4954) (@liyuance)
- [#4950](https://github.com/apache/incubator-superset/pull/4950) Support hours in relative time range selection (#4950) (@liyuance)
- [#4944](https://github.com/apache/incubator-superset/pull/4944) Move from deprecated flask-cache to flask-caching (#4944) (@mistercrunch)
- [#4946](https://github.com/apache/incubator-superset/pull/4946) Fix naming for geojson (#4946) (@hughhhh)
### 0.25.0 (2018/05/08 05:20 +00:00)
- [#4942](https://github.com/apache/incubator-superset/pull/4942) [docs] add entry for Hive in installation.rst (#4942) (@mistercrunch)
- [#4928](https://github.com/apache/incubator-superset/pull/4928) [sql lab] handle query stop race condition (#4928) (@mistercrunch)
- [#4930](https://github.com/apache/incubator-superset/pull/4930) Update installation.rst (#4930) (@vihar)
- [#4833](https://github.com/apache/incubator-superset/pull/4833) Merge pull request #4833 from timifasubaa/help_sqllab_forget_the_past (@timifasubaa)
- [ab958c6](https://github.com/apache/incubator-superset/commit/ab958c67e6b7fde14e3d79c535045ca87fc5b732) make queries older than 6 hours timeout (@timifasubaa)
- [#4939](https://github.com/apache/incubator-superset/pull/4939) Add Portugal to country_map visualization (#4939) (@joaomg)
- [#4938](https://github.com/apache/incubator-superset/pull/4938) add Airboxlab to Superset users list (#4938) (@antoine-galataud)
- [#4940](https://github.com/apache/incubator-superset/pull/4940) Add Windsor.ai to the list of organizations (#4940) (@octaviancorlade)
- [#4899](https://github.com/apache/incubator-superset/pull/4899) rm-slices (#4899) (@hughhhh)
- [#4887](https://github.com/apache/incubator-superset/pull/4887) [druid] Updating Druid refresh metadata tests (#4887) (@john-bodley)
- [#4900](https://github.com/apache/incubator-superset/pull/4900) Hide restricted ui elements, remove <br> from error message (#4900) (@jasnovak)
- [#4923](https://github.com/apache/incubator-superset/pull/4923) Install superset in Kubernetes with helm chart (#4923) (@cychiang)
- [#4925](https://github.com/apache/incubator-superset/pull/4925) Support Apache Kylin in EngineSpec (#4925) (@zhaoyongjie)
- [#4921](https://github.com/apache/incubator-superset/pull/4921) [bufix] filtered column was removed (#4921) (@mistercrunch)
- [#4917](https://github.com/apache/incubator-superset/pull/4917) Add doc entry for BigQuery support (#4917) (@mistercrunch)
- [#4918](https://github.com/apache/incubator-superset/pull/4918) Fix typos from linting (#4918) (@mistercrunch)
- [#4911](https://github.com/apache/incubator-superset/pull/4911) Fix for week_start_sunday and week_ending_saturday (#4911) (@betodealmeida)
- [#4908](https://github.com/apache/incubator-superset/pull/4908) Replace NaN/Infinity with null (#4908) (@betodealmeida)
- [#4913](https://github.com/apache/incubator-superset/pull/4913) Fix country_map visualization URL (#4913) (@mistercrunch)
- [#4883](https://github.com/apache/incubator-superset/pull/4883) Add note about 0.25.0 upgrade in UPDATING.md (#4883) (@mistercrunch)
- [#4897](https://github.com/apache/incubator-superset/pull/4897) Heatmap improvements (#4897) (@mistercrunch)
- [#4906](https://github.com/apache/incubator-superset/pull/4906) requirements: bump gunicorn to 19.8.0 (#4906) (@xrmx)
- [#4907](https://github.com/apache/incubator-superset/pull/4907) translations: rename pt_BR gettext files (#4907) (@xrmx)
- [#4884](https://github.com/apache/incubator-superset/pull/4884) [pylint] prepping for enabling pylint for non-errors (#4884) (@john-bodley)
- [#4901](https://github.com/apache/incubator-superset/pull/4901) Fix 'Uncaught TypeError: pe.clamp is not a function' (#4901) (@mistercrunch)
- [#4896](https://github.com/apache/incubator-superset/pull/4896) [sql lab] allow stoping 'pending' queries (#4896) (@mistercrunch)
- [#4886](https://github.com/apache/incubator-superset/pull/4886) remove hard code http scheme of short url #4656 (#4886) (@ripoul)
- [#4891](https://github.com/apache/incubator-superset/pull/4891) Allow limiting rows on Pivot Table (#4891) (@mistercrunch)
- [#4890](https://github.com/apache/incubator-superset/pull/4890) [bugfix] temporal columns with expression fail (#4890) (@mistercrunch)
- [#4882](https://github.com/apache/incubator-superset/pull/4882) Implement Snowflake engine with supported time grains (#4882) (@villebro)
- [#4841](https://github.com/apache/incubator-superset/pull/4841) Move a few JS files (#4841) (@mistercrunch)
- [#4872](https://github.com/apache/incubator-superset/pull/4872) Remove spurious "has" from README (#4872) (@davidthewatson)
- [#4869](https://github.com/apache/incubator-superset/pull/4869) remove DISTINCT ON statement (#4869) (@stillmatic)
- [#4866](https://github.com/apache/incubator-superset/pull/4866) [axis formatting] Override the valueformat to be percentage when contribution is selected (#4866) (@conglei)
- [#4836](https://github.com/apache/incubator-superset/pull/4836) Refactoring on exploreReducer.js (#4836) (@hughhhh)
- [#4856](https://github.com/apache/incubator-superset/pull/4856) Fix 'pip install .' (#4856) (@mistercrunch)
- [#4842](https://github.com/apache/incubator-superset/pull/4842) Safely passing data to d3.html (#4842) (@michellethomas)
- [#4867](https://github.com/apache/incubator-superset/pull/4867) Add Astronomer to list of organizations using Apache Superset (#4867) (@ryw)
- [#4843](https://github.com/apache/incubator-superset/pull/4843) [formats] add better defaults for time + number formatting (#4843) (@williaster)
- [#4853](https://github.com/apache/incubator-superset/pull/4853) [sql] Using read_sql_query instead of read_sql (#4853) (@john-bodley)
- [#4854](https://github.com/apache/incubator-superset/pull/4854) correct config language key to pt_BR (#4854) (@pld)
- [#4850](https://github.com/apache/incubator-superset/pull/4850) Remove obsolete TODO.md (#4850) (@mistercrunch)
- [#4844](https://github.com/apache/incubator-superset/pull/4844) [docs] minor file name and format fix for the setup document (#4844) (@sekikn)
- [#4821](https://github.com/apache/incubator-superset/pull/4821) Fix time granularity-related issues (#4821) (@mistercrunch)
- [#4829](https://github.com/apache/incubator-superset/pull/4829) ensure directory exists before saving csv file (#4829) (@timifasubaa)
- [e47d8a5](https://github.com/apache/incubator-superset/commit/e47d8a59a4773f29e62d9b33d7ad6ad2b343abdd) help sqllab forget the past (@timifasubaa)
- [#4651](https://github.com/apache/incubator-superset/pull/4651) [explore] proper filtering of NULLs and '' (#4651) (@mistercrunch)
- [#4835](https://github.com/apache/incubator-superset/pull/4835) [setup] Dropping 3.4 and adding 3.6 (#4835) (@john-bodley)
- [#4820](https://github.com/apache/incubator-superset/pull/4820) Moving some JS folders (#4820) (@mistercrunch)
- [#4828](https://github.com/apache/incubator-superset/pull/4828) [travis] Fixing environments (#4828) (@john-bodley)
- [#4831](https://github.com/apache/incubator-superset/pull/4831) db_engine_specs: use correct sqlite week time grain (#4831) (@xrmx)
- [#4825](https://github.com/apache/incubator-superset/pull/4825) Update README with fresher screenshots (#4825) (@mistercrunch)
- [#4736](https://github.com/apache/incubator-superset/pull/4736) [Explore] Adding custom expressions to adhoc metrics (#4736) (@GabeLoins)
- [#4817](https://github.com/apache/incubator-superset/pull/4817) [docs] many improvements to the documentation / cleanup (#4817) (@mistercrunch)
- [#4823](https://github.com/apache/incubator-superset/pull/4823) docs: use proper dialect for redshift (#4823) (@xrmx)
- [#4702](https://github.com/apache/incubator-superset/pull/4702) RFC: add logger that logs into browser console (#4702) (@betodealmeida)
- [#4798](https://github.com/apache/incubator-superset/pull/4798) [DeckGL] Added fixtures and Deck test (#4798) (@hughhhh)
- [#4800](https://github.com/apache/incubator-superset/pull/4800) Improve the calendar heatmap (#4800) (@mistercrunch)
- [#4746](https://github.com/apache/incubator-superset/pull/4746) Filtering out SQLLab views out of table list view by default (#4746) (@mistercrunch)
- [#4815](https://github.com/apache/incubator-superset/pull/4815) [migrations] Fixing issue #4810 (#4815) (@john-bodley)
- [#4807](https://github.com/apache/incubator-superset/pull/4807) Make the bottom margin a bit taller (#4807) (@mistercrunch)
- [#4801](https://github.com/apache/incubator-superset/pull/4801) [bugfix] dedup groupby columns in Deck visualizations (#4801) (@mistercrunch)
- [#4803](https://github.com/apache/incubator-superset/pull/4803) [explore] set working default for MetricsControl (#4803) (@mistercrunch)
- [#4806](https://github.com/apache/incubator-superset/pull/4806) [tests] cleaning up test configuration (#4806) (@john-bodley)
- [#4659](https://github.com/apache/incubator-superset/pull/4659) Adding tests for the time table viz (#4659) (@michellethomas)
- [#3658](https://github.com/apache/incubator-superset/pull/3658) BugFix(#3658) (#4133) (@hidetoshiito)
- [#4804](https://github.com/apache/incubator-superset/pull/4804) call next() the right way (#4804) (@timifasubaa)
- [#4808](https://github.com/apache/incubator-superset/pull/4808) filter recently viewed to just have explore and dashboard types (#4808) (@hughhhh)
- [#4525](https://github.com/apache/incubator-superset/pull/4525) adding option for multiple metrics, group by, opacity, legends (#4525) (@ArielStv)
- [#4587](https://github.com/apache/incubator-superset/pull/4587) [logs] Dropping dt column (#4587) (@john-bodley)
- [#4802](https://github.com/apache/incubator-superset/pull/4802) [homepage] Fix Favorites chart list (#4802) (@graceguo-supercat)
- [#4552](https://github.com/apache/incubator-superset/pull/4552) [travis/tox] Restructuring configuration (#4552) (@john-bodley)
- [#4799](https://github.com/apache/incubator-superset/pull/4799) [bugfix] when num_period_compare is not set (#4799) (@mistercrunch)
- [#4756](https://github.com/apache/incubator-superset/pull/4756) Improve xAxis ticks, thinner bottom margin (#4756) (@mistercrunch)
- [#4792](https://github.com/apache/incubator-superset/pull/4792) Add Ascendica Development in organizations list who use Superset (#4792) (@davidhassan)
- [#4774](https://github.com/apache/incubator-superset/pull/4774) [explore] forcing .1% number format when using 'Period Ratio' (#4774) (@mistercrunch)
- [#4647](https://github.com/apache/incubator-superset/pull/4647) Add play slider to screengrid (#4647) (@betodealmeida)
- [#4781](https://github.com/apache/incubator-superset/pull/4781) Rename UPDATING.MD to UPDATING.md (#4781) (@john-bodley)
- [#4765](https://github.com/apache/incubator-superset/pull/4765) [line] fix verbose names in time shift (#4765) (@mistercrunch)
- [#4777](https://github.com/apache/incubator-superset/pull/4777) [doc] module header for controls.jsx and visTypes.jsx (#4777) (@mistercrunch)
- [#4772](https://github.com/apache/incubator-superset/pull/4772) [dashboard] open in edit mode when adding a chart (#4772) (@mistercrunch)
- [#4768](https://github.com/apache/incubator-superset/pull/4768) [Bug fix] Resolving key conflicts in Timeseries Annotation Layer when key is a string (#4768) (@EvelynTurner)
- [#4767](https://github.com/apache/incubator-superset/pull/4767) Improve controls layout for Table visualization (#4767) (@mistercrunch)
- [#4755](https://github.com/apache/incubator-superset/pull/4755) Pass granularity from backend to frontend as ISO duration (#4755) (@betodealmeida)
- [#4773](https://github.com/apache/incubator-superset/pull/4773) Fix brush with annotations (#4773) (@betodealmeida)
- [#4778](https://github.com/apache/incubator-superset/pull/4778) Add notes to contrib file about testing and code coverage (#4778) (@ttannis)
- [#4766](https://github.com/apache/incubator-superset/pull/4766) [explore] set control default for *showminmax = false (#4766) (@mistercrunch)
- [#4673](https://github.com/apache/incubator-superset/pull/4673) Add context to templates / respect slice timeout (#4673) (@daoready)
- [#4761](https://github.com/apache/incubator-superset/pull/4761) [druid] Excluding refreshing verbose name (#4761) (@john-bodley)
- [#4754](https://github.com/apache/incubator-superset/pull/4754) [deck_multi] fixing issues with deck_multi (#4754) (@mistercrunch)
- [#4741](https://github.com/apache/incubator-superset/pull/4741) Set longer CSRF token duration (one week) (#4741) (@mistercrunch)
- [#4742](https://github.com/apache/incubator-superset/pull/4742) [sql lab] preserve schema through visualize flow (#4742) (@mistercrunch)
- [#4005](https://github.com/apache/incubator-superset/pull/4005) [BUGFIX]: JavaScripts max int is 2^53 - 1, longs are bigger (#4005) (@fabianmenges)
- [#4728](https://github.com/apache/incubator-superset/pull/4728) [sql_lab]Disabled run query button if sql query editor is empty (#4728) (@lprashant-94)
- [#4726](https://github.com/apache/incubator-superset/pull/4726) [bugfix] convert metrics to numeric in dataframe (#4726) (@mistercrunch)
- [#4648](https://github.com/apache/incubator-superset/pull/4648) Pass timezone to Druid Query granularity (#4648) (@ktong)
- [#4646](https://github.com/apache/incubator-superset/pull/4646) [BugFix] Allowing limit ordering by post-aggregation metrics (#4646) (@jeffreythewang)
- [#4603](https://github.com/apache/incubator-superset/pull/4603) [flask-appbuilder] Bumping version to 1.10.0 (#4603) (@john-bodley)
- [#4730](https://github.com/apache/incubator-superset/pull/4730) Fix deep equality logic (#4730) (@mistercrunch)
- [#4654](https://github.com/apache/incubator-superset/pull/4654) Expose metrics to JS (#4654) (@betodealmeida)
- [#4718](https://github.com/apache/incubator-superset/pull/4718) including auto generated avg metrics in druid (#4718) (@GabeLoins)
- [#4738](https://github.com/apache/incubator-superset/pull/4738) easier tab closing in sqllab (#4738) (@GabeLoins)
- [#4729](https://github.com/apache/incubator-superset/pull/4729) [explore] don't prompt to 'Run Query' on viewport change (#4729) (@mistercrunch)
- [#4720](https://github.com/apache/incubator-superset/pull/4720) Add '.1%' to number format options (#4720) (@mistercrunch)
- [#4717](https://github.com/apache/incubator-superset/pull/4717) [sqllab] fix data grid's instant search function (#4717) (@mistercrunch)
- [#4451](https://github.com/apache/incubator-superset/pull/4451) [cli] Deprecating gunicorn/flower dependencies (#4451) (@john-bodley)
- [#4689](https://github.com/apache/incubator-superset/pull/4689) Remove redundant has_access definition in superset (#4689) (@timifasubaa)
- [#4669](https://github.com/apache/incubator-superset/pull/4669) [sqllab] Using app context for Celery task (#4669) (@john-bodley)
- [#4693](https://github.com/apache/incubator-superset/pull/4693) Use 3 letters month prefix in default date format (#4693) (@mistercrunch)
- [#4719](https://github.com/apache/incubator-superset/pull/4719) [sql lab] ctrl-r hotkey should run latest SQL (#4719) (@mistercrunch)
- [#4714](https://github.com/apache/incubator-superset/pull/4714) Add missing perms to sql_lab role (#4714) (@mistercrunch)
- [#4709](https://github.com/apache/incubator-superset/pull/4709) Remove trailing '/' from Mailing list link in README file (#4709) (@Alagappan)
- [#4663](https://github.com/apache/incubator-superset/pull/4663) [Explore] Streamlined metric definitions for SQLA and Druid (#4663) (@GabeLoins)
- [#4703](https://github.com/apache/incubator-superset/pull/4703) Rename no_reload (#4703) (@betodealmeida)
- [#4700](https://github.com/apache/incubator-superset/pull/4700) Fixing label issue when columnType is null (#4700) (@michellethomas)
- [#4687](https://github.com/apache/incubator-superset/pull/4687) i18n(es_es) (#4687) (@joebordes)
- [#4565](https://github.com/apache/incubator-superset/pull/4565) [security] Refactor security code into SupersetSecurityManager (#4565) (@timifasubaa)
- [#4680](https://github.com/apache/incubator-superset/pull/4680) Hotkeys in SQL Lab (#4680) (@mistercrunch)
- [#4697](https://github.com/apache/incubator-superset/pull/4697) Docs on how to package a release + CHANGELOG for 0.24.0 (#4697) (@mistercrunch)
### 0.24.0 (2018/03/27 06:50 +00:00)
- [#4655](https://github.com/apache/incubator-superset/pull/4655) [druid] Updating refresh logic (#4655) (@john-bodley)
- [#4683](https://github.com/apache/incubator-superset/pull/4683) Fix bug with sorting columns in group by using time shift (#4683) (@michellethomas)
- [#4645](https://github.com/apache/incubator-superset/pull/4645) CRUD hints around SQL expressions (#4645) (@mistercrunch)
- [#4686](https://github.com/apache/incubator-superset/pull/4686) Preprocess SQL Lab query prior to checking syntax (#4686) (@villebro)
- [#4684](https://github.com/apache/incubator-superset/pull/4684) Fix up the Lyft color scheme (#4684) (@mistercrunch)
- [#4682](https://github.com/apache/incubator-superset/pull/4682) Add lyftColor to the game 💯 (#4682) (@hughhhh)
- [#4679](https://github.com/apache/incubator-superset/pull/4679) add yarn lock info to contributing.md (#4679) (@timifasubaa)
- [#4639](https://github.com/apache/incubator-superset/pull/4639) forms: make csv import parse dates accepts a list of columns (#4639) (@xrmx)
- [#4674](https://github.com/apache/incubator-superset/pull/4674) add yarn.lock (#4674) (@timifasubaa)
- [#4676](https://github.com/apache/incubator-superset/pull/4676) Fix setup.py, comma makes download_url a tuple (#4676) (@mistercrunch)
- [#4630](https://github.com/apache/incubator-superset/pull/4630) [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data (#4630) (@EvelynTurner)
- [#4670](https://github.com/apache/incubator-superset/pull/4670) Update messages.po (#4670) (@aleksi75)
- [#4664](https://github.com/apache/incubator-superset/pull/4664) fix: epoch_s and epoch_ms to date time (#4664) (@deatheyes)
- [#4660](https://github.com/apache/incubator-superset/pull/4660) Better default for MAPBOX_API_KEY (#4660) (@betodealmeida)
- [#4633](https://github.com/apache/incubator-superset/pull/4633) Cache the query string (#4633) (@jeffreythewang)
- [#4628](https://github.com/apache/incubator-superset/pull/4628) [sql lab] search to use fist&last name instead of username (#4628) (@mistercrunch)
- [#4608](https://github.com/apache/incubator-superset/pull/4608) Set filter_select_enabled default to True for Druid (#4608) (@mistercrunch)
- [#4555](https://github.com/apache/incubator-superset/pull/4555) [examples] let's not use 'date' as a col name (#4555) (@mistercrunch)
- [#4606](https://github.com/apache/incubator-superset/pull/4606) Use 'count' as the default metric when available (#4606) (@mistercrunch)
- [#4629](https://github.com/apache/incubator-superset/pull/4629) Fix sqllab numpy array (#4629) (@michellethomas)
- [#4601](https://github.com/apache/incubator-superset/pull/4601) Only show overlay if container is set (#4601) (@betodealmeida)
- [#4638](https://github.com/apache/incubator-superset/pull/4638) [cosmetic] removing table border in ModelView list (#4638) (@mistercrunch)
- [#4641](https://github.com/apache/incubator-superset/pull/4641) part1 (#4641) (@hughhhh)
- [#4632](https://github.com/apache/incubator-superset/pull/4632) Adding to list of generated-members to fix pylint errors (#4632) (@michellethomas)
- [#4566](https://github.com/apache/incubator-superset/pull/4566) Adding column type label to dropdowns (#4566) (@michellethomas)
- [#4627](https://github.com/apache/incubator-superset/pull/4627) Merge pull request #4627 from mistercrunch/fix_run_extra (@mistercrunch)
- [b906fec](https://github.com/apache/incubator-superset/commit/b906fece68bee8ccfba4d1f46da2221c37b5d0fa) Move run_extra_queries outsize of BaseViz init (@mistercrunch)
- [#4593](https://github.com/apache/incubator-superset/pull/4593) [sql lab] reduce the number of metadata calls when loading a table (#4593) (@mistercrunch)
- [#4620](https://github.com/apache/incubator-superset/pull/4620) Fix function name (#4620) (@betodealmeida)
- [#4622](https://github.com/apache/incubator-superset/pull/4622) Remove group by from deck.gl viz (#4622) (@betodealmeida)
- [#4617](https://github.com/apache/incubator-superset/pull/4617) Allowing config flag to turn off flask-compress (#4617) (@mistercrunch)
- [#4194](https://github.com/apache/incubator-superset/pull/4194) [bug fixes] annotations x domains, zeros in text (#4194) (@williaster)
- [#4621](https://github.com/apache/incubator-superset/pull/4621) fix mapbox viz (#4621) (@graceguo-supercat)
- [#4616](https://github.com/apache/incubator-superset/pull/4616) [contributing] Removing obsolete code climate reference (#4616) (@john-bodley)
- [#4572](https://github.com/apache/incubator-superset/pull/4572) Legend for deck.gl scatterplot (#4572) (@betodealmeida)
- [#4604](https://github.com/apache/incubator-superset/pull/4604) Show "Range Filter" by default (#4604) (@betodealmeida)
- [#4609](https://github.com/apache/incubator-superset/pull/4609) overriding annotation and layers control tab (#4609) (@GabeLoins)
- [#4607](https://github.com/apache/incubator-superset/pull/4607) [slice_json] pass slice id to get_form_data() (#4607) (@williaster)
- [#4590](https://github.com/apache/incubator-superset/pull/4590) Merge pull request #4590 from michellethomas/fixing_double_escape_presto (@michellethomas)
- [#4579](https://github.com/apache/incubator-superset/pull/4579) Merge pull request #4579 from michellethomas/removing_title_label (@michellethomas)
- [#4573](https://github.com/apache/incubator-superset/pull/4573) Merge pull request #4573 from john-bodley/john-bodley-cache-fix-datasource-uid (@john-bodley)
- [#4602](https://github.com/apache/incubator-superset/pull/4602) Merge pull request #4602 from john-bodley/john-bodley-druid-sync-fix-filter (@john-bodley)
### 0.23.3 (2018/03/13 17:14 +00:00)
- [#4581](https://github.com/apache/incubator-superset/pull/4581) timeseries_limit should not be required for phase 2 (#4581) (@michellethomas)
- [8829218](https://github.com/apache/incubator-superset/commit/882921825ca6508b598dee52c9dea73e54982b1b) Changing the title for explore pages (@michellethomas)
- [9604e1d](https://github.com/apache/incubator-superset/commit/9604e1dd1466521c0de4e81b53f2b1ae61b88942) [druid] Adding cluster filter for refresh
- [#4597](https://github.com/apache/incubator-superset/pull/4597) [BugFix] Resizing widgets problem #4596 (#4597) (@oxydash)
- [26257d9](https://github.com/apache/incubator-superset/commit/26257d94f5f43a5d3b745c1b08a29cc40980f211) [cache] Ensuring that the datasource UID is defined
- [#4514](https://github.com/apache/incubator-superset/pull/4514) Added new exception class and start of better exception/error handling (#4514) (@hughhhh)
- [#4599](https://github.com/apache/incubator-superset/pull/4599) Add ignore git @eaDir Synology directory (#4599) (@oxydash)
- [#4591](https://github.com/apache/incubator-superset/pull/4591) Add Aktia Bank in organizations list who use Superset (#4591) (@villebro)
- [#4594](https://github.com/apache/incubator-superset/pull/4594) docs: fixup code blocks rendering (#4594) (@xrmx)
- [e1af421](https://github.com/apache/incubator-superset/commit/e1af421f0c7426391e7124d1bae5aae9f8a49792) Removing escape_sql so we dont double escape (@michellethomas)
- [#4532](https://github.com/apache/incubator-superset/pull/4532) histograms: fixup left margin assigment (#4532) (@xrmx)
- [#4504](https://github.com/apache/incubator-superset/pull/4504) Return time in Druid scan (#4504) (@betodealmeida)
- [#4584](https://github.com/apache/incubator-superset/pull/4584) [sqllab] Added share button to bottom menu (#4584) (@hughhhh)
- [#4551](https://github.com/apache/incubator-superset/pull/4551) [sql lab] option to disable cross schema search (#4551) (@mistercrunch)
- [#4585](https://github.com/apache/incubator-superset/pull/4585) [sql lab] comment injection hook (#4585) (@mistercrunch)
- [#4586](https://github.com/apache/incubator-superset/pull/4586) [Translate] Added Full Russian Translation (#4586) (@oxydash)
- [#4582](https://github.com/apache/incubator-superset/pull/4582) Merge pull request #4582 from john-bodley/john-bodley-javascript-codecov (@john-bodley)
- [3fbadd6](https://github.com/apache/incubator-superset/commit/3fbadd68a471e4dcbdc8f0d37352af9c556e4e94) [code-climate] Deprecating Code Climate from JavaScript tests
- [#4570](https://github.com/apache/incubator-superset/pull/4570) Adding option to visualize negative values in Table view (#4570) (@tanvach)
- [402c7dd](https://github.com/apache/incubator-superset/commit/402c7ddb26399d4ef984bcf786e2514eaeb7f355) Removing [dashboard] and [slice] titles to show name (@michellethomas)
- [#4578](https://github.com/apache/incubator-superset/pull/4578) [Explore] Save custom url parameters when user save slices (#4578) (@graceguo-supercat)
- [#4550](https://github.com/apache/incubator-superset/pull/4550) Evelynturner/annotation timezone fix2 (#4550) (@EvelynTurner)
- [#4472](https://github.com/apache/incubator-superset/pull/4472) Basic Portuguese Brazilian Translation (#4472) (@AcNeidert)
- [#4562](https://github.com/apache/incubator-superset/pull/4562) [bug] Fix CSV upload feature for DB with password (#4562) (@ktravis)
- [#4563](https://github.com/apache/incubator-superset/pull/4563) [landscape.io] Deprecating .landscape.yml (#4563) (@john-bodley)
- [#4564](https://github.com/apache/incubator-superset/pull/4564) [requires.io] Removing obsolete requires.io link (#4564) (@john-bodley)
- [#4567](https://github.com/apache/incubator-superset/pull/4567) Merge pull request #4567 from john-bodley/john-bodley-payload-error-status-code (@john-bodley)
- [1e8cd0e](https://github.com/apache/incubator-superset/commit/1e8cd0e61e7bb442af7eab9997da487a82c91673) [payload] Set status code on error rather than query status
- [#4560](https://github.com/apache/incubator-superset/pull/4560) [bug] fix shortener url (#4560) (@graceguo-supercat)
- [#4505](https://github.com/apache/incubator-superset/pull/4505) Expose hook to inject database connection logic on the fly (#4505) (@mistercrunch)
- [#4543](https://github.com/apache/incubator-superset/pull/4543) Setting up compression using flask-compress (#4543) (@mistercrunch)
- [#4549](https://github.com/apache/incubator-superset/pull/4549) [bugfix] Fixing regression from #4500 (#4549) (@john-bodley)
- [#4553](https://github.com/apache/incubator-superset/pull/4553) [landing] Making Dashboards the first/default tab (#4553) (@john-bodley)
- [#4542](https://github.com/apache/incubator-superset/pull/4542) Removing files from MANIFEST.in (#4542) (@mistercrunch)
- [#4533](https://github.com/apache/incubator-superset/pull/4533) Merge pull request #4533 from john-bodley/john-bodley-replace-coveralls-with-codecov (@john-bodley)
- [#4530](https://github.com/apache/incubator-superset/pull/4530) [presto] Removing patched presto (#4530) (@john-bodley)
- [#4536](https://github.com/apache/incubator-superset/pull/4536) [dump.rdb] Removing rouge file (#4536) (@john-bodley)
- [#4541](https://github.com/apache/incubator-superset/pull/4541) Add ScopeAI (#4541) (@lucianoiscool)
### 0.23.1 (2018/03/06 06:41 +00:00)
- [#4534](https://github.com/apache/incubator-superset/pull/4534) Merge pull request #4534 from john-bodley/john-bodley-setup-url (@john-bodley)
### 0.23.0 (2018/03/06 00:59 +00:00)
- [#4500](https://github.com/apache/incubator-superset/pull/4500) Merge pull request #4500 from john-bodley/john-bodley-fix-pr-4396 (@john-bodley)
- [b01a9bb](https://github.com/apache/incubator-superset/commit/b01a9bba1f2043435e6fc1b189661e27b7dbbaea) [setup] Fixing URLs
- [#4538](https://github.com/apache/incubator-superset/pull/4538) Pass datasource as form_data param (#4538) (@Pek1s)
- [4f7258a](https://github.com/apache/incubator-superset/commit/4f7258aacaa5acf37c64769fa18da57f7dbd606e) [coverage] Replacing coveralls with codecov
- [#4513](https://github.com/apache/incubator-superset/pull/4513) Superset issue #4512: fixing histogram (#4513) (@ArielStv)
- [#4511](https://github.com/apache/incubator-superset/pull/4511) Fix how the annotation layer interpretes the timestamp string without timezone info; use it as UTC (#4511) (@EvelynTurner)
- [#4515](https://github.com/apache/incubator-superset/pull/4515) [dashboard] (#4515) (@graceguo-supercat)
- [#4482](https://github.com/apache/incubator-superset/pull/4482) chart style options get their own tab (#4482) (@GabeLoins)
- [#4487](https://github.com/apache/incubator-superset/pull/4487) Make margin width based on container width instead of slice width (#4487) (@jeffreythewang)
- [7440d34](https://github.com/apache/incubator-superset/commit/7440d34936784283f692a39402bcb11a9eeaa6a3) [payload] Fixing regression introducted in ##4396
- [#4486](https://github.com/apache/incubator-superset/pull/4486) [Explore] applying refresh chart overlay when chart is stale (#4486) (@GabeLoins)
- [#4480](https://github.com/apache/incubator-superset/pull/4480) Add https support for Druid (#4480) (@mistercrunch)
- [#4491](https://github.com/apache/incubator-superset/pull/4491) Introduce an onInit method for when a new viz_type is selected (#4491) (@mistercrunch)
- [#4488](https://github.com/apache/incubator-superset/pull/4488) fixes to csv - hive upload (#4488) (@timifasubaa)
- [#4469](https://github.com/apache/incubator-superset/pull/4469) check for access before requesting access (#4469) (@timifasubaa)
- [#4496](https://github.com/apache/incubator-superset/pull/4496) Change limit form 50k to 10k (#4496) (@mistercrunch)
- [#4490](https://github.com/apache/incubator-superset/pull/4490) [WiP] Cleanup & fix URL scheme for the explore view (#4490) (@mistercrunch)
- [#4485](https://github.com/apache/incubator-superset/pull/4485) [dashboard] Fix JS error when position_json data is empty (#4485) (@graceguo-supercat)
- [#4463](https://github.com/apache/incubator-superset/pull/4463) New Landing Page v1.0 (#4463) (@hughhhh)
- [#4459](https://github.com/apache/incubator-superset/pull/4459) [Explore] highlighting run query when chart is stale on explore view (#4459) (@GabeLoins)
- [#4467](https://github.com/apache/incubator-superset/pull/4467) [geo] add controls for minRadiusPixels and maxRadiusPixels in deck_scatter (#4467) (@mistercrunch)
- [#4477](https://github.com/apache/incubator-superset/pull/4477) [flake8] Adding flake8-coding (#4477) (@john-bodley)
- [#4478](https://github.com/apache/incubator-superset/pull/4478) add organization (#4478) (@ailurus1991)
- [#4466](https://github.com/apache/incubator-superset/pull/4466) [FilterBox] Make filterbox localizable (#4466) (@raffas)
- [#4476](https://github.com/apache/incubator-superset/pull/4476) [flake8] Adding future-import check (#4476) (@john-bodley)
- [#4474](https://github.com/apache/incubator-superset/pull/4474) [flake8] Fixing additional flake8 issue w/ the presence of ignore (#4474) (@john-bodley)
- [#4475](https://github.com/apache/incubator-superset/pull/4475) Pass param of limit for recent activity (#4475) (@hughhhh)
- [#4461](https://github.com/apache/incubator-superset/pull/4461) [hotfix] resolve utf-8 encoding issue in db migration (#4461) (@timifasubaa)
- [#4457](https://github.com/apache/incubator-superset/pull/4457) [explore] allow URL shortner even if no slice exist (#4457) (@mistercrunch)
- [#4400](https://github.com/apache/incubator-superset/pull/4400) Allowing config flag to turn off javascript controls (#4400) (@mistercrunch)
- [#4449](https://github.com/apache/incubator-superset/pull/4449) Make instant controls store state in URL (#4449) (@betodealmeida)
- [#4454](https://github.com/apache/incubator-superset/pull/4454) Make npm run dev-fast the default (#4454) (@mistercrunch)
- [#4456](https://github.com/apache/incubator-superset/pull/4456) [gitignore] Adding venv to .gitignore (#4456) (@GabeLoins)
- [#4444](https://github.com/apache/incubator-superset/pull/4444) A collection of bug fixes (#4444) (@mistercrunch)
- [#4455](https://github.com/apache/incubator-superset/pull/4455) fixing spacing issue on internationalization dropdown (#4455) (@GabeLoins)
- [#4452](https://github.com/apache/incubator-superset/pull/4452) [bugfix] address issue 4206 (#4452) (@mistercrunch)
- [#4446](https://github.com/apache/incubator-superset/pull/4446) for 48 columns layout, adjust default size and layout for newly added slices (#4446) (@graceguo-supercat)
- [#4413](https://github.com/apache/incubator-superset/pull/4413) Remove comments from queries in SQL Lab that break Explore view (#4413) (@villebro)
- [#4450](https://github.com/apache/incubator-superset/pull/4450) fix typo. "グルプ分け可能" => "グループ分け可能" (#4450) (@m4neda)
- [#4447](https://github.com/apache/incubator-superset/pull/4447) remove html tag in timeout error message (#4447) (@graceguo-supercat)
- [#4442](https://github.com/apache/incubator-superset/pull/4442) Improve default placeholder text on SelectControl (#4442) (@mistercrunch)
- [#4448](https://github.com/apache/incubator-superset/pull/4448) Removed double call to ConnectorRegistry.sources (#4448) (@villebro)
- [#4408](https://github.com/apache/incubator-superset/pull/4408) Add link on how to get permission to permission error (#4408) (@timifasubaa)
- [#4434](https://github.com/apache/incubator-superset/pull/4434) Added Example snippet for setting up Redis cache (#4434) (@hughhhh)
- [#4336](https://github.com/apache/incubator-superset/pull/4336) Play scrubber (#4336) (@betodealmeida)
- [#4430](https://github.com/apache/incubator-superset/pull/4430) Change current thumbnails to smaller ones. (#4430) (@mistercrunch)
- [#4436](https://github.com/apache/incubator-superset/pull/4436) Pass in cache timeout for async queries (#4436) (@jeffreythewang)
- [#4437](https://github.com/apache/incubator-superset/pull/4437) Fix separator visualization by propagating header height (#4437) (@jaylindquist)
- [#4438](https://github.com/apache/incubator-superset/pull/4438) Make chart title backgrounds transparent to prevent buttonface color in IE (#4438) (@jaylindquist)
- [#4416](https://github.com/apache/incubator-superset/pull/4416) [dashboard] more granular grid layout (#4416) (@mistercrunch)
- [#4432](https://github.com/apache/incubator-superset/pull/4432) Added check cache key util (#4432) (@hughhhh)
- [#4418](https://github.com/apache/incubator-superset/pull/4418) Updated Italian Translation (#4418) (@raffas)
- [#4431](https://github.com/apache/incubator-superset/pull/4431) Add .1s option to D3 Format dropdown (#4431) (@raffas)
- [#4405](https://github.com/apache/incubator-superset/pull/4405) Disable user access request (#4405) (@timifasubaa)
- [#4427](https://github.com/apache/incubator-superset/pull/4427) Bump dependencies with security issues (#4427) (@xrmx)
- [#3993](https://github.com/apache/incubator-superset/pull/3993) [Explore view] Use POST method for charting requests (#3993) (@graceguo-supercat)
- [#4410](https://github.com/apache/incubator-superset/pull/4410) Unset 'series limit' default from 50 to null (#4410) (@mistercrunch)
- [#4411](https://github.com/apache/incubator-superset/pull/4411) use full path in case of there are query params (#4411) (@Chun-LingChen)
- [#4389](https://github.com/apache/incubator-superset/pull/4389) [geo] introduce "Auto Zoom" control (#4389) (@mistercrunch)
- [#4401](https://github.com/apache/incubator-superset/pull/4401) [SqlLab] Fix a few UI issues (#4401) (@graceguo-supercat)
- [#4404](https://github.com/apache/incubator-superset/pull/4404) Check class name string instead of checking the instance (#4404) (@mxmzdlv)
- [#4380](https://github.com/apache/incubator-superset/pull/4380) [error handling] 'Time Comparison' query returns no data (#4380) (@mistercrunch)
- [#4383](https://github.com/apache/incubator-superset/pull/4383) Typo fix: dashbaord -> dashboard. (#4383) (@xiaohanyu)
- [#4396](https://github.com/apache/incubator-superset/pull/4396) Fix markup broken since cache related changes (#4396) (@mistercrunch)
- [#4178](https://github.com/apache/incubator-superset/pull/4178) Add PeopleDoc in organizations list who use superset (#4178) (@rodo)
- [#4390](https://github.com/apache/incubator-superset/pull/4390) Fix 4 security vulnerabilities (#4390) (@ddworken-sc)
- [#4349](https://github.com/apache/incubator-superset/pull/4349) Minor fixes to sunburst (#4349) (@mistercrunch)
- [#4346](https://github.com/apache/incubator-superset/pull/4346) Add permission checks to save_or_overwrite_slice (#4346) (@jaylindquist)
- [#4388](https://github.com/apache/incubator-superset/pull/4388) Remove permission check for frontend logging API (#4388) (@graceguo-supercat)
- [#4353](https://github.com/apache/incubator-superset/pull/4353) Superset issue #4323 (#4353) (@maver1ck)
- [#4377](https://github.com/apache/incubator-superset/pull/4377) Bump pydruid to 0.4.1 (#4377) (@mistercrunch)
- [#4359](https://github.com/apache/incubator-superset/pull/4359) [revert] Reverting PR #4062 (#4359) (@john-bodley)
- [#4316](https://github.com/apache/incubator-superset/pull/4316) Fix caching issues (#4316) (@mistercrunch)
- [#4372](https://github.com/apache/incubator-superset/pull/4372) Set default row_limit to 50k (#4372) (@mistercrunch)
- [#4363](https://github.com/apache/incubator-superset/pull/4363) [line] improve feature (#4363) (@mistercrunch)
- [#4373](https://github.com/apache/incubator-superset/pull/4373) Remove dangerouslySetInnerHTML in StackTraceMessage component (#4373) (@mistercrunch)
- [#4341](https://github.com/apache/incubator-superset/pull/4341) Bump python dependencies (#4341) (@mistercrunch)
- [#4333](https://github.com/apache/incubator-superset/pull/4333) Add hour grain to Sqlite (#4333) (@betodealmeida)
- [#4358](https://github.com/apache/incubator-superset/pull/4358) [druid] fix bug around handling NULLs (#4358) (@mistercrunch)
- [#4368](https://github.com/apache/incubator-superset/pull/4368) Add ipdb to dev dependencies. (#4368) (@xiaohanyu)
- [#4319](https://github.com/apache/incubator-superset/pull/4319) convert postgresql date_trunc() to UTC to prevent pandas error (#4319) (@habalux)
- [#4367](https://github.com/apache/incubator-superset/pull/4367) Remove useless empty npm-debug.log (#4367) (@xiaohanyu)
- [#4364](https://github.com/apache/incubator-superset/pull/4364) New options for european time format in in D3_TIME_FORMAT_OPTIONS (#4364) (@raffas)
- [#4344](https://github.com/apache/incubator-superset/pull/4344) Adding dashboard add view (#4344) (@michellethomas)
- [#4345](https://github.com/apache/incubator-superset/pull/4345) fix uri form data' (#4345) (@timifasubaa)
- [#4337](https://github.com/apache/incubator-superset/pull/4337) read query params for json in dashboard endpoint (#4337) (@hughhhh)
- [#4339](https://github.com/apache/incubator-superset/pull/4339) 1. fix check filters change logic (#4339) (@graceguo-supercat)
- [#4338](https://github.com/apache/incubator-superset/pull/4338) Fix the bug of charts/slices cannot be filtered by datasource name. (#4338) (@liutgnu)
- [#4298](https://github.com/apache/incubator-superset/pull/4298) Refactor import csv (#4298) (@timifasubaa)
- [#3676](https://github.com/apache/incubator-superset/pull/3676) [New Viz] Nightingale Rose Chart (#3676) (@Mogball)
- [#4241](https://github.com/apache/incubator-superset/pull/4241) [cli] permission cleanup on 'superset init' (#4241) (@mistercrunch)
- [#4224](https://github.com/apache/incubator-superset/pull/4224) [BugFix]: Creating a PostgresBaseEngineSpec so changes to the Postgre… (#4224) (@fabianmenges)
- [#4325](https://github.com/apache/incubator-superset/pull/4325) Bump pyrdruid to 0.4.0 (#4325) (@mistercrunch)
- [#4326](https://github.com/apache/incubator-superset/pull/4326) [explore] fix missing CacheLabel (#4326) (@mistercrunch)
- [#4321](https://github.com/apache/incubator-superset/pull/4321) Update installation.rst for Ubuntu 16.04 LTS (#4321) (@raffas)
- [#4322](https://github.com/apache/incubator-superset/pull/4322) [Bug] Resize should trigger chart re-render (#4322) (@graceguo-supercat)
- [#4301](https://github.com/apache/incubator-superset/pull/4301) [Explore] Fix Stop Query Button behavior (#4301) (@graceguo-supercat)
- [#4293](https://github.com/apache/incubator-superset/pull/4293) Refactoring deckgl (#4293) (@betodealmeida)
- [#4226](https://github.com/apache/incubator-superset/pull/4226) add frontend logging utility function (#4226) (@graceguo-supercat)
- [#4242](https://github.com/apache/incubator-superset/pull/4242) Added Path, Polygon, and Arcs to deckGL example dashboard (#4242) (@hughhhh)
- [#4260](https://github.com/apache/incubator-superset/pull/4260) Use the query_obj as the basis for the cache key (#4260) (@mistercrunch)
- [#4299](https://github.com/apache/incubator-superset/pull/4299) Bump sqlalchemy to 1.2.2 (#4299) (@xrmx)
- [#4303](https://github.com/apache/incubator-superset/pull/4303) Reverts apache/incubator-superset#4244 (#4303) (@mistercrunch)
- [#4291](https://github.com/apache/incubator-superset/pull/4291) Fixing json decode error on druiddatasourcemodelview/api/read (#4291) (@michellethomas)
- [#4272](https://github.com/apache/incubator-superset/pull/4272) [geo] Add JS controls to remaining layers (#4272) (@hughhhh)
- [#4261](https://github.com/apache/incubator-superset/pull/4261) Set point size control's default for deck_scatter viz (#4261) (@mistercrunch)
- [#4270](https://github.com/apache/incubator-superset/pull/4270) deck_multi to pass down filters to layers (#4270) (@mistercrunch)
- [#4275](https://github.com/apache/incubator-superset/pull/4275) Handle 'pd.Timestamp' when jsonifying (#4275) (@mistercrunch)
- [#4276](https://github.com/apache/incubator-superset/pull/4276) Prevent FilterBox extra query (#4276) (@mistercrunch)
- [#4277](https://github.com/apache/incubator-superset/pull/4277) Fix SUPERSET_WEBSERVER_TIMEOUT in VisualizeModal (#4277) (@mistercrunch)
- [#4262](https://github.com/apache/incubator-superset/pull/4262) [geo] JS function to receive the whole data array instead of individual object (#4262) (@mistercrunch)
- [#4265](https://github.com/apache/incubator-superset/pull/4265) Fix click on now in DateFilterControl (#4265) (@mistercrunch)
- [#4273](https://github.com/apache/incubator-superset/pull/4273) [explore] fix empty query message in 'View Query' (#4273) (@mistercrunch)
- [#4279](https://github.com/apache/incubator-superset/pull/4279) Always use fluid container for navbar. (#4279) (@xiaohanyu)
- [#4108](https://github.com/apache/incubator-superset/pull/4108) [BUGFIX]: Check datatype of results before converting to DataFrame (#4108) (@marcusianlevine)
- [#4243](https://github.com/apache/incubator-superset/pull/4243) Use json for imports and exports, not pickle (#4243) (@timifasubaa)
- [#4251](https://github.com/apache/incubator-superset/pull/4251) Using a NullPool for external connections by default (#4251) (@mistercrunch)
- [#4264](https://github.com/apache/incubator-superset/pull/4264) Set 'Range Filter' default to false (#4264) (@mistercrunch)
- [#4268](https://github.com/apache/incubator-superset/pull/4268) Fix heatmap tooltip disappears under the slice's header (#4268) (@abotero)
- [#4263](https://github.com/apache/incubator-superset/pull/4263) Bump flower==0.9.2 (#4263) (@mistercrunch)
- [#4240](https://github.com/apache/incubator-superset/pull/4240) [cache] Fixing json.dumps for timestamp (#4240) (@john-bodley)
- [#4246](https://github.com/apache/incubator-superset/pull/4246) [Sql Lab] Fix query results display at the bottom of screen (#4246) (@graceguo-supercat)
- [#4244](https://github.com/apache/incubator-superset/pull/4244) [Sql Lab] Fix Autorefresh component pulling not stopped. (#4244) (@graceguo-supercat)
- [#4237](https://github.com/apache/incubator-superset/pull/4237) Fix 'argument to reversed() must be a sequence' (#4237) (@mistercrunch)
- [#4227](https://github.com/apache/incubator-superset/pull/4227) Added DeckGL.Polygon Layer w/ JS controls (#4227) (@hughhhh)
- [#4235](https://github.com/apache/incubator-superset/pull/4235) remove setting spatial in DeckPathViz class (#4235) (@hughhhh)
- [#4229](https://github.com/apache/incubator-superset/pull/4229) Don't cache if there's no cache key (#4229) (@michellethomas)
- [#4234](https://github.com/apache/incubator-superset/pull/4234) add Ona as a user (#4234) (@pld)
- [#4220](https://github.com/apache/incubator-superset/pull/4220) Improve deck.gl GeoJSON visualization (#4220) (@mistercrunch)
- [#4221](https://github.com/apache/incubator-superset/pull/4221) [bugfix] time_pivot entry got missing in merge conflict (#4221) (@mistercrunch)
- [#4225](https://github.com/apache/incubator-superset/pull/4225) [bugfix] markup and iframe viz raise 'Empty query' (#4225) (@mistercrunch)
- [#4215](https://github.com/apache/incubator-superset/pull/4215) Fix tutorial doesn't match the current interface #4138 (#4215) (@zhaoyongjie)
- [#4217](https://github.com/apache/incubator-superset/pull/4217) templates: open code and documentation on a new tab (#4217) (@xrmx)
- [#4207](https://github.com/apache/incubator-superset/pull/4207) Adding limit to time_table viz to get druid query to work (#4207) (@michellethomas)
- [#4202](https://github.com/apache/incubator-superset/pull/4202) [line chart] fix time shift color (#4202) (@mistercrunch)
- [#4016](https://github.com/apache/incubator-superset/pull/4016) [cache] Using the query as the basis of the cache key (#4016) (@john-bodley)
- [#4203](https://github.com/apache/incubator-superset/pull/4203) [druid] fix 2 phases queries that specify 'Sort By' on 'Series limit' (#4203) (@mistercrunch)
- [#4200](https://github.com/apache/incubator-superset/pull/4200) [bugfix] dealing with DBAPIs that return unserilizable types (#4200) (@mistercrunch)
- [#4134](https://github.com/apache/incubator-superset/pull/4134) [Geo] Added DeckGL Arc Layer and Refactor on BaseDeckGL class (#4134) (@hughhhh)
- [#4126](https://github.com/apache/incubator-superset/pull/4126) Hanization (#4126) (@asdf2014)
- [#4114](https://github.com/apache/incubator-superset/pull/4114) Superset was using undefined metrics for specifying limits (#4114) (@bolkedebruin)
- [#4173](https://github.com/apache/incubator-superset/pull/4173) Using user-defined Javascript to customize geospatial visualization (#4173) (@mistercrunch)
- [#4183](https://github.com/apache/incubator-superset/pull/4183) [datasource editor] click checkbox creates metrics instantly (#4183) (@mistercrunch)
- [#4201](https://github.com/apache/incubator-superset/pull/4201) [explore] fix json highlighting for Druid queries (#4201) (@mistercrunch)
- [#4186](https://github.com/apache/incubator-superset/pull/4186) Sort out dependencies in travis/tox (#4186) (@mistercrunch)
- [#4184](https://github.com/apache/incubator-superset/pull/4184) Enable SQL syntax highlighting in View Query (#4184) (@betodealmeida)
- [#4187](https://github.com/apache/incubator-superset/pull/4187) [annotations] Fixing migration for annotation layers (#4187) (@john-bodley)
- [#4176](https://github.com/apache/incubator-superset/pull/4176) fix since or until is empty value #4170 (#4176) (@zhaoyongjie)
- [#4182](https://github.com/apache/incubator-superset/pull/4182) Moving the custom_password_store out of Database class (#4182) (@fabianmenges)
- [#4180](https://github.com/apache/incubator-superset/pull/4180) [security] Adding all derived FAB UserModelView views to admin only (#4180) (@john-bodley)
- [#4101](https://github.com/apache/incubator-superset/pull/4101) Don't use fully qualified column names in metric definitions (#4101) (@mistercrunch)
- [#4172](https://github.com/apache/incubator-superset/pull/4172) [FAB] configuring updating of permissions (#4172) (@john-bodley)
- [#4164](https://github.com/apache/incubator-superset/pull/4164) Allow alpha role import csv (#4164) (@timifasubaa)
- [#4147](https://github.com/apache/incubator-superset/pull/4147) Make Welcome page into a simple React app (#4147) (@mistercrunch)
- [#4156](https://github.com/apache/incubator-superset/pull/4156) Fix chart rendering error in time series table (#4156) (@graceguo-supercat)
- [#4157](https://github.com/apache/incubator-superset/pull/4157) [Bug] Closing change datasource modal throws JS error (#4157) (@graceguo-supercat)
- [#4162](https://github.com/apache/incubator-superset/pull/4162) Check for non-None database before using. (#4162) (@atronchi)
- [#4163](https://github.com/apache/incubator-superset/pull/4163) Druid support via SQLAlchemy (#4163) (@betodealmeida)
- [#4125](https://github.com/apache/incubator-superset/pull/4125) Fix invaild gitter url (#4125) (@asdf2014)
- [#4148](https://github.com/apache/incubator-superset/pull/4148) Adding Apache Kylin datasource for documentation (#4148) (@zhaoyongjie)
- [#4143](https://github.com/apache/incubator-superset/pull/4143) Create DATA_DIR after importing config (#4143) (@leorochael)
- [#4121](https://github.com/apache/incubator-superset/pull/4121) Fix USA's state geojson for 'Country Map' visualization (#4121) (@mistercrunch)
- [#4139](https://github.com/apache/incubator-superset/pull/4139) fix variable name (#4139) (@timifasubaa)
- [#4130](https://github.com/apache/incubator-superset/pull/4130) Remedy for dual axis annotation (#4130) (@Mogball)
- [#4104](https://github.com/apache/incubator-superset/pull/4104) [explore] add datasource metadata (#4104) (@mistercrunch)
- [#4135](https://github.com/apache/incubator-superset/pull/4135) better thumbnail for deck_geojson (#4135) (@hughhhh)
- [#4124](https://github.com/apache/incubator-superset/pull/4124) Added guard statement for spatial controls (#4124) (@hughhhh)
- [#4096](https://github.com/apache/incubator-superset/pull/4096) Multi layers DECK.GL visualization (#4096) (@mistercrunch)
- [#4116](https://github.com/apache/incubator-superset/pull/4116) Fix rst grammar problems (#4116) (@asdf2014)
- [#4118](https://github.com/apache/incubator-superset/pull/4118) Update UserInfo.jsx and set additional properties for react-gravatar (#4118) (@jpesculis)
- [#4097](https://github.com/apache/incubator-superset/pull/4097) [geo] Added DeckGL GeoJson layer (#4097) (@hughhhh)
- [#4076](https://github.com/apache/incubator-superset/pull/4076) Introduce Javascript controls (#4076) (@mistercrunch)
- [#4042](https://github.com/apache/incubator-superset/pull/4042) [Bugfix] Issues with merge_extra_filters (#4042) (#4091) (@nbonnotte)
- [#3996](https://github.com/apache/incubator-superset/pull/3996) [sql lab] deeper support for templating (#3996) (@mistercrunch)
- [#4067](https://github.com/apache/incubator-superset/pull/4067) [geo] add support for deck.gl's path layer (#4067) (@mistercrunch)
- [#4090](https://github.com/apache/incubator-superset/pull/4090) Using TextAreaControl for WHERE and HAVING clause section (#4090) (@mistercrunch)
- [#4071](https://github.com/apache/incubator-superset/pull/4071) Fix for SQL editor throwing can't deserialize google.cloud.bigquery._helpers.Row with BigQuery (#4071) (@kuriancheeramelil)
- [#4089](https://github.com/apache/incubator-superset/pull/4089) Bugfix: Druid having filters are broken (#4089) (@fabianmenges)
- [#4083](https://github.com/apache/incubator-superset/pull/4083) Event annotation should have min width (#4083) (@fabianmenges)
- [#4082](https://github.com/apache/incubator-superset/pull/4082) [bugfix] iframe and markup are broken (#4082) (@mistercrunch)
- [#4072](https://github.com/apache/incubator-superset/pull/4072) DB migration of annotation_layers on slice objects and slimming down annotation object. (#4072) (@fabianmenges)
- [#4073](https://github.com/apache/incubator-superset/pull/4073) [Bugfix] Issues with table filtering (#4073) (@Mogball)
- [#3530](https://github.com/apache/incubator-superset/pull/3530) [Feature] enhanced memoized on get_sqla_engine and other functions (#3530) (@Mogball)
- [#3518](https://github.com/apache/incubator-superset/pull/3518) Full Annotation Framework (#3518) (@fabianmenges)
- [#4065](https://github.com/apache/incubator-superset/pull/4065) #4058 Fix Oracle timestamps (Oracle "ORA-00907: missing right parenthesis" error) (#4065) (@nichobbs)
- [#4066](https://github.com/apache/incubator-superset/pull/4066) [geo] turn off renderTrigger on viewport control (#4066) (@mistercrunch)
- [#4062](https://github.com/apache/incubator-superset/pull/4062) [health] Adding DB check to /health (#4062) (@john-bodley)
- [#4059](https://github.com/apache/incubator-superset/pull/4059) Adding rowcount label to explore view header (#4059) (@mistercrunch)
- [#4032](https://github.com/apache/incubator-superset/pull/4032) [geo] provide more flexible Spatial controls (#4032) (@mistercrunch)
- [#4063](https://github.com/apache/incubator-superset/pull/4063) Add db_engine_spec for Druid (#4063) (@mistercrunch)
- [#4048](https://github.com/apache/incubator-superset/pull/4048) Bump dev version on trunk (#4048) (@mistercrunch)
- [#4045](https://github.com/apache/incubator-superset/pull/4045) Changelog for 0.21.0 (#4045) (@mistercrunch)
- [#4047](https://github.com/apache/incubator-superset/pull/4047) Fix the pypi build (#4047) (@mistercrunch)
- [#4049](https://github.com/apache/incubator-superset/pull/4049) Change reference for slices to chart (#4049) (@hughhhh)
### 0.22.1
Fixes 0.22.0

View File

@@ -49,7 +49,7 @@ If you are proposing a feature:
implement.
- Remember that this is a volunteer-driven project, and that
contributions are welcome :)
### Questions
There is a dedicated [tag](https://stackoverflow.com/questions/tagged/apache-superset) on [stackoverflow](https://stackoverflow.com/). Please use it when asking questions.
@@ -61,15 +61,19 @@ 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
2. Run `tox` and resolve all errors and test failures.
3. If the pull request adds functionality, the docs should be updated
as part of the same PR. Doc string are often sufficient, make
sure to follow the sphinx compatible standards.
3. The pull request should work for Python 2.7, and ideally python 3.4+.
4. The pull request should work for Python 2.7 and Python 3.6.
``from __future__ import`` will be required in every `.py` file soon.
4. Code will be reviewed by re running the unittests, flake8 and syntax
should be as rigorous as the core Python project.
5. Please rebase and resolve all conflicts before submitting.
6. If you are asked to update your pull request with some changes there's
5. If the pull request adds a Python dependency include it in `setup.py`
denoting any specific restrictions and in `requirements.txt` pinned to a
specific version which ensures that the application build is deterministic.
6. Please rebase and resolve all conflicts before submitting.
7. Please ensure the necessary checks pass and that code coverage does not
decrease.
8. If you are asked to update your pull request with some changes there's
no need to create a new one. Push your changes to the same branch.
## Documentation
@@ -98,11 +102,11 @@ to manage the Python packages you're about to install:
virtualenv superset-dev
source superset-dev/bin/activate
Finally, to make changes to the rst files and build the docs using Sphinx,
Finally, to make changes to the rst files and build the docs using Sphinx,
you'll need to install a handful of dependencies from the repo you cloned:
cd incubator-superset
pip install -r dev-reqs-for-docs.txt
pip install -r docs/requirements.txt
To get the feel for how to edit and build the docs, let's edit a file, build
the docs and see our changes in action. First, you'll want to
@@ -177,6 +181,7 @@ Check the [OS dependencies](https://superset.incubator.apache.org/installation.h
source env/bin/activate
# install for development
pip install -r requirements.txt
pip install -e .
# Create an admin user
@@ -195,6 +200,19 @@ Check the [OS dependencies](https://superset.incubator.apache.org/installation.h
superset runserver -d
### Logging to the browser console (Python 3 only)
When debugging your application, you can have the server logs sent directly to the browser console:
superset runserver -d --console-log
You can log anything to the browser console, including objects:
from superset import app
app.logger.error('An exception occurred!')
app.logger.info(form_data)
## Setting up the node / npm javascript environment
`superset/assets` contains all npm-managed, front end assets.
@@ -259,22 +277,33 @@ superset runserver -d -p 8081
npm run dev
```
#### Upgrading npm packages
Should you add or upgrade a npm package, which involves changing `package.json`, you'll need to re-run `yarn install` and push the newly generated `yarn.lock` file so we get the reproducible build. More information at (https://yarnpkg.com/blog/2016/11/24/lockfiles-for-all/)
## Testing
All tests are carried out in [tox](http://tox.readthedocs.io/en/latest/index.html)
a standardized testing framework mostly for Python (though we also used it for Javascript).
All python tests can be run with any of the tox [environments](http://tox.readthedocs.io/en/latest/example/basic.html#a-simple-tox-ini-default-environments), via,
Before running python unit tests, please setup local testing environment:
```
pip install -r dev-reqs.txt
```
tox -e <environment>
All python tests can be run with:
i.e.,
./run_tests.sh
Alternatively, you can run a specific test with:
tox -e py27
tox -e py36
./run_specific_test.sh tests.core_tests:CoreTests.test_function_name
Note that before running specific tests, you have to both setup the local testing environment and run all tests.
Alternatively, you can run all tests in a single file via,
tox -e <environment> -- tests/test_file.py
or for a specific test via,
tox -e <environment> -- tests/test_file.py:TestClassName.test_method_name
Note that the test environment uses a temporary directory for defining the
SQLite databases which will be cleared each time before the group of test
commands are invoked.
We use [Mocha](https://mochajs.org/), [Chai](http://chaijs.com/) and [Enzyme](http://airbnb.io/enzyme/) to test Javascript. Tests can be run with:
@@ -287,40 +316,17 @@ We use [Mocha](https://mochajs.org/), [Chai](http://chaijs.com/) and [Enzyme](ht
Lint the project with:
# for python
flake8
tox -e flake8
# for javascript
npm run lint
## Linting with codeclimate
Codeclimate is a service we use to measure code quality and test coverage. To get codeclimate's report on your branch, ideally before sending your PR, you can setup codeclimate against your Superset fork. After you push to your fork, you should be able to get the report at http://codeclimate.com . Alternatively, if you prefer to work locally, you can install the codeclimate cli tool.
*Install the codeclimate cli tool*
```
curl -L https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-`uname -s`-`uname -m` > /usr/local/bin/docker-machine && chmod +x /usr/local/bin/docker-machine
brew install docker
docker-machine create --driver virtual box default
docker-machine env default
eval "$(docker-machine env default)"
docker pull codeclimate/codeclimate
brew tap codeclimate/formulae
brew install codeclimate
```
*Run the lint command:*
```
docker-machine start
eval "$(docker-machine env default)”
codeclimate analyze
```
More info can be found here: https://docs.codeclimate.com/docs/open-source-free
tox -e eslint
## API documentation
Generate the documentation with:
cd docs && ./build.sh
pip install -r docs/requirements.txt
python setup.py build_sphinx
## CSS Themes
As part of the npm build process, CSS for Superset is compiled from `Less`, a dynamic stylesheet language.
@@ -411,10 +417,9 @@ https://github.com/apache/incubator-superset/pull/3013
Every once in a while we want to compile the documentation and publish it.
Here's how to do it.
.. code::
```
# install doc dependencies
pip install -r dev-reqs-for-docs.txt
pip install -r docs/requirements.txt
# build the docs
python setup.py build_sphinx
@@ -428,10 +433,93 @@ https://github.com/apache/incubator-superset/pull/3013
# copy
cp -r /tmp/tmp_superset_docs/ ~/incubator-superset-site.git/
# commit and push to `asf-site` branch
cd ~/incubator-superset-site.git/
git checkout asf-site
git add .
git commit -a -m "New doc version"
git push origin master
```
## Publishing a Pypi release
We create a branch that goes along each minor release `0.24`
and micro releases get corresponding tags as in `0.24.0`. Git history should
never be altered in release branches.
Bug fixes and security-related patches get cherry-picked
(usually from master) as in `git cherry-pick -x {SHA}`.
Following a set of cherries being picked, a release can be pushed to
Pypi as follows:
```
# branching off of master
git checkout -b 0.25
# cherry-picking a SHA
git cherry-pick -x f9d85bd2e1fd9bc233d19c76bed09467522b968a
# repeat with other SHAs, don't forget the -x
# source of thruth for release numbers live in package.json
vi superset/assets/package.json
# hard code release in file, commit to the release branch
git commit -a -m "0.25.0"
# create the release tag in the release branch
git tag 0.25.0
git push apache 0.25 --tags
# check travis to confirm the build succeeded as
# you shouldn't assume that a clean cherry will be clean
# when landing on a new sundae
# compile the JS, and push to pypi
# to run this part you'll need a pypi account and rights on the
# superset package. Committers that want to ship releases
# should have this access.
# You'll also need a `.pypirc` as specified here:
# http://peterdowns.com/posts/first-time-with-pypi.html
./pypi_push.sh
# publish an update to the CHANGELOG.md for the right version range
# looking the latest CHANGELOG entry for the second argument
./gen_changelog.sh 0.22.1 0.25.0
# this will overwrite the CHANGELOG.md with only the version range
# so you'll want to copy paste that on top of the previous CHANGELOG.md
# open a PR against `master`
```
In the future we'll start publishing release candidates for minor releases
only, but typically not for micro release.
The process will be similar to the process described above, expect the
tags will be formatted `0.25.0rc1`, `0.25.0rc2`, ..., until consensus
is reached.
We should also have a Github PR label process to target the proper
release, and tooling helping keeping track of all the cherries and
target versions.
For Apache releases, the process will be a bit heavier and should get
documented here. There will be extra steps for signing the binaries,
with a PGP key and providing MD5, Apache voting, as well as
publishing to Apache's SVN repository. View the ASF docs for more
information.
## Merging DB migrations
When 2 db migrations collide, you'll get an error message like this one:
```
alembic.util.exc.CommandError: Multiple head revisions are present for
given argument 'head'; please specify a specific target
revision, '<branchname>@head' to narrow to a specific head,
or 'heads' for all heads`
```
To fix it, first run `superset db heads`, this should list 2 or more
migration hashes. Then run
`superset db merge {PASTE_SHA1_HERE} {PASTE_SHA2_HERE}`. This will create
a new merge migration. You can then `superset db upgrade` to this new
checkpoint.

View File

@@ -1,10 +1,10 @@
include README.md
recursive-include superset/data *
recursive-include superset/migrations *
recursive-include superset/static *
recursive-exclude superset/static/docs *
recursive-exclude superset/static/assets/docs *
recursive-exclude superset/static/assets/visualizations *
recursive-exclude superset/static/assets/images/viz_thumbnails_large *
recursive-exclude superset/static/docs *
recursive-exclude superset/static/spec *
recursive-exclude superset/static/images/viz_thumbnails_large *
recursive-exclude superset/static/assets/node_modules *

View File

@@ -3,9 +3,8 @@ Superset
[![Build Status](https://travis-ci.org/apache/incubator-superset.svg?branch=master)](https://travis-ci.org/apache/incubator-superset)
[![PyPI version](https://badge.fury.io/py/superset.svg)](https://badge.fury.io/py/superset)
[![Coverage Status](https://coveralls.io/repos/apache/incubator-superset/badge.svg?branch=master&service=github)](https://coveralls.io/github/apache/incubator-superset?branch=master)
[![Coverage Status](https://codecov.io/github/apache/incubator-superset/coverage.svg?branch=master)](https://codecov.io/github/apache/incubator-superset)
[![PyPI](https://img.shields.io/pypi/pyversions/superset.svg?maxAge=2592000)](https://pypi.python.org/pypi/superset)
[![Requirements Status](https://requires.io/github/apache/incubator-superset/requirements.svg?branch=master)](https://requires.io/github/apache/incubator-superset/requirements/?branch=master)
[![Join the chat at https://gitter.im/airbnb/superset](https://badges.gitter.im/apache/incubator-superset.svg)](https://gitter.im/airbnb/superset?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Documentation](https://img.shields.io/badge/docs-apache.org-blue.svg)](https://superset.incubator.apache.org)
[![dependencies Status](https://david-dm.org/apache/incubator-superset/status.svg?path=superset/assets)](https://david-dm.org/apache/incubator-superset?path=superset/assets)
@@ -27,27 +26,23 @@ Screenshots & Gifs
**View Dashboards**
![superset-dashboard](https://cloud.githubusercontent.com/assets/130878/20371438/a703a2a0-ac19-11e6-80c4-00a47c2eb644.gif)
<kbd><img title="View Dashboards" src="https://raw.githubusercontent.com/apache/incubator-superset/master/superset/assets/images/screenshots/bank_dash.png"></kbd><br/>
<br/>
**Slice & dice your data**
**View/Edit a Slice**
<kbd><img title="Slice & dice your data" src="https://raw.githubusercontent.com/apache/incubator-superset/master/superset/assets/images/screenshots/explore.png"></kbd><br/>
![superset-explore-slice](https://cloud.githubusercontent.com/assets/130878/20372732/410392f4-ac22-11e6-9c6d-3ef512e81212.gif)
**Query and visualize your data with SQL Lab**
<br/>
<kbd><img title="SQL Lab" src="https://raw.githubusercontent.com/apache/incubator-superset/master/superset/assets/images/screenshots/sqllab.png"></kbd><br/>
**Query and Visualize with SQL Lab**
**Visualize geospatial data with deck.gl**
![superset-sql-lab-visualization](https://cloud.githubusercontent.com/assets/130878/20372911/7c3b3358-ac23-11e6-8f24-923ef1b35715.gif)
<kbd><img title="Geospatial" src="https://raw.githubusercontent.com/apache/incubator-superset/master/superset/assets/images/screenshots/deckgl_dash.png"></kbd><br/>
<br/>
**Choose from a wide array of visualizations**
![superset-dashboard-misc](https://cloud.githubusercontent.com/assets/130878/20234704/0f40778c-a835-11e6-9556-983a62ea061b.png)
![superset-edit-table](https://cloud.githubusercontent.com/assets/130878/20234705/0f415c88-a835-11e6-8b03-f7c35d56dd7d.png)
![superset-query-search](https://cloud.githubusercontent.com/assets/130878/20234706/0f430a10-a835-11e6-8a0d-8b26cc2e6bbd.png)
<kbd><img title="Visualizations" src="https://raw.githubusercontent.com/apache/incubator-superset/master/superset/assets/images/screenshots/visualizations.png"></kbd><br/>
Apache Superset
---------------
@@ -97,6 +92,7 @@ Superset can be used to visualize data out of most databases:
* MonetDB
* Snowflake
* Redshift
* Clickhouse
* **more!** look for the availability of a SQLAlchemy dialect for your database
to find out whether it will work with Superset
@@ -105,7 +101,7 @@ Druid!
------
On top of having the ability to query your relational databases,
Superset has ships with deep integration with Druid (a real time distributed
Superset ships with deep integration with Druid (a real time distributed
column-store). When querying Druid,
Superset can query humongous amounts of data on top of real time dataset.
Note that Superset does not require Druid in any way to function, it's simply
@@ -129,7 +125,7 @@ Installation & Configuration
Resources
-------------
* [Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org/)
* [Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org)
* [Gitter (live chat) Channel](https://gitter.im/airbnb/superset)
* [Docker image](https://hub.docker.com/r/amancevice/superset/) (community contributed)
* [Slides from Strata (March 2016)](https://drive.google.com/open?id=0B5PVE0gzO81oOVJkdF9aNkJMSmM)
@@ -152,10 +148,15 @@ the world know they are using Superset. Join our growing community!
- [AiHello](https://www.aihello.com)
- [Airbnb](https://github.com/airbnb)
- [Airboxlab](https://foobot.io)
- [Aktia Bank plc](https://www.aktia.com)
- [Amino](https://amino.com)
- [Ascendica Development](http://ascendicadevelopment.com)
- [Astronomer](https://www.astronomer.io)
- [Brilliant.org](https://brilliant.org/)
- [Capital Service S.A.](http://capitalservice.pl)
- [Clark.de](http://clark.de/)
- [CnOvit](http://www.cnovit.com/)
- [Digit Game Studios](https://www.digitgaming.com/)
- [Douban](https://www.douban.com/)
- [Endress+Hauser](http://www.endress.com/)
@@ -163,39 +164,24 @@ the world know they are using Superset. Join our growing community!
- [Faasos](http://faasos.com/)
- [GfK Data Lab](http://datalab.gfk.com)
- [Konfío](http://konfio.mx)
- [Lime](https://www.limebike.com/)
- [Lyft](https://www.lyft.com/)
- [Maieutical Labs](https://cloudschooling.it)
- [PeopleDoc](https://www.people-doc.com)
- [Maieutical Labs](https://maieuticallabs.it)
- [PeopleDoc](https://www.people-doc.com)
- [Ona](https://ona.io)
- [Pronto Tools](http://www.prontotools.io)
- [Qunar](https://www.qunar.com/)
- [ScopeAI](https://www.getscopeai.com)
- [Shopee](https://shopee.sg)
- [Shopkick](https://www.shopkick.com)
- [Tails.com](https://tails.com)
- [THEICONIC](http://theiconic.com.au/)
- [Tobii](http://www.tobii.com/)
- [Tooploox](https://www.tooploox.com/)
- [Twitter](https://twitter.com/)
- [Udemy](https://www.udemy.com/)
- [VIPKID](https://www.vipkid.com.cn/)
- [Windsor.ai](https://www.windsor.ai/)
- [Yahoo!](https://yahoo.com/)
- [Zaihang](http://www.zaih.com/)
- [Zalando](https://www.zalando.com)
More screenshots
----------------
![superset-security-menu](https://cloud.githubusercontent.com/assets/130878/20234707/0f565886-a835-11e6-9277-b4f5f4aa2fcc.png)
![superset-slice-bubble](https://cloud.githubusercontent.com/assets/130878/20234708/0f57f3d0-a835-11e6-8268-fcefe8f868c8.png)
![superset-slice-map](https://cloud.githubusercontent.com/assets/130878/20234709/0f5a5a44-a835-11e6-987a-1b6f8ac9922b.png)
![superset-slice-multiline](https://cloud.githubusercontent.com/assets/130878/20234710/0f632d68-a835-11e6-98d1-542dcb618193.png)
![superset-slice-sankey](https://cloud.githubusercontent.com/assets/130878/20234711/0f639136-a835-11e6-8721-fe5e48dab8e7.png)
![superset-slice-view](https://cloud.githubusercontent.com/assets/130878/20234712/0f63c4c6-a835-11e6-8595-6091a6428fa9.png)
![superset-sql-lab-2](https://cloud.githubusercontent.com/assets/130878/20234713/0f67b856-a835-11e6-9d50-7a52168f66fd.png)
![superset-sql-lab](https://cloud.githubusercontent.com/assets/130878/20234714/0f68f45a-a835-11e6-9467-f47ad0af7e79.png)

48
TODO.md
View File

@@ -1,48 +0,0 @@
# TODO
List of TODO items for Superset
## 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
Superset 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
* **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
* **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
* [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

47
UPDATING.md Normal file
View File

@@ -0,0 +1,47 @@
# Updating Superset
This file documents any backwards-incompatible changes in Superset and
assists people when migrating to a new version.
## Superset 0.27.0
* Superset 0.27 start to use nested layout for dashboard builder, which is not
backward-compatible with earlier dashboard grid data. We provide migration script
to automatically convert dashboard grid to nested layout data. To be safe, please
take a database backup prior to this upgrade. It's the only way people could go
back to a previous state.
## Superset 0.26.0
* Superset 0.26.0 deprecates the `superset worker` CLI, which is a simple
wrapper around the `celery worker` command, forcing you into crafting
your own native `celery worker` command. Your command should look something
like `celery worker --app=superset.sql_lab:celery_app --pool=gevent -Ofair`
## Superset 0.25.0
Superset 0.25.0 contains a backwards incompatible changes.
If you run a production system you should schedule downtime for this
upgrade.
The PRs bellow have more information around the breaking changes:
* [4587](https://github.com/apache/incubator-superset/pull/4587) : a backward
incompatible database migration that requires downtime. Once the
db migration succeeds, the web server needs to be restarted with the
new version. The previous version will fail
* [4565](https://github.com/apache/incubator-superset/pull/4565) : we've
changed the security model a bit where in the past you would have to
define your authentication scheme by inheriting from Flask
App Builder's
`from flask_appbuilder.security.sqla.manager import SecurityManager`,
you now have to derive Superset's
own derivative `superset.security.SupersetSecurityManager`. This
can provide you with more hooks to define your own logic and/or defer
permissions to another system as needed. For all implementation, you
simply have to import and derive `SupersetSecurityManager` in place
of the `SecurityManager`
* [4835](https://github.com/apache/incubator-superset/pull/4835) :
our `setup.py` now only pins versions where required, giving you
more latitude in using versions of libraries as needed. We do now
provide a `requirements.txt` with pinned versions if you want to run
the suggested versions that `Superset` builds and runs tests against.
Simply `pip install -r requirements.txt` in your build pipeline, likely
prior to `pip install superset==0.25.0`

0
babel-node Normal file
View File

60
contrib/docker/Dockerfile Normal file
View File

@@ -0,0 +1,60 @@
FROM python:3.6
MAINTAINER Xiao Hanyu <hanyu.xiao@shopeemobile.com>
# Add a normal user
RUN useradd --user-group --create-home --shell /bin/bash work
# Configure environment
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
HOME=/home/work
RUN apt-get update -y
# Install some dependencies
# http://airbnb.io/superset/installation.html#os-dependencies
RUN apt-get update -y && apt-get install -y build-essential libssl-dev \
libffi-dev python3-dev libsasl2-dev libldap2-dev
RUN apt-get install -y vim less postgresql-client redis-tools
# Install nodejs for custom build
# https://github.com/apache/incubator-superset/blob/master/docs/installation.rst#making-your-own-build
# https://nodejs.org/en/download/package-manager/
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get install -y nodejs
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -; \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list; \
apt-get update; \
apt-get install -y yarn
RUN mkdir $HOME/incubator-superset
WORKDIR $HOME/incubator-superset
COPY ./ ./
RUN pip install --upgrade setuptools pip
RUN pip install -e . && pip install -r requirements-dev.txt
ENV PATH=/home/work/incubator-superset/superset/bin:$PATH \
PYTHONPATH=./superset/:$PYTHONPATH
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
COPY ./superset ./superset
RUN chown -R work:work $HOME
USER work
RUN cd superset/assets && yarn
RUN cd superset/assets && npm run build
HEALTHCHECK CMD ["curl", "-f", "http://localhost:8088/health"]
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 8088

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -ex
docker build -t apache/incubator-superset -f Dockerfile .

View File

@@ -0,0 +1,48 @@
version: '3'
services:
redis:
image: redis:3.2
restart: always
ports:
- 6379:6379
volumes:
- redis:/data
postgres:
image: postgres:10
restart: always
environment:
POSTGRES_DB: superset
POSTGRES_PASSWORD: superset
POSTGRES_USER: superset
ports:
- 5432:5432
volumes:
- postgres:/var/lib/postgresql/data
superset:
image: apache/incubator-superset
restart: always
environment:
POSTGRES_DB: superset
POSTGRES_USER: superset
POSTGRES_PASSWORD: superset
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
REDIS_HOST: redis
REDIS_PORT: 6379
SUPERSET_ENV: local
ports:
- 8088:8088
command: "tail -f /dev/null"
depends_on:
- postgres
- redis
volumes:
- .:/home/work/incubator-superset
- superset-node-modules:/home/work/incubator-superset/superset/assets/node_modules
volumes:
postgres:
external: false
redis:
external: false
superset-node-modules:
external: false

View File

@@ -0,0 +1,12 @@
#!/bin/bash
set -ex
if [ "$#" -ne 0 ]; then
exec "$@"
elif [ "$SUPERSET_ENV" = "local" ]; then
superset runserver -d
elif [ "$SUPERSET_ENV" = "production" ]; then
superset runserver -a 0.0.0.0 -w $((2 * $(getconf _NPROCESSORS_ONLN) + 1))
else
superset --help
fi

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -ex
# Create an admin user (you will be prompted to set username, first and last name before setting a password)
fabmanager create-admin --app superset
# Initialize the database
superset db upgrade
# Load some data to play with
superset load_examples
# Create default roles and permissions
superset init
# Need to run `npm run build` when enter contains for first time
cd superset/assets && npm run build && cd ../../
# Start superset worker for SQL Lab
superset worker &
# To start a development web server, use the -d switch
superset runserver -d

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import os
def get_env_variable(var_name, default=None):
"""Get the environment variable or raise exception."""
try:
return os.environ[var_name]
except KeyError:
if default is not None:
return default
else:
error_msg = 'The environment variable {} was missing, abort...'\
.format(var_name)
raise EnvironmentError(error_msg)
POSTGRES_USER = get_env_variable('POSTGRES_USER')
POSTGRES_PASSWORD = get_env_variable('POSTGRES_PASSWORD')
POSTGRES_HOST = get_env_variable('POSTGRES_HOST')
POSTGRES_PORT = get_env_variable('POSTGRES_PORT')
POSTGRES_DB = get_env_variable('POSTGRES_DB')
# The SQLAlchemy connection string.
SQLALCHEMY_DATABASE_URI = 'postgresql://%s:%s@%s:%s/%s' % (POSTGRES_USER,
POSTGRES_PASSWORD,
POSTGRES_HOST,
POSTGRES_PORT,
POSTGRES_DB)
REDIS_HOST = get_env_variable('REDIS_HOST')
REDIS_PORT = get_env_variable('REDIS_PORT')
class CeleryConfig(object):
BROKER_URL = 'redis://%s:%s/0' % (REDIS_HOST, REDIS_PORT)
CELERY_IMPORTS = ('superset.sql_lab', )
CELERY_RESULT_BACKEND = 'redis://%s:%s/1' % (REDIS_HOST, REDIS_PORT)
CELERY_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}
CELERY_TASK_PROTOCOL = 1
CELERY_CONFIG = CeleryConfig

View File

@@ -1,3 +0,0 @@
sphinx
sphinx-rtd-theme
sphinxcontrib.youtube

View File

@@ -1,15 +0,0 @@
codeclimate-test-reporter
coveralls
flake8
flask_cors
ipdb
mock
mysqlclient
nose
psycopg2
pylint
pyyaml
redis
statsd
# Also install everything we need to build Sphinx docs
-r dev-reqs-for-docs.txt

View File

@@ -1 +0,0 @@
Folder containing the sphinx-generated documentation

View File

@@ -52,7 +52,7 @@ master_doc = 'index'
# General information about the project.
project = "Apache Superset"
copyright = None
copyright = 'Apache Software Foundation'
author = u'Maxime Beauchemin'
# The version info for the project you're documenting, acts as replacement for

View File

@@ -1,16 +1,14 @@
Druid
=====
Superset works well with Druid, though currently not all
advanced features out of Druid are covered. This page clarifies what is
covered and what isn't and explains how to use some of the features.
Superset has a native connector to Druid, and a majority of Druid's
features are accessible through Superset.
.. note ::
Currently Airbnb runs against Druid ``0.8.x`` and previous /
following versions are not tested against.
Supported
'''''''''
Druid now supports SQL and can be accessed through Superset's
SQLAlchemy connector. The long term vision is to deprecate
the Druid native REST connector and query Druid exclusively through
the SQL interface.
Aggregations
------------
@@ -28,7 +26,7 @@ element correspond to Druid aggregation definition. You can create your own
aggregations manually from the ``List Druid Metric`` tab following Druid
documentation.
.. image:: _static/img/druid_agg.png
.. image:: images/druid_agg.png
:scale: 50 %
Post-Aggregations
@@ -41,8 +39,9 @@ json post-aggregation definition (as specified in the Druid docs) in the
Json field.
Not yet supported
'''''''''''''''''
Unsupported Features
--------------------
- Regex filters
- Lookups / joins
.. note ::
Unclear at this point, this section of the documentation could use
some input.

View File

@@ -48,8 +48,10 @@ https://github.com/airbnb/superset/issues?q=label%3Aexample+is%3Aclosed
Can I upload and visualize csv data?
------------------------------------
Yes, using the ``Upload a CSV`` button under the ``Sources``
menu item. This brings up a form that allows you specify required information. After creating the table from CSV, it can then be loaded like any other on the ``Sources -> Tables``page.
Yes, using the ``Upload a CSV`` button under the ``Sources`` menu item.
This brings up a form that allows you specify required information.
After creating the table from CSV, it can then be loaded like any
other on the ``Sources -> Tables`` page.
Why are my queries timing out?
@@ -106,7 +108,7 @@ edit the ``JSON Metadata`` field, more specifically the
never be affected by any dashboard level filtering.
..code:: json
.. code-block:: json
{
"filter_immune_slices": [324, 65, 92],
@@ -141,7 +143,7 @@ to be refreshed - especially if some data is slow moving, or run heavy queries.
slices from the timed refresh process, add the ``timed_refresh_immune_slices`` key to the dashboard
``JSON Metadata`` field:
..code:: json
.. code-block:: json
{
"filter_immune_slices": [],
@@ -157,7 +159,7 @@ Slice refresh will also be staggered over the specified period. You can turn off
by setting the ``stagger_refresh`` to ``false`` and modify the stagger period by setting
``stagger_time`` to a value in milliseconds in the ``JSON Metadata`` field:
..code:: json
.. code-block:: json
{
"stagger_refresh": false,
@@ -168,7 +170,7 @@ Here, the entire dashboard will refresh at once if periodic refresh is on. The s
2.5 seconds is ignored.
Why does fabmanager or superset freezed/hung/not responding when started (my home directory is NFS mounted)?
-----------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
By default, superset creates and uses an sqlite database at ``~/.superset/superset.db``. Sqlite is known to `don't work well if used on NFS`__ due to broken file locking implementation on NFS.
__ https://www.sqlite.org/lockingv3.html
@@ -236,7 +238,7 @@ It is possible on a per-dashboard basis by providing a mapping of
labels to colors in the ``JSON Metadata`` attribute using the
``label_colors`` key.
..code:: json
.. code-block:: json
{
"label_colors": {

View File

@@ -1,89 +1,190 @@
Gallery
=======
Visualizations Gallery
======================
.. image:: _static/img/viz_thumbnails/line.png
:scale: 50 %
.. image:: images/viz_thumbnails/area.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/bubble.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/table.png
:scale: 50 %
.. image:: images/viz_thumbnails/bar.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/pie.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/bar.png
:scale: 50 %
.. image:: images/viz_thumbnails/big_number.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/world_map.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/sankey.png
:scale: 50 %
.. image:: images/viz_thumbnails/big_number_total.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/word_cloud.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/filter_box.png
:scale: 50 %
.. image:: images/viz_thumbnails/box_plot.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/pivot_table.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/directed_force.png
:scale: 50 %
.. image:: images/viz_thumbnails/bubble.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/compare.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/sunburst.png
:scale: 50 %
.. image:: images/viz_thumbnails/bullet.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/area.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/big_number.png
:scale: 50 %
.. image:: images/viz_thumbnails/cal_heatmap.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/big_number_total.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/bullet.png
:scale: 50 %
.. image:: images/viz_thumbnails/chord.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/dist_bar.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/heatmap.png
:scale: 50 %
.. image:: images/viz_thumbnails/compare.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/markup.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/para.png
:scale: 50 %
.. image:: images/viz_thumbnails/country_map.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/iframe.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/box_plot.png
:scale: 50 %
.. image:: images/viz_thumbnails/deck_arc.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/treemap.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/cal_heatmap.png
:scale: 50 %
.. image:: images/viz_thumbnails/deck_geojson.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/horizon.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/mapbox.png
:scale: 50 %
.. image:: images/viz_thumbnails/deck_grid.png
:scale: 25 %
.. image:: _static/img/viz_thumbnails/separator.png
:scale: 50 %
.. image:: _static/img/viz_thumbnails/histogram.png
:scale: 50 %
.. image:: images/viz_thumbnails/deck_hex.png
:scale: 25 %
.. image:: images/viz_thumbnails/deck_multi.png
:scale: 25 %
.. image:: images/viz_thumbnails/deck_path.png
:scale: 25 %
.. image:: images/viz_thumbnails/deck_polygon.png
:scale: 25 %
.. image:: images/viz_thumbnails/deck_scatter.png
:scale: 25 %
.. image:: images/viz_thumbnails/deck_screengrid.png
:scale: 25 %
.. image:: images/viz_thumbnails/directed_force.png
:scale: 25 %
.. image:: images/viz_thumbnails/dist_bar.png
:scale: 25 %
.. image:: images/viz_thumbnails/dual_line.png
:scale: 25 %
.. image:: images/viz_thumbnails/event_flow.png
:scale: 25 %
.. image:: images/viz_thumbnails/filter_box.png
:scale: 25 %
.. image:: images/viz_thumbnails/heatmap.png
:scale: 25 %
.. image:: images/viz_thumbnails/histogram.png
:scale: 25 %
.. image:: images/viz_thumbnails/horizon.png
:scale: 25 %
.. image:: images/viz_thumbnails/iframe.png
:scale: 25 %
.. image:: images/viz_thumbnails/line.png
:scale: 25 %
.. image:: images/viz_thumbnails/mapbox.png
:scale: 25 %
.. image:: images/viz_thumbnails/markup.png
:scale: 25 %
.. image:: images/viz_thumbnails/paired_ttest.png
:scale: 25 %
.. image:: images/viz_thumbnails/para.png
:scale: 25 %
.. image:: images/viz_thumbnails/partition.png
:scale: 25 %
.. image:: images/viz_thumbnails/pie.png
:scale: 25 %
.. image:: images/viz_thumbnails/pivot_table.png
:scale: 25 %
.. image:: images/viz_thumbnails/rose.png
:scale: 25 %
.. image:: images/viz_thumbnails/sankey.png
:scale: 25 %
.. image:: images/viz_thumbnails/separator.png
:scale: 25 %
.. image:: images/viz_thumbnails/sunburst.png
:scale: 25 %
.. image:: images/viz_thumbnails/table.png
:scale: 25 %
.. image:: images/viz_thumbnails/time_pivot.png
:scale: 25 %
.. image:: images/viz_thumbnails/time_table.png
:scale: 25 %
.. image:: images/viz_thumbnails/treemap.png
:scale: 25 %
.. image:: images/viz_thumbnails/word_cloud.png
:scale: 25 %
.. image:: images/viz_thumbnails/world_map.png
:scale: 25 %

1
docs/images Symbolic link
View File

@@ -0,0 +1 @@
../superset/assets/images/

View File

@@ -49,12 +49,17 @@ By default, default (null) values will be omitted. Use the ``-d`` flag to includ
If you want back references to be included (e.g. a column to include the table id
it belongs to) use the ``-b`` flag.
Alternatively you can export datasources using the UI: ::
Alternatively you can export datasources using the UI:
1. Open **Sources** -> **Databases** to export all tables associated to a single or multiple databases. (**Tables** for one or more tables, **Druid Clusters** for clusters, **Druid Datasources** for datasources)
2. Select the items you would like to export
3. Click **Actions** -> **Export to YAML**
4. If you want to import an item that you exported through the UI, you will need to nest it inside its parent element, e.g. a `database` needs to be nested under `databases` a `table` needs to be nested inside a `database` element.
1. Open **Sources** -> **Databases** to export all tables associated to a
single or multiple databases. (**Tables** for one or more tables,
**Druid Clusters** for clusters, **Druid Datasources** for datasources)
#. Select the items you would like to export
#. Click **Actions** -> **Export to YAML**
#. If you want to import an item that you exported through the UI, you
will need to nest it inside its parent element, e.g. a `database`
needs to be nested under `databases` a `table` needs to be
nested inside a `database` element.
Exporting the complete supported YAML schema
--------------------------------------------

View File

@@ -1,4 +1,4 @@
.. image:: _static/img/s.png
.. image:: images/s.png
Apache Superset (incubating)
''''''''''''''''''''''''''''
@@ -45,17 +45,22 @@ Features
- Integration with most SQL-speaking RDBMS through SQLAlchemy
- Deep integration with Druid.io
------
Screenshots
-----------
.. image:: https://camo.githubusercontent.com/82e264ef777ba06e1858766fe3b8817ee108eb7e/687474703a2f2f672e7265636f726469742e636f2f784658537661475574732e676966
.. image:: images/screenshots/bank_dash.png
------
.. image:: https://camo.githubusercontent.com/4991ff37a0005ea4e4267919a52786fda82d2d21/687474703a2f2f672e7265636f726469742e636f2f755a6767594f645235672e676966
.. image:: images/screenshots/explore.png
------
.. image:: https://camo.githubusercontent.com/a389af15ac1e32a3d0fee941b4c62c850b1d583b/687474703a2f2f672e7265636f726469742e636f2f55373046574c704c76682e676966
.. image:: images/screenshots/sqllab.png
------
.. image:: images/screenshots/deckgl_dash.png
------
@@ -70,10 +75,9 @@ Contents
tutorial
security
sqllab
visualization
videos
gallery
druid
misc
faq

View File

@@ -4,7 +4,7 @@ Installation & Configuration
Getting Started
---------------
Superset is tested against Python ``2.7`` and Python ``3.4``.
Superset is tested against Python ``2.7`` and Python ``3.6``.
Airbnb currently uses 2.7.* in production. We do not plan on supporting
Python ``2.6``.
@@ -35,6 +35,30 @@ The Superset web server and the Superset Celery workers (optional)
are stateless, so you can scale out by running on as many servers
as needed.
Start with Docker
-----------------
If you know docker, then you're lucky, we have shortcut road for you to
initialize development environment: ::
git clone https://github.com/apache/incubator-superset/
cd incubator-superset
cp contrib/docker/{docker-build.sh,docker-compose.yml,docker-entrypoint.sh,docker-init.sh,Dockerfile} .
cp contrib/docker/superset_config.py superset/
bash -x docker-build.sh
docker-compose up -d
docker-compose exec superset bash
bash docker-init.sh
After several minutes for superset initialization to finish, you can open
a browser and view `http://localhost:8088` to start your journey.
If you are attempting to build on a Mac and it exits with 137 you need to increase your docker resources.
OSX instructions: https://docs.docker.com/docker-for-mac/#advanced (Search for memory)
Or if you're curious and want to install superset from bottom up, then go
ahead.
OS dependencies
---------------
@@ -53,7 +77,7 @@ the required dependencies are installed: ::
sudo apt-get install build-essential libssl-dev libffi-dev python-dev python-pip libsasl2-dev libldap2-dev
**Ubuntu 16.04** If you have python3.5 installed alongside with python2.7, as is default on **Ubuntu 16.04 LTS**, run this command also
**Ubuntu 16.04** If you have python3.5 installed alongside with python2.7, as is default on **Ubuntu 16.04 LTS**, run this command also: ::
sudo apt-get install build-essential libssl-dev libffi-dev python3.5-dev python-pip libsasl2-dev libldap2-dev
@@ -125,11 +149,8 @@ Follow these few simple steps to install Superset.::
# Create default roles and permissions
superset init
# Start the web server on port 8088, use -p to bind to another port
superset runserver
# To start a development web server, use the -d switch
# superset runserver -d
# To start a development web server on port 8088, use -p to bind to another port
superset runserver -d
After installation, you should be able to point your browser to the right
@@ -147,12 +168,8 @@ Gunicorn, preferably in **async mode**, which allows for impressive
concurrency even and is fairly easy to install and configure. Please
refer to the
documentation of your preferred technology to set up this Flask WSGI
application in a way that works well in your environment.
While the `superset runserver` command act as an quick wrapper
around `gunicorn`, it doesn't expose all the options you may need,
so you'll want to craft your own `gunicorn` command in your production
environment. Here's an **async** setup known to work well: ::
application in a way that works well in your environment. Here's an **async**
setup known to work well in production: ::
 gunicorn \
-w 10 \
@@ -165,7 +182,7 @@ environment. Here's an **async** setup known to work well: ::
superset:app
Refer to the
[Gunicorn documentation](http://docs.gunicorn.org/en/stable/design.html)
`Gunicorn documentation <http://docs.gunicorn.org/en/stable/design.html>`_
for more information.
Note that *gunicorn* does not
@@ -173,6 +190,9 @@ work on Windows so the `superset runserver` command is not expected to work
in that context. Also note that the development web
server (`superset runserver -d`) is not intended for production use.
If not using gunicorn, you may want to disable the use of flask-compress
by setting `ENABLE_FLASK_COMPRESS = False` in your `superset_config.py`
Flask-AppBuilder Permissions
----------------------------
@@ -212,7 +232,7 @@ In case that the reverse proxy is used for providing ssl encryption,
an explicit definition of the `X-Forwarded-Proto` may be required.
For the Apache webserver this can be set as follows: ::
 RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Proto "https"
Configuration
-------------
@@ -225,7 +245,6 @@ of the parameters you can copy / paste in that configuration module: ::
# Superset specific config
#---------------------------------------------------------
ROW_LIMIT = 5000
SUPERSET_WORKERS = 4
SUPERSET_WEBSERVER_PORT = 8088
#---------------------------------------------------------
@@ -247,17 +266,29 @@ of the parameters you can copy / paste in that configuration module: ::
WTF_CSRF_ENABLED = True
# Add endpoints that need to be exempt from CSRF protection
WTF_CSRF_EXEMPT_LIST = []
# A CSRF token that expires in 1 year
WTF_CSRF_TIME_LIMIT = 60 * 60 * 24 * 365
# Set this API key to enable Mapbox visualizations
MAPBOX_API_KEY = ''
This file also allows you to define configuration parameters used by
Flask App Builder, the web framework used by Superset. Please consult
All the parameters and default values defined in
https://github.com/apache/incubator-superset/blob/master/superset/config.py
can be altered in your local ``superset_config.py`` .
Administrators will want to
read through the file to understand what can be configured locally
as well as the default values in place.
Since ``superset_config.py`` acts as a Flask configuration module, it
can be used to alter the settings Flask itself,
as well as Flask extensions like ``flask-wtf``, ``flask-cache``,
``flask-migrate``, and ``flask-appbuilder``. Flask App Builder, the web
framework used by Superset offers many configuration settings. Please consult
the `Flask App Builder Documentation
<http://flask-appbuilder.readthedocs.org/en/latest/config.html>`_
for more information on how to configure Superset.
for more information on how to configure it.
Please make sure to change:
Make sure to change:
* *SQLALCHEMY_DATABASE_URI*, by default it is stored at *~/.superset/superset.db*
* *SECRET_KEY*, to a long random string
@@ -287,11 +318,15 @@ Here's a list of some of the recommended packages.
+---------------+-------------------------------------+-------------------------------------------------+
| Presto | ``pip install pyhive`` | ``presto://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| Hive | ``pip install pyhive`` | ``hive://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| Oracle | ``pip install cx_Oracle`` | ``oracle://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| sqlite | | ``sqlite://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| Redshift | ``pip install sqlalchemy-redshift`` | ``postgresql+psycopg2://`` |
| Snowflake | ``pip install snowflake-sqlalchemy``| ``snowflake://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| Redshift | ``pip install sqlalchemy-redshift`` | ``redshift+psycopg2://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| MSSQL | ``pip install pymssql`` | ``mssql://`` |
+---------------+-------------------------------------+-------------------------------------------------+
@@ -303,6 +338,8 @@ Here's a list of some of the recommended packages.
+---------------+-------------------------------------+-------------------------------------------------+
| Athena | ``pip install "PyAthenaJDBC>1.0.9"``| ``awsathena+jdbc://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| Athena | ``pip install "PyAthena>1.2.0"`` | ``awsathena+rest://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| Vertica | ``pip install | ``vertica+vertica_python://`` |
| | sqlalchemy-vertica-python`` | |
+---------------+-------------------------------------+-------------------------------------------------+
@@ -311,6 +348,8 @@ Here's a list of some of the recommended packages.
+---------------+-------------------------------------+-------------------------------------------------+
| Kylin | ``pip install kylinpy`` | ``kylin://`` |
+---------------+-------------------------------------+-------------------------------------------------+
| BigQuery | ``pip install pybigquery`` | ``bigquery://`` |
+---------------+-------------------------------------+-------------------------------------------------+
Note that many other database are supported, the main criteria being the
existence of a functional SqlAlchemy dialect and Python driver. Googling
@@ -328,6 +367,29 @@ Where you need to escape/encode at least the s3_staging_dir, i.e., ::
s3://... -> s3%3A//...
You can also use `PyAthena` library(no java required) like this ::
awsathena+rest://{aws_access_key_id}:{aws_secret_access_key}@athena.{region_name}.amazonaws.com/{schema_name}?s3_staging_dir={s3_staging_dir}&...
See `PyAthena <https://github.com/laughingman7743/PyAthena#sqlalchemy>`_.
Snowflake
---------
The connection string for Snowflake looks like this ::
snowflake://{user}:{password}@{account}.{region}/{database}?role={role}&warehouse={warehouse}
The schema is not necessary in the connection string, as it is defined per table/query.
The role and warehouse can be omitted if defaults are defined for the user, i.e.
snowflake://{user}:{password}@{account}.{region}/{database}
Make sure the user has privileges to access and use all required
databases/schemas/tables/views/warehouses, as the Snowflake SQLAlchemy engine does
not test for user rights during engine creation.
See `Snowflake SQLAlchemy <https://github.com/snowflakedb/snowflake-sqlalchemy>`_.
Caching
-------
@@ -349,7 +411,7 @@ For setting your timeouts, this is done in the Superset metadata and goes
up the "timeout searchpath", from your slice configuration, to your
data source's configuration, to your database's and ultimately falls back
into your global default defined in ``CACHE_CONFIG``.
.. code-block:: python
CACHE_CONFIG = {
@@ -368,7 +430,7 @@ It is possible to tweak the database connection information using the
parameters exposed by SQLAlchemy. In the ``Database`` edit view, you will
find an ``extra`` field as a ``JSON`` blob.
.. image:: _static/img/tutorial/add_db.png
.. image:: images/tutorial/add_db.png
:scale: 30 %
This JSON string contains extra configuration elements. The ``engine_params``
@@ -404,6 +466,16 @@ in your config file to point to that function. ::
SQLALCHEMY_CUSTOM_PASSWORD_STORE = example_lookup_password
A common pattern is to use environment variables to make secrets available.
``SQLALCHEMY_CUSTOM_PASSWORD_STORE`` can also be used for that purpose. ::
def example_password_as_env_var(url):
# assuming the uri looks like
# mysql://localhost?superset_user:{SUPERSET_PASSWORD}
return url.password.format(os.environ)
SQLALCHEMY_CUSTOM_PASSWORD_STORE = example_password_as_env_var
SSL Access to databases
-----------------------
@@ -500,8 +572,8 @@ execute beyond the typical web request's timeout (30-60 seconds), it is
necessary to configure an asynchronous backend for Superset which consist of:
* one or many Superset worker (which is implemented as a Celery worker), and
can be started with the ``superset worker`` command, run
``superset worker --help`` to view the related options
can be started with the ``celery worker`` command, run
``celery worker --help`` to view the related options.
* a celery broker (message queue) for which we recommend using Redis
or RabbitMQ
* a results backend that defines where the worker will persist the query
@@ -521,6 +593,10 @@ have the same configuration.
CELERY_CONFIG = CeleryConfig
To start a Celery worker to leverage the configuration run: ::
celery worker --app=superset.sql_lab:celery_app --pool=gevent -Ofair
To setup a result backend, you need to pass an instance of a derivative
of ``werkzeug.contrib.cache.BaseCache`` to the ``RESULTS_BACKEND``
configuration key in your ``superset_config.py``. It's possible to use
@@ -561,6 +637,15 @@ in this dictionary are made available for users to use in their SQL.
}
Flower is a web based tool for monitoring the Celery cluster which you can
install from pip: ::
pip install flower
and run via: ::
celery flower --app=superset.sql_lab:celery_app
Making your own build
---------------------
@@ -588,7 +673,7 @@ at the ``/simple_page`` url. This can allow you to run other things such
as custom data visualization applications alongside Superset, on the
same server.
..code ::
.. code-block:: python
from flask import Blueprint
simple_page = Blueprint('simple_page', __name__,
@@ -609,10 +694,94 @@ are logged as well as key events like query start and end in SQL Lab.
To setup StatsD logging, it's a matter of configuring the logger in your
``superset_config.py``.
..code ::
.. code-block:: python
from superset.stats_logger import StatsdStatsLogger
STATS_LOGGER = StatsdStatsLogger(host='localhost', port=8125, prefix='superset')
Note that it's also possible to implement you own logger by deriving
``superset.stats_logger.BaseStatsLogger``.
Install Superset with helm in Kubernetes
--------------
You can install Superset into Kubernetes with Helm <https://helm.sh/>. The chart is
located in ``install/helm``.
To install Superset into your Kubernetes:
.. code-block:: bash
helm upgrade --install superset ./install/helm/superset
Note that the above command will install Superset into ``default`` namespace of your Kubernetes cluster.
Custom OAuth2 configuration
---------------------------
Beyond FAB supported providers (github, twitter, linkedin, google, azure), its easy to connect Superset with other OAuth2 Authorization Server implementations that supports "code" authorization.
The first step: Configure authorization in Superset ``superset_config.py``.
.. code-block:: python
AUTH_TYPE = AUTH_OAUTH
OAUTH_PROVIDERS = [
{ 'name':'egaSSO',
'token_key':'access_token', # Name of the token in the response of access_token_url
'icon':'fa-address-card', # Icon for the provider
'remote_app': {
'consumer_key':'myClientId', # Client Id (Identify Superset application)
'consumer_secret':'MySecret', # Secret for this Client Id (Identify Superset application)
'request_token_params':{
'scope': 'read' # Scope for the Authorization
},
'access_token_method':'POST', # HTTP Method to call access_token_url
'access_token_params':{ # Additional parameters for calls to access_token_url
'client_id':'myClientId'
},
'access_token_headers':{ # Additional headers for calls to access_token_url
'Authorization': 'Basic Base64EncodedClientIdAndSecret'
},
'base_url':'https://myAuthorizationServer/oauth2AuthorizationServer/',
'access_token_url':'https://myAuthorizationServer/oauth2AuthorizationServer/token',
'authorize_url':'https://myAuthorizationServer/oauth2AuthorizationServer/authorize'
}
}
]
# Will allow user self registration, allowing to create Flask users from Authorized User
AUTH_USER_REGISTRATION = True
# The default user self registration role
AUTH_USER_REGISTRATION_ROLE = "Public"
Second step: Create a `CustomSsoSecurityManager` that extends `SupersetSecurityManager` and overrides `oauth_user_info`:
.. code-block:: python
from superset.security import SupersetSecurityManager
class CustomSsoSecurityManager(SupersetSecurityManager):
def oauth_user_info(self, provider, response=None):
logging.debug("Oauth2 provider: {0}.".format(provider))
if provider == 'egaSSO':
# As example, this line request a GET to base_url + '/' + userDetails with Bearer Authentication,
# and expects that authorization server checks the token, and response with user details
me = self.appbuilder.sm.oauth_remotes[provider].get('userDetails').data
logging.debug("user_data: {0}".format(me))
return { 'name' : me['name'], 'email' : me['email'], 'id' : me['user_name'], 'username' : me['user_name'], 'first_name':'', 'last_name':''}
...
This file must be located at the same directory than ``superset_config.py`` with the name ``custom_sso_security_manager.py``.
Then we can add this two lines to ``superset_config.py``:
.. code-block:: python
from custom_sso_security_manager import CustomSsoSecurityManager
CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager

10
docs/misc.rst Normal file
View File

@@ -0,0 +1,10 @@
Misc
----
.. toctree::
:maxdepth: 2
visualization
videos
import_export_datasources

3
docs/requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
sphinx==1.7.1
sphinx-rtd-theme==0.2.4
sphinxcontrib.youtube==0.1.2

View File

@@ -70,7 +70,7 @@ sure the users with limited access have [only] the Gamma role assigned to
them. Second, create a new role (``Menu -> Security -> List Roles``) and
click the ``+`` sign.
.. image:: _static/img/create_role.png
.. image:: images/create_role.png
:scale: 50 %
This new window allows you to give this new role a name, attribute it to users

View File

@@ -4,6 +4,11 @@ SQL Lab
SQL Lab is a modern, feature-rich SQL IDE written in
`React <https://facebook.github.io/react/>`_.
------
.. image:: images/screenshots/sqllab.png
------
Feature Overview
----------------

View File

@@ -1,31 +1,31 @@
Tutorial for Superset Administrators
====================================
Tutorial - Creating your first dashboard
========================================
This tutorial targets a Superset administrator: someone configuring Superset
for an organization on behalf of users. We'll show you how to connect Superset
to a new database and configure a table in that database for analysis. You'll
also explore the data you've exposed and add a visualization to a dashboard
This tutorial targets someone who wants to create charts and dashboards
in Superset. We'll show you how to connect Superset
to a new database and configure a table in that database for analysis. You'll
also explore the data you've exposed and add a visualization to a dashboard
so that you get a feel for the end-to-end user experience.
Connecting to a new database
----------------------------
We assume you already have a database configured and can connect to it from the
instance on which youre running Superset. If youre just testing Superset and
want to explore sample data, you can load some
instance on which youre running Superset. If youre just testing Superset and
want to explore sample data, you can load some
`sample PostgreSQL datasets <https://wiki.postgresql.org/wiki/Sample_Databases>`_
into a fresh DB, or configure the
into a fresh DB, or configure the
`example weather data <https://github.com/dylburger/noaa-ghcn-weather-data>`_
we use here.
Under the **Sources** menu, select the *Databases* option:
.. image:: _static/img/tutorial/tutorial_01_sources_database.png
.. image:: images/tutorial/tutorial_01_sources_database.png
:scale: 70%
On the resulting page, click on the green plus sign, near the top right:
.. image:: _static/img/tutorial/tutorial_02_add_database.png
.. image:: images/tutorial/tutorial_02_add_database.png
:scale: 70%
You can configure a number of advanced options on this page, but for
@@ -33,12 +33,12 @@ this walkthrough, youll only need to do **two things**:
1. Name your database connection:
.. image:: _static/img/tutorial/tutorial_03_database_name.png
.. image:: images/tutorial/tutorial_03_database_name.png
:scale: 70%
2. Provide the SQLAlchemy Connection URI and test the connection:
.. image:: _static/img/tutorial/tutorial_04_sqlalchemy_connection_string.png
.. image:: images/tutorial/tutorial_04_sqlalchemy_connection_string.png
:scale: 70%
This example shows the connection string for our test weather database.
@@ -51,19 +51,19 @@ Click the **Test Connection** button to confirm things work end to end.
Once Superset can successfully connect and authenticate, you should see
a popup like this:
.. image:: _static/img/tutorial/tutorial_05_connection_popup.png
.. image:: images/tutorial/tutorial_05_connection_popup.png
:scale: 50%
Moreover, you should also see the list of tables Superset can read from
the schema youre connected to, at the bottom of the page:
.. image:: _static/img/tutorial/tutorial_06_list_of_tables.png
.. image:: images/tutorial/tutorial_06_list_of_tables.png
:scale: 70%
If the connection looks good, save the configuration by clicking the **Save**
button at the bottom of the page:
.. image:: _static/img/tutorial/tutorial_07_save_button.png
.. image:: images/tutorial/tutorial_07_save_button.png
:scale: 70%
Adding a new table
@@ -74,25 +74,25 @@ to Superset that youd like to query.
Under the **Sources** menu, select the *Tables* option:
.. image:: _static/img/tutorial/tutorial_08_sources_tables.png
.. image:: images/tutorial/tutorial_08_sources_tables.png
:scale: 70%
On the resulting page, click on the green plus sign, near the top left:
.. image:: _static/img/tutorial/tutorial_09_add_new_table.png
.. image:: images/tutorial/tutorial_09_add_new_table.png
:scale: 70%
You only need a few pieces of information to add a new table to Superset:
* The name of the table
.. image:: _static/img/tutorial/tutorial_10_table_name.png
.. image:: images/tutorial/tutorial_10_table_name.png
:scale: 70%
* The target database from the **Database** drop-down menu (i.e. the one
you just added above)
.. image:: _static/img/tutorial/tutorial_11_choose_db.png
.. image:: images/tutorial/tutorial_11_choose_db.png
:scale: 70%
* Optionally, the database schema. If the table exists in the “default” schema
@@ -101,13 +101,13 @@ You only need a few pieces of information to add a new table to Superset:
Click on the **Save** button to save the configuration:
.. image:: _static/img/tutorial/tutorial_07_save_button.png
.. image:: images/tutorial/tutorial_07_save_button.png
:scale: 70%
When redirected back to the list of tables, you should see a message indicating
that your table was created:
.. image:: _static/img/tutorial/tutorial_12_table_creation_success_msg.png
.. image:: images/tutorial/tutorial_12_table_creation_success_msg.png
:scale: 70%
This message also directs you to edit the table configuration. Well edit a limited
@@ -116,7 +116,7 @@ a more advanced tutorial.
Click on the edit button next to the table youve created:
.. image:: _static/img/tutorial/tutorial_13_edit_table_config.png
.. image:: images/tutorial/tutorial_13_edit_table_config.png
:scale: 70%
On the resulting page, click on the **List Table Column** tab. Here, youll define the
@@ -136,7 +136,7 @@ Heres how weve configured fields for the weather data. Even for measures l
weather measurements (precipitation, snowfall, etc.), its ideal to group and filter
by these values:
.. image:: _static/img/tutorial/tutorial_14_field_config.png
.. image:: images/tutorial/tutorial_14_field_config.png
As with the configurations above, click the **Save** button to save these settings.
@@ -146,17 +146,17 @@ Exploring your data
To start exploring your data, simply click on the table name you just created in
the list of available tables:
.. image:: _static/img/tutorial/tutorial_15_click_table_name.png
.. image:: images/tutorial/tutorial_15_click_table_name.png
By default, youll be presented with a Table View:
.. image:: _static/img/tutorial/tutorial_16_datasource_chart_type.png
.. image:: images/tutorial/tutorial_16_datasource_chart_type.png
Lets walk through a basic query to get the count of all records in our table.
First, well need to change the **Since** filter to capture the range of our data.
You can use simple phrases to apply these filters, like "3 years ago":
.. image:: _static/img/tutorial/tutorial_17_choose_time_range.png
.. image:: images/tutorial/tutorial_17_choose_time_range.png
The upper limit for time, the **Until** filter, defaults to "now", which may or may
not be what you want.
@@ -164,25 +164,25 @@ not be what you want.
Look for the Metrics section under the **GROUP BY** header, and start typing "Count"
- youll see a list of metrics matching what you type:
.. image:: _static/img/tutorial/tutorial_18_choose_metric.png
.. image:: images/tutorial/tutorial_18_choose_metric.png
Select the *COUNT(\*)* metric, then click the green **Query** button near the top
of the explore:
.. image:: _static/img/tutorial/tutorial_19_click_query.png
.. image:: images/tutorial/tutorial_19_click_query.png
Youll see your results in the table:
.. image:: _static/img/tutorial/tutorial_20_count_star_result.png
.. image:: images/tutorial/tutorial_20_count_star_result.png
Lets group this by the *weather_description* field to get the count of records by
the type of weather recorded by adding it to the *Group by* section:
.. image:: _static/img/tutorial/tutorial_21_group_by.png
.. image:: images/tutorial/tutorial_21_group_by.png
and run the query:
.. image:: _static/img/tutorial/tutorial_22_group_by_result.png
.. image:: images/tutorial/tutorial_22_group_by_result.png
Lets find a more useful data point: the top 10 times and places that recorded the
highest temperature in 2015.
@@ -190,11 +190,11 @@ highest temperature in 2015.
We replace *weather_description* with *latitude*, *longitude* and *measurement_date* in the
*Group by* section:
.. image:: _static/img/tutorial/tutorial_23_group_by_more_dimensions.png
.. image:: images/tutorial/tutorial_23_group_by_more_dimensions.png
And replace *COUNT(\*)* with *max__measurement_flag*:
.. image:: _static/img/tutorial/tutorial_24_max_metric.png
.. image:: images/tutorial/tutorial_24_max_metric.png
The *max__measurement_flag* metric was created when we checked the box under **Max** and
next to the *measurement_flag* field, indicating that this field was numeric and that
@@ -206,16 +206,16 @@ precipitation and temperature). Therefore, we must filter our query only on reco
where the *weather_description* is equal to "Maximum temperature", which we do in
the **Filters** section at the bottom of the explore:
.. image:: _static/img/tutorial/tutorial_25_max_temp_filter.png
.. image:: images/tutorial/tutorial_25_max_temp_filter.png
Finally, since we only care about the top 10 measurements, we limit our results to
10 records using the *Row limit* option under the **Options** header:
.. image:: _static/img/tutorial/tutorial_26_row_limit.png
.. image:: images/tutorial/tutorial_26_row_limit.png
We click **Query** and get the following results:
.. image:: _static/img/tutorial/tutorial_27_top_10_max_temps.png
.. image:: images/tutorial/tutorial_27_top_10_max_temps.png
In this dataset, the maximum temperature is recorded in tenths of a degree Celsius.
The top value of 1370, measured in the middle of Nevada, is equal to 137 C, or roughly
@@ -240,20 +240,20 @@ a dashboard.
We change the Chart Type to "Distribution - Bar Chart":
.. image:: _static/img/tutorial/tutorial_28_bar_chart.png
.. image:: images/tutorial/tutorial_28_bar_chart.png
Our filter on Maximum temperature measurements was retained, but the query and
formatting options are dependent on the chart type, so youll have to set the
values again:
.. image:: _static/img/tutorial/tutorial_29_bar_chart_series_metrics.png
.. image:: images/tutorial/tutorial_29_bar_chart_series_metrics.png
You should note the extensive formatting options for this chart: the ability to
set axis labels, margins, ticks, etc. To make the data presentable to a broad
audience, youll want to apply many of these to slices that end up in dashboards.
For now, though, we run our query and get the following chart:
.. image:: _static/img/tutorial/tutorial_30_bar_chart_results.png
.. image:: images/tutorial/tutorial_30_bar_chart_results.png
:scale: 70%
Creating a slice and dashboard
@@ -265,39 +265,39 @@ a saved query is called a **Slice**.
To create a slice, click the **Save as** button near the top-left of the
explore:
.. image:: _static/img/tutorial/tutorial_19_click_query.png
.. image:: images/tutorial/tutorial_19_click_query.png
A popup should appear, asking you to name the slice, and optionally add it to a
dashboard. Since we havent yet created any dashboards, we can create one and
immediately add our slice to it. Lets do it:
.. image:: _static/img/tutorial/tutorial_31_save_slice_to_dashboard.png
.. image:: images/tutorial/tutorial_31_save_slice_to_dashboard.png
:scale: 70%
Click Save, which will direct you back to your original query. We see that
our slice and dashboard were successfully created:
.. image:: _static/img/tutorial/tutorial_32_save_slice_confirmation.png
.. image:: images/tutorial/tutorial_32_save_slice_confirmation.png
:scale: 70%
Lets check out our new dashboard. We click on the **Dashboards** menu:
.. image:: _static/img/tutorial/tutorial_33_dashboard.png
.. image:: images/tutorial/tutorial_33_dashboard.png
and find the dashboard we just created:
.. image:: _static/img/tutorial/tutorial_34_weather_dashboard.png
.. image:: images/tutorial/tutorial_34_weather_dashboard.png
Things seemed to have worked - our slice is here!
.. image:: _static/img/tutorial/tutorial_35_slice_on_dashboard.png
.. image:: images/tutorial/tutorial_35_slice_on_dashboard.png
:scale: 70%
But its a bit smaller than we might like. Luckily, you can adjust the size
of slices in a dashboard by clicking, holding and dragging the bottom-right
corner to your desired dimensions:
.. image:: _static/img/tutorial/tutorial_36_adjust_dimensions.gif
.. image:: images/tutorial/tutorial_36_adjust_dimensions.gif
:scale: 120%
After adjusting the size, youll be asked to click on the icon near the

View File

@@ -1,54 +1,5 @@
Videos
======
Here is a collection of short videos showing different aspect
of Superset.
Quick Intro
'''''''''''
This video demonstrates how Superset works at a high level, it shows how
to navigate through datasets and dashboards that are already available.
.. youtube:: https://www.youtube.com/watch?v=3Txm_nj_R7M
Dashboard Creation
''''''''''''''''''
This video walk you through the creation of a simple dashboard as a
collection of data slices.
- Coming soon!
Dashboard Filtering
'''''''''''''''''''
This video shows how to create dynamic filters on dashboards, how to
immunize certain widgets from being affected by filters.
- Coming soon!
Customize CSS and dashboard themes
''''''''''''''''''''''''''''''''''
A quick walkthrough on how to apply existing CSS templates, alter them and
create new ones.
- Coming soon!
Slice Annotations
'''''''''''''''''
A short video on how to annotate your charts, the markdown language and
to toggle them on dashboards.
- Coming soon!
Adding a Table
''''''''''''''
This videos shows you how to expose a new table in Superset, and how to
define the semantics on how this can be accessed by others in the ``Explore``
and ``Dashboard`` views.
- Coming soon!
Define SQL Expressions
''''''''''''''''''''''
A walkthrough on how to create your own derived dimensions and metrics.
- Coming soon!
.. note ::
This section of the documentation has yet to be filled in.

View File

@@ -1735,7 +1735,7 @@ To add a new country in country map tools, we need follow next steps :
7. Add your country in component 'select_country'
Example :
.. code:: python
.. code-block:: javascript
select_country: {
type: 'SelectControl',

BIN
dump.rdb

Binary file not shown.

View File

@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

View File

@@ -0,0 +1,9 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: superset
maintainers:
- name: Chuan-Yen Chiang
email: cychiang0823@gmail.com
url: https://github.com/cychiang
version: 0.1.0

View File

@@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "superset.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "superset.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "superset.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "superset.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

View File

@@ -0,0 +1,32 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "superset.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "superset.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "superset.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: superset-configmap
labels:
app: {{ template "superset.name" . }}
chart: {{ template "superset.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
{{ (.Files.Glob "config/*").AsConfig | indent 2 }}

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "superset.fullname" . }}
labels:
app: {{ template "superset.name" . }}
chart: {{ template "superset.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "superset.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "superset.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: superset-config
mountPath: /etc/superset/
ports:
- name: http
containerPort: 8088
protocol: TCP
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
volumes:
- name: "superset-config"
configMap:
name: superset-configmap

View File

@@ -0,0 +1,38 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "superset.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "superset.name" . }}
chart: {{ template "superset.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}

View File

@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "superset.fullname" . }}
labels:
app: {{ template "superset.name" . }}
chart: {{ template "superset.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app: {{ template "superset.name" . }}
release: {{ .Release.Name }}

View File

@@ -0,0 +1,45 @@
# Default values for superset.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: amancevice/superset
tag: latest
pullPolicy: IfNotPresent
service:
type: NodePort
port: 8088
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- chart-example.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}

View File

@@ -1,2 +0,0 @@
#!/bin/bash
pylint superset --errors-only

View File

@@ -3,5 +3,6 @@ rm superset/assets/dist/*
cd superset/assets/
npm run build
cd ../..
python setup.py sdist upload
python setup.py sdist
echo "RUN: twine upload dist/superset-{VERSION}.tar.gz"

16
requirements-dev.txt Normal file
View File

@@ -0,0 +1,16 @@
console_log==0.2.10
flake8-coding==1.3.0
flake8-commas==2.0.0
flake8-future-import==0.4.5
flake8-import-order==0.18
flake8-quotes==1.0.0
flake8==3.5.0
flask-cors==3.0.3
ipdb==0.11
mysqlclient==1.3.12
psycopg2-binary==2.7.5
pycodestyle==2.3.1
pylint==1.9.2
redis==2.10.6
statsd==3.2.2
tox==3.1.2

42
requirements.txt Normal file
View File

@@ -0,0 +1,42 @@
bleach==2.1.2
boto3==1.4.7
botocore==1.7.48
celery==4.2.0
colorama==0.3.9
cryptography==1.9
flask==0.12.2
flask-appbuilder==1.10.0
flask-caching==1.4.0
flask-compress==1.4.0
flask-migrate==2.1.1
flask-wtf==0.14.2
flower==0.9.2
future==0.16.0
geopy==1.11.0
gunicorn==19.8.0
humanize==0.5.1
idna==2.6
isodate==0.6.0
markdown==2.6.11
pandas==0.23.1
parsedatetime==2.0.0
pathlib2==2.3.0
polyline==1.3.2
pydruid==0.4.4
pyhive==0.5.1
python-dateutil==2.6.1
python-geohash==0.8.5
pyyaml==3.12
requests==2.18.4
simplejson==3.15.0
six==1.11.0
sqlalchemy==1.2.2
sqlalchemy-utils==0.32.21
sqlparse==0.2.4
tableschema==1.1.0
thrift==0.11.0
thrift-sasl==0.3.0
unicodecsv==0.14.1
unidecode==1.0.22
contextlib2==0.5.5

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
echo $DB
rm -f .coverage
export SUPERSET_CONFIG=tests.superset_test_config
set -e
superset/bin/superset version -v
export SOLO_TEST=1
# e.g. tests.core_tests:CoreTests.test_templated_sql_json
nosetests $1

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
echo $DB
rm ~/.superset/unittests.db
rm ~/.superset/celerydb.sqlite
rm ~/.superset/celery_results.sqlite
rm -f .coverage
export SUPERSET_CONFIG=tests.superset_test_config
set -e
superset/bin/superset db upgrade
superset/bin/superset version -v
python setup.py nosetests
if [ "$CI" = "true" ] ; then
coveralls
fi

View File

@@ -1,3 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from collections import defaultdict
from superset import sm

View File

@@ -10,16 +10,16 @@ license = Apache License, Version 2.0
packages = superset
[build_sphinx]
source-dir = docs/
build-dir = docs/_build
all_files = 1
source-dir = docs
build-dir = docs/_build
all_files = 1
[upload_sphinx]
upload-dir = docs/_build/html
[nosetests]
verbosity=3
detailed-errors=1
with-coverage=1
nocapture=1
cover-package=superset
verbosity = 3
detailed-errors = 1
with-coverage = 1
nocapture = 1
cover-package = superset

105
setup.py
View File

@@ -1,3 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import io
import json
import os
import subprocess
@@ -10,11 +17,14 @@ PACKAGE_FILE = os.path.join(PACKAGE_DIR, 'package.json')
with open(PACKAGE_FILE) as package_file:
version_string = json.load(package_file)['version']
with io.open('README.md', encoding='utf-8') as f:
long_description = f.read()
def get_git_sha():
try:
s = str(subprocess.check_output(['git', 'rev-parse', 'HEAD']))
return s.strip()
s = subprocess.check_output(['git', 'rev-parse', 'HEAD'])
return s.decode().strip()
except Exception:
return ''
@@ -36,70 +46,71 @@ with open(os.path.join(PACKAGE_DIR, 'version_info.json'), 'w') as version_file:
setup(
name='superset',
description=(
'A interactive data visualization platform build on SqlAlchemy '
'and druid.io'),
'A modern, enterprise-ready business intelligence web application'),
long_description=long_description,
long_description_content_type='text/markdown',
version=version_string,
packages=find_packages(),
include_package_data=True,
zip_safe=False,
scripts=['superset/bin/superset'],
install_requires=[
'boto3>=1.4.6',
'celery==4.1.0',
'colorama==0.3.9',
'cryptography==1.9',
'flask==0.12.2',
'flask-appbuilder==1.9.6',
'flask-cache==0.13.1',
'flask-migrate==2.1.1',
'flask-script==2.0.6',
'flask-sqlalchemy==2.1',
'flask-testing==0.7.1',
'flask-wtf==0.14.2',
'flower==0.9.2',
'bleach',
'boto3==1.4.7',
'botocore>=1.7.0, <1.8.0',
'celery>=4.2.0',
'colorama',
'contextlib2',
'cryptography',
'flask<1.0.0',
'flask-appbuilder==1.10.0', # known db migration with 1.11+
'flask-caching',
'flask-compress',
'flask-migrate',
'flask-wtf',
'flower', # deprecated
'future>=0.16.0, <0.17',
'python-geohash==0.8.5',
'humanize==0.5.1',
'gunicorn==19.7.1',
'idna==2.6',
'markdown==2.6.11',
'pandas==0.22.0',
'parsedatetime==2.0.0',
'pathlib2==2.3.0',
'polyline==1.3.2',
'pydruid==0.4.1',
'PyHive>=0.4.0',
'python-dateutil==2.6.1',
'geopy',
'gunicorn', # deprecated
'humanize',
'idna',
'isodate',
'markdown',
'pandas>=0.18.0',
'parsedatetime',
'pathlib2',
'polyline',
'pydruid>=0.4.3',
'pyhive>=0.4.0',
'python-dateutil',
'python-geohash',
'pyyaml>=3.11',
'requests==2.18.4',
'simplejson==3.13.2',
'six==1.11.0',
'sqlalchemy==1.2.2',
'sqlalchemy-utils==0.32.21',
'sqlparse==0.2.4',
'requests',
'simplejson>=3.15.0',
'six',
'sqlalchemy',
'sqlalchemy-utils',
'sqlparse',
'tableschema',
'thrift>=0.9.3',
'thrift-sasl>=0.2.1',
'unicodecsv',
'unidecode>=0.04.21',
'bleach==2.1.2',
],
extras_require={
'cors': ['Flask-Cors>=2.0.0'],
'cors': ['flask-cors>=2.0.0'],
'console_log': ['console_log==0.2.10'],
},
tests_require=[
'codeclimate-test-reporter',
'coverage',
'mock',
'nose',
'redis',
],
author='Maxime Beauchemin',
author_email='maximebeauchemin@gmail.com',
url='https://github.com/airbnb/superset',
url='https://github.com/apache/incubator-superset',
download_url=(
'https://github.com/airbnb/superset/tarball/' + version_string),
'https://github.com'
'/apache/incubator-superset/tarball/' + version_string
),
classifiers=[
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
)

View File

@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# pylint: disable=C,R,W
"""Package's main module!"""
from __future__ import absolute_import
from __future__ import division
@@ -12,12 +14,14 @@ import os
from flask import Flask, redirect
from flask_appbuilder import AppBuilder, IndexView, SQLA
from flask_appbuilder.baseviews import expose
from flask_compress import Compress
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect
from werkzeug.contrib.fixers import ProxyFix
from superset import config, utils
from superset.connectors.connector_registry import ConnectorRegistry
from superset import utils, config # noqa
from superset.security import SupersetSecurityManager
APP_DIR = os.path.dirname(__file__)
CONFIG_MODULE = os.environ.get('SUPERSET_CONFIG', 'superset.config')
@@ -43,23 +47,37 @@ def parse_manifest_json():
global manifest
try:
with open(MANIFEST_FILE, 'r') as f:
manifest = json.load(f)
# the manifest inclues non-entry files
# we only need entries in templates
full_manifest = json.load(f)
manifest = full_manifest.get('entrypoints', {})
except Exception:
pass
def get_manifest_file(filename):
def get_js_manifest_files(filename):
if app.debug:
parse_manifest_json()
return '/static/assets/dist/' + manifest.get(filename, '')
entry_files = manifest.get(filename, {})
return entry_files.get('js', [])
def get_css_manifest_files(filename):
if app.debug:
parse_manifest_json()
entry_files = manifest.get(filename, {})
return entry_files.get('css', [])
parse_manifest_json()
@app.context_processor
def get_js_manifest():
return dict(js_manifest=get_manifest_file)
def get_manifest():
return dict(
js_manifest=get_js_manifest_files,
css_manifest=get_css_manifest_files,
)
#################################################################
@@ -75,7 +93,9 @@ for bp in conf.get('BLUEPRINTS'):
if conf.get('SILENCE_FAB'):
logging.getLogger('flask_appbuilder').setLevel(logging.ERROR)
if not app.debug:
if app.debug:
app.logger.setLevel(logging.DEBUG)
else:
# In production mode, add log handler to sys.stderr.
app.logger.addHandler(logging.StreamHandler())
app.logger.setLevel(logging.INFO)
@@ -147,16 +167,23 @@ class MyIndexView(IndexView):
return redirect('/superset/welcome')
custom_sm = app.config.get('CUSTOM_SECURITY_MANAGER') or SupersetSecurityManager
if not issubclass(custom_sm, SupersetSecurityManager):
raise Exception(
"""Your CUSTOM_SECURITY_MANAGER must now extend SupersetSecurityManager,
not FAB's security manager.
See [4565] in UPDATING.md""")
appbuilder = AppBuilder(
app,
db.session,
base_template='superset/base.html',
indexview=MyIndexView,
security_manager_class=app.config.get('CUSTOM_SECURITY_MANAGER'),
security_manager_class=custom_sm,
update_perms=utils.get_update_perms_flag(),
)
sm = appbuilder.sm
security_manager = appbuilder.sm
results_backend = app.config.get('RESULTS_BACKEND')
@@ -165,6 +192,10 @@ module_datasource_map = app.config.get('DEFAULT_MODULE_DS_MAP')
module_datasource_map.update(app.config.get('ADDITIONAL_MODULE_DS_MAP'))
ConnectorRegistry.register_sources(module_datasource_map)
# Flask-Compress
if conf.get('ENABLE_FLASK_COMPRESS'):
Compress(app)
# Hook that provides administrators a handle on the Flask APP
# after initialization
flask_app_mutator = app.config.get('FLASK_APP_MUTATOR')

View File

@@ -1,3 +1,4 @@
{
"presets" : ["airbnb"],
"presets" : ["airbnb", "react", "env"],
"plugins": ["syntax-dynamic-import"],
}

View File

@@ -8,3 +8,4 @@ node_modules*/*
stylesheets/*
vendor/*
docs/*
src/dashboard/deprecated/*

View File

@@ -1,6 +1,7 @@
{
"extends": "airbnb",
"parserOptions":{
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
@@ -38,5 +39,8 @@
"react/no-unescaped-entities": 0,
"react/no-unused-prop-types": 0,
"react/no-string-refs": 0,
"indent": 0,
"no-multi-spaces": 0,
"padded-blocks": 0,
}
}

View File

@@ -1,9 +1,10 @@
verbose: true
instrumentation:
root: './javascripts'
root: './src'
extensions: ['.js', '.jsx']
excludes: [
'dist/**'
'dist/**',
'visualizations/index.js',
]
embed-source: false
variable: __coverage__

View File

@@ -1683,18 +1683,6 @@
"renderTrigger": true,
"default": ""
},
"where": {
"type": "TextControl",
"label": "Custom WHERE clause",
"default": "",
"description": "The text in this box gets included in your query's WHERE clause, as an AND to other criteria. You can include complex expression, parenthesis and anything else supported by the backend it is directed towards."
},
"having": {
"type": "TextControl",
"label": "Custom HAVING clause",
"default": "",
"description": "The text in this box gets included in your query's HAVING clause, as an AND to other criteria. You can include complex expression, parenthesis and anything else supported by the backend it is directed towards."
},
"compare_lag": {
"type": "TextControl",
"label": "Comparison Period Lag",
@@ -2214,6 +2202,20 @@
"default": false,
"description": "Whether to apply filter when table cell is clicked"
},
"align_pn": {
"type": "CheckboxControl",
"label": "Align +/-",
"renderTrigger": true,
"default": false,
"description": "Whether to align the background chart for +/- values"
},
"color_pn": {
"type": "CheckboxControl",
"label": "Color +/-",
"renderTrigger": true,
"default": true,
"description": "Whether to color +/- values"
},
"show_bubbles": {
"type": "CheckboxControl",
"label": "Show Bubbles",
@@ -2614,12 +2616,6 @@
"default": "",
"description": "Labels for the marker lines"
},
"filters": {
"type": "FilterControl",
"label": "",
"default": [],
"description": ""
},
"annotation_layers": {
"type": "AnnotationLayerControl",
"label": "",
@@ -2627,12 +2623,6 @@
"description": "Annotation Layers",
"renderTrigger": true
},
"having_filters": {
"type": "FilterControl",
"label": "",
"default": [],
"description": ""
},
"slice_id": {
"type": "HiddenControl",
"label": "Slice ID",
@@ -2733,6 +2723,10 @@
[
"googleCategory20c",
"googleCategory20c"
],
[
"lyftColors",
"lyftColors"
]
],
"description": "The color scheme for rendering chart",
@@ -2974,4 +2968,4 @@
"description": "Partitions whose height to parent height proportions are below this value are pruned"
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View File

@@ -1,19 +0,0 @@
# TODO
* Figure out how to organize the left panel, integrate Search
* collapse sql beyond 10 lines
* Security per-database (dropdown)
* Get a to work
## Cosmetic
* Result set font is too big
* lmiit/timer/buttons wrap
* table label is transparent
* SqlEditor buttons
* use react-bootstrap-prompt for query title input
* Make tabs look great
# PROJECT
* Write Runbook
* Confirm backups
* merge chef branch

View File

@@ -1,309 +0,0 @@
/* global notify */
import moment from 'moment';
import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Alert, Button, Col, Modal } from 'react-bootstrap';
import Select from 'react-select';
import { Table } from 'reactable';
import shortid from 'shortid';
import { exportChart } from '../../explore/exploreUtils';
import * as actions from '../actions';
import { VISUALIZE_VALIDATION_ERRORS } from '../constants';
import visTypes from '../../explore/stores/visTypes';
import { t } from '../../locales';
const CHART_TYPES = Object.keys(visTypes)
.filter(typeName => !!visTypes[typeName].showOnExplore)
.map((typeName) => {
const vis = visTypes[typeName];
return {
value: typeName,
label: vis.label,
requiresTime: !!vis.requiresTime,
};
});
const propTypes = {
actions: PropTypes.object.isRequired,
onHide: PropTypes.func,
query: PropTypes.object,
show: PropTypes.bool,
datasource: PropTypes.string,
errorMessage: PropTypes.string,
timeout: PropTypes.number,
};
const defaultProps = {
show: false,
query: {},
onHide: () => {},
};
class VisualizeModal extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
chartType: CHART_TYPES[0],
datasourceName: this.datasourceName(),
columns: this.getColumnFromProps(),
hints: [],
};
}
componentDidMount() {
this.validate();
}
getColumnFromProps() {
const props = this.props;
if (!props ||
!props.query ||
!props.query.results ||
!props.query.results.columns) {
return {};
}
const columns = {};
props.query.results.columns.forEach((col) => {
columns[col.name] = col;
});
return columns;
}
datasourceName() {
const { query } = this.props;
const uniqueId = shortid.generate();
let datasourceName = uniqueId;
if (query) {
datasourceName = query.user ? `${query.user}-` : '';
datasourceName += query.db ? `${query.db}-` : '';
datasourceName += `${query.tab}-${uniqueId}`;
}
return datasourceName;
}
validate() {
const hints = [];
const cols = this.mergedColumns();
const re = /^\w+$/;
Object.keys(cols).forEach((colName) => {
if (!re.test(colName)) {
hints.push(
<div>
{t('%s is not right as a column name, please alias it ' +
'(as in SELECT count(*) ', colName)} <strong>{t('AS my_alias')}</strong>) {t('using only ' +
'alphanumeric characters and underscores')}
</div>);
}
});
if (this.state.chartType === null) {
hints.push(VISUALIZE_VALIDATION_ERRORS.REQUIRE_CHART_TYPE);
} else if (this.state.chartType.requiresTime) {
let hasTime = false;
for (const colName in cols) {
const col = cols[colName];
if (col.hasOwnProperty('is_date') && col.is_date) {
hasTime = true;
}
}
if (!hasTime) {
hints.push(VISUALIZE_VALIDATION_ERRORS.REQUIRE_TIME);
}
}
this.setState({ hints });
}
changeChartType(option) {
this.setState({ chartType: option }, this.validate);
}
mergedColumns() {
const columns = Object.assign({}, this.state.columns);
if (this.props.query && this.props.query.results.columns) {
this.props.query.results.columns.forEach((col) => {
if (columns[col.name] === undefined) {
columns[col.name] = col;
}
});
}
return columns;
}
buildVizOptions() {
return {
chartType: this.state.chartType.value,
datasourceName: this.state.datasourceName,
columns: this.state.columns,
sql: this.props.query.sql,
dbId: this.props.query.dbId,
};
}
buildVisualizeAdvise() {
let advise;
const timeout = this.props.timeout;
const queryDuration = moment.duration(this.props.query.endDttm - this.props.query.startDttm);
if (Math.round(queryDuration.asMilliseconds()) > timeout * 1000) {
advise = (
<Alert bsStyle="warning">
This query took {Math.round(queryDuration.asSeconds())} seconds to run,
and the explore view times out at {timeout} seconds,
following this flow will most likely lead to your query timing out.
We recommend your summarize your data further before following that flow.
If activated you can use the <strong>CREATE TABLE AS</strong> feature
to store a summarized data set that you can then explore.
</Alert>);
}
return advise;
}
visualize() {
this.props.actions.createDatasource(this.buildVizOptions(), this)
.done((resp) => {
const columns = Object.keys(this.state.columns).map(k => this.state.columns[k]);
const data = JSON.parse(resp);
const mainGroupBy = columns.filter(d => d.is_dim)[0];
const formData = {
datasource: `${data.table_id}__table`,
viz_type: this.state.chartType.value,
since: '100 years ago',
limit: '0',
};
if (mainGroupBy) {
formData.groupby = [mainGroupBy.name];
}
notify.info(t('Creating a data source and popping a new tab'));
// open new window for data visualization
exportChart(formData);
})
.fail(() => {
notify.error(this.props.errorMessage);
});
}
changeDatasourceName(event) {
this.setState({ datasourceName: event.target.value }, this.validate);
}
changeCheckbox(attr, columnName, event) {
let columns = this.mergedColumns();
const column = Object.assign({}, columns[columnName], { [attr]: event.target.checked });
columns = Object.assign({}, columns, { [columnName]: column });
this.setState({ columns }, this.validate);
}
changeAggFunction(columnName, option) {
let columns = this.mergedColumns();
const val = (option) ? option.value : null;
const column = Object.assign({}, columns[columnName], { agg: val });
columns = Object.assign({}, columns, { [columnName]: column });
this.setState({ columns }, this.validate);
}
render() {
if (!(this.props.query) || !(this.props.query.results) || !(this.props.query.results.columns)) {
return (
<div className="VisualizeModal">
<Modal show={this.props.show} onHide={this.props.onHide}>
<Modal.Body>
{t('No results available for this query')}
</Modal.Body>
</Modal>
</div>
);
}
const tableData = this.props.query.results.columns.map(col => ({
column: col.name,
is_dimension: (
<input
type="checkbox"
onChange={this.changeCheckbox.bind(this, 'is_dim', col.name)}
checked={(this.state.columns[col.name]) ? this.state.columns[col.name].is_dim : false}
className="form-control"
/>
),
is_date: (
<input
type="checkbox"
className="form-control"
onChange={this.changeCheckbox.bind(this, 'is_date', col.name)}
checked={(this.state.columns[col.name]) ? this.state.columns[col.name].is_date : false}
/>
),
agg_func: (
<Select
options={[
{ value: 'sum', label: 'SUM(x)' },
{ value: 'min', label: 'MIN(x)' },
{ value: 'max', label: 'MAX(x)' },
{ value: 'avg', label: 'AVG(x)' },
{ value: 'count_distinct', label: 'COUNT(DISTINCT x)' },
]}
onChange={this.changeAggFunction.bind(this, col.name)}
value={(this.state.columns[col.name]) ? this.state.columns[col.name].agg : null}
/>
),
}));
const alerts = this.state.hints.map((hint, i) => (
<Alert bsStyle="warning" key={i}>{hint}</Alert>
));
const modal = (
<div className="VisualizeModal">
<Modal show={this.props.show} onHide={this.props.onHide}>
<Modal.Header closeButton>
<Modal.Title>{t('Visualize')}</Modal.Title>
</Modal.Header>
<Modal.Body>
{alerts}
{this.buildVisualizeAdvise()}
<div className="row">
<Col md={6}>
{t('Chart Type')}
<Select
name="select-chart-type"
placeholder={t('[Chart Type]')}
options={CHART_TYPES}
value={(this.state.chartType) ? this.state.chartType.value : null}
autosize={false}
onChange={this.changeChartType.bind(this)}
/>
</Col>
<Col md={6}>
{t('Datasource Name')}
<input
type="text"
className="form-control input-sm"
placeholder={t('datasource name')}
onChange={this.changeDatasourceName.bind(this)}
value={this.state.datasourceName}
/>
</Col>
</div>
<hr />
<Table
className="table table-condensed"
columns={['column', 'is_dimension', 'is_date', 'agg_func']}
data={tableData}
/>
<Button
onClick={this.visualize.bind(this)}
bsStyle="primary"
disabled={(this.state.hints.length > 0)}
>
{t('Visualize')}
</Button>
</Modal.Body>
</Modal>
</div>
);
return modal;
}
}
VisualizeModal.propTypes = propTypes;
VisualizeModal.defaultProps = defaultProps;
function mapStateToProps(state) {
return {
datasource: state.datasource,
errorMessage: state.errorMessage,
timeout: state.common ? state.common.conf.SUPERSET_WEBSERVER_TIMEOUT : null,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch),
};
}
export { VisualizeModal };
export default connect(mapStateToProps, mapDispatchToProps)(VisualizeModal);

View File

@@ -1,34 +0,0 @@
import { t } from '../locales';
export const STATE_BSSTYLE_MAP = {
failed: 'danger',
pending: 'info',
fetching: 'info',
running: 'warning',
stopped: 'danger',
success: 'success',
};
export const STATUS_OPTIONS = [
'success',
'failed',
'running',
'pending',
];
export const TIME_OPTIONS = [
'now',
'1 hour ago',
'1 day ago',
'7 days ago',
'28 days ago',
'90 days ago',
'1 year ago',
];
export const VISUALIZE_VALIDATION_ERRORS = {
REQUIRE_CHART_TYPE: t('Pick a chart type!'),
REQUIRE_TIME: t('To use this chart type you need at least one column flagged as a date'),
REQUIRE_DIMENSION: t('To use this chart type you need at least one dimension'),
REQUIRE_AGGREGATION_FUNCTION: t('To use this chart type you need at least one aggregation function'),
};

View File

@@ -1,99 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Panel, Grid, Row, Col } from 'react-bootstrap';
import Select from 'react-virtualized-select';
import visTypes from '../explore/stores/visTypes';
import { t } from '../locales';
const propTypes = {
datasources: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
})).isRequired,
};
export default class AddSliceContainer extends React.PureComponent {
constructor(props) {
super(props);
const visTypeKeys = Object.keys(visTypes);
this.vizTypeOptions = visTypeKeys.map(vt => ({ label: visTypes[vt].label, value: vt }));
this.state = {
visType: 'table',
};
}
exploreUrl() {
const baseUrl = `/superset/explore/${this.state.datasourceType}/${this.state.datasourceId}`;
const formData = encodeURIComponent(JSON.stringify({ viz_type: this.state.visType }));
return `${baseUrl}?form_data=${formData}`;
}
gotoSlice() {
window.location.href = this.exploreUrl();
}
changeDatasource(e) {
this.setState({
datasourceValue: e.value,
datasourceId: e.value.split('__')[0],
datasourceType: e.value.split('__')[1],
});
}
changeVisType(e) {
this.setState({ visType: e.value });
}
isBtnDisabled() {
return !(this.state.datasourceId && this.state.visType);
}
render() {
return (
<div className="container">
<Panel header={<h3>{t('Create a new slice')}</h3>}>
<Grid>
<Row>
<Col xs={12} sm={6}>
<div>
<p>{t('Choose a datasource')}</p>
<Select
clearable={false}
name="select-datasource"
onChange={this.changeDatasource.bind(this)}
options={this.props.datasources}
placeholder={t('Choose a datasource')}
value={this.state.datasourceValue}
/>
</div>
<br />
<div>
<p>{t('Choose a visualization type')}</p>
<Select
clearable={false}
name="select-vis-type"
onChange={this.changeVisType.bind(this)}
options={this.vizTypeOptions}
placeholder={t('Choose a visualization type')}
value={this.state.visType}
/>
</div>
<br />
<Button
bsStyle="primary"
disabled={this.isBtnDisabled()}
onClick={this.gotoSlice.bind(this)}
>
{t('Create new slice')}
</Button>
<br /><br />
</Col>
</Row>
</Grid>
</Panel>
</div>
);
}
}
AddSliceContainer.propTypes = propTypes;

View File

@@ -1,236 +0,0 @@
/* eslint camelcase: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import Mustache from 'mustache';
import { Tooltip } from 'react-bootstrap';
import { d3format } from '../modules/utils';
import ChartBody from './ChartBody';
import Loading from '../components/Loading';
import { Logger, LOG_ACTIONS_RENDER_EVENT } from '../logger';
import StackTraceMessage from '../components/StackTraceMessage';
import visMap from '../../visualizations/main';
import sandboxedEval from '../modules/sandbox';
import './chart.css';
const propTypes = {
annotationData: PropTypes.object,
actions: PropTypes.object,
chartKey: PropTypes.string.isRequired,
containerId: PropTypes.string.isRequired,
datasource: PropTypes.object.isRequired,
formData: PropTypes.object.isRequired,
headerHeight: PropTypes.number,
height: PropTypes.number,
width: PropTypes.number,
setControlValue: PropTypes.func,
timeout: PropTypes.number,
vizType: PropTypes.string.isRequired,
// state
chartAlert: PropTypes.string,
chartStatus: PropTypes.string,
chartUpdateEndTime: PropTypes.number,
chartUpdateStartTime: PropTypes.number,
latestQueryFormData: PropTypes.object,
queryRequest: PropTypes.object,
queryResponse: PropTypes.object,
lastRendered: PropTypes.number,
triggerQuery: PropTypes.bool,
// dashboard callbacks
addFilter: PropTypes.func,
getFilters: PropTypes.func,
clearFilter: PropTypes.func,
removeFilter: PropTypes.func,
};
const defaultProps = {
addFilter: () => ({}),
getFilters: () => ({}),
clearFilter: () => ({}),
removeFilter: () => ({}),
};
class Chart extends React.PureComponent {
constructor(props) {
super(props);
this.state = {};
// these properties are used by visualizations
this.annotationData = props.annotationData;
this.containerId = props.containerId;
this.selector = `#${this.containerId}`;
this.formData = props.formData;
this.datasource = props.datasource;
this.addFilter = this.addFilter.bind(this);
this.getFilters = this.getFilters.bind(this);
this.clearFilter = this.clearFilter.bind(this);
this.removeFilter = this.removeFilter.bind(this);
this.headerHeight = this.headerHeight.bind(this);
this.height = this.height.bind(this);
this.width = this.width.bind(this);
}
componentDidMount() {
if (this.props.triggerQuery) {
this.props.actions.runQuery(this.props.formData, false,
this.props.timeout,
this.props.chartKey,
);
}
}
componentWillReceiveProps(nextProps) {
this.annotationData = nextProps.annotationData;
this.containerId = nextProps.containerId;
this.selector = `#${this.containerId}`;
this.formData = nextProps.formData;
this.datasource = nextProps.datasource;
}
componentDidUpdate(prevProps) {
if (
this.props.queryResponse &&
['success', 'rendered'].indexOf(this.props.chartStatus) > -1 &&
!this.props.queryResponse.error && (
prevProps.annotationData !== this.props.annotationData ||
prevProps.queryResponse !== this.props.queryResponse ||
prevProps.height !== this.props.height ||
prevProps.width !== this.props.width ||
prevProps.lastRendered !== this.props.lastRendered)
) {
this.renderViz();
}
}
getFilters() {
return this.props.getFilters();
}
setTooltip(tooltip) {
this.setState({ tooltip });
}
addFilter(col, vals, merge = true, refresh = true) {
this.props.addFilter(col, vals, merge, refresh);
}
clearFilter() {
this.props.clearFilter();
}
removeFilter(col, vals, refresh = true) {
this.props.removeFilter(col, vals, refresh);
}
clearError() {
this.setState({
errorMsg: null,
});
}
width() {
return this.props.width || this.container.el.offsetWidth;
}
headerHeight() {
return this.props.headerHeight || 0;
}
height() {
return this.props.height || this.container.el.offsetHeight;
}
d3format(col, number) {
const { datasource } = this.props;
const format = (datasource.column_formats && datasource.column_formats[col]) || '0.3s';
return d3format(format, number);
}
render_template(s) {
const context = {
width: this.width(),
height: this.height(),
};
return Mustache.render(s, context);
}
renderTooltip() {
if (this.state.tooltip) {
/* eslint-disable react/no-danger */
return (
<Tooltip
className="chart-tooltip"
id="chart-tooltip"
placement="right"
positionTop={this.state.tooltip.y - 10}
positionLeft={this.state.tooltip.x + 30}
arrowOffsetTop={10}
>
<div dangerouslySetInnerHTML={{ __html: this.state.tooltip.content }} />
</Tooltip>
);
/* eslint-enable react/no-danger */
}
return null;
}
renderViz() {
const viz = visMap[this.props.vizType];
const fd = this.props.formData;
const qr = this.props.queryResponse;
const renderStart = Logger.getTimestamp();
try {
// Executing user-defined data mutator function
if (fd.js_data) {
qr.data = sandboxedEval(fd.js_data)(qr.data);
}
// [re]rendering the visualization
viz(this, qr, this.props.setControlValue);
Logger.append(LOG_ACTIONS_RENDER_EVENT, {
label: this.props.chartKey,
vis_type: this.props.vizType,
start_offset: renderStart,
duration: Logger.getTimestamp() - renderStart,
});
this.props.actions.chartRenderingSucceeded(this.props.chartKey);
} catch (e) {
console.error(e); // eslint-disable-line
this.props.actions.chartRenderingFailed(e, this.props.chartKey);
}
}
render() {
const isLoading = this.props.chartStatus === 'loading';
return (
<div className={`token col-md-12 ${isLoading ? 'is-loading' : ''}`}>
{this.renderTooltip()}
{isLoading &&
<Loading size={25} />
}
{this.props.chartAlert &&
<StackTraceMessage
message={this.props.chartAlert}
queryResponse={this.props.queryResponse}
/>
}
{!isLoading && !this.props.chartAlert &&
<ChartBody
containerId={this.containerId}
vizType={this.props.vizType}
height={this.height}
width={this.width}
ref={(inner) => {
this.container = inner;
}}
/>
}
</div>
);
}
}
Chart.propTypes = propTypes;
Chart.defaultProps = defaultProps;
export default Chart;

View File

@@ -1,29 +0,0 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as Actions from './chartAction';
import Chart from './Chart';
function mapStateToProps({ charts }, ownProps) {
const chart = charts[ownProps.chartKey];
return {
annotationData: chart.annotationData,
chartAlert: chart.chartAlert,
chartStatus: chart.chartStatus,
chartUpdateEndTime: chart.chartUpdateEndTime,
chartUpdateStartTime: chart.chartUpdateStartTime,
latestQueryFormData: chart.latestQueryFormData,
lastRendered: chart.lastRendered,
queryResponse: chart.queryResponse,
queryRequest: chart.queryRequest,
triggerQuery: chart.triggerQuery,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Chart);

View File

@@ -1,38 +0,0 @@
/* global notify */
import React from 'react';
import AlertContainer from 'react-alert';
import PropTypes from 'prop-types';
const propTypes = {
initMessages: PropTypes.array,
};
const defaultProps = {
initMessages: [],
};
export default class AlertsWrapper extends React.PureComponent {
componentDidMount() {
this.props.initMessages.forEach((msg) => {
if (['info', 'error', 'success'].indexOf(msg[0]) >= 0) {
notify[msg[0]](msg[1]);
} else {
notify.show(msg[1]);
}
});
}
render() {
return (
<AlertContainer
ref={(ref) => {
global.notify = ref;
}}
offset={14}
position="top right"
theme="dark"
time={5000}
transition="fade"
/>);
}
}
AlertsWrapper.propTypes = propTypes;
AlertsWrapper.defaultProps = defaultProps;

View File

@@ -1,127 +0,0 @@
/* global notify */
import $ from 'jquery';
import { getExploreUrlAndPayload } from '../explore/exploreUtils';
export const ADD_FILTER = 'ADD_FILTER';
export function addFilter(sliceId, col, vals, merge = true, refresh = true) {
return { type: ADD_FILTER, sliceId, col, vals, merge, refresh };
}
export const CLEAR_FILTER = 'CLEAR_FILTER';
export function clearFilter(sliceId) {
return { type: CLEAR_FILTER, sliceId };
}
export const REMOVE_FILTER = 'REMOVE_FILTER';
export function removeFilter(sliceId, col, vals, refresh = true) {
return { type: REMOVE_FILTER, sliceId, col, vals, refresh };
}
export const UPDATE_DASHBOARD_LAYOUT = 'UPDATE_DASHBOARD_LAYOUT';
export function updateDashboardLayout(layout) {
return { type: UPDATE_DASHBOARD_LAYOUT, layout };
}
export const UPDATE_DASHBOARD_TITLE = 'UPDATE_DASHBOARD_TITLE';
export function updateDashboardTitle(title) {
return { type: UPDATE_DASHBOARD_TITLE, title };
}
export function addSlicesToDashboard(dashboardId, sliceIds) {
return () => (
$.ajax({
type: 'POST',
url: `/superset/add_slices/${dashboardId}/`,
data: {
data: JSON.stringify({ slice_ids: sliceIds }),
},
})
.done(() => {
// Refresh page to allow for slices to re-render
window.location.reload();
})
);
}
export const REMOVE_SLICE = 'REMOVE_SLICE';
export function removeSlice(slice) {
return { type: REMOVE_SLICE, slice };
}
export const UPDATE_SLICE_NAME = 'UPDATE_SLICE_NAME';
export function updateSliceName(slice, sliceName) {
return { type: UPDATE_SLICE_NAME, slice, sliceName };
}
export function saveSlice(slice, sliceName) {
const oldName = slice.slice_name;
return (dispatch) => {
const sliceParams = {};
sliceParams.slice_id = slice.slice_id;
sliceParams.action = 'overwrite';
sliceParams.slice_name = sliceName;
const { url, payload } = getExploreUrlAndPayload({
formData: slice.form_data,
endpointType: 'base',
force: false,
curUrl: null,
requestParams: sliceParams,
});
return $.ajax({
url,
type: 'POST',
data: {
form_data: JSON.stringify(payload),
},
success: () => {
dispatch(updateSliceName(slice, sliceName));
notify.success('This slice name was saved successfully.');
},
error: () => {
// if server-side reject the overwrite action,
// revert to old state
dispatch(updateSliceName(slice, oldName));
notify.error("You don't have the rights to alter this slice");
},
});
};
}
const FAVESTAR_BASE_URL = '/superset/favstar/Dashboard';
export const TOGGLE_FAVE_STAR = 'TOGGLE_FAVE_STAR';
export function toggleFaveStar(isStarred) {
return { type: TOGGLE_FAVE_STAR, isStarred };
}
export const FETCH_FAVE_STAR = 'FETCH_FAVE_STAR';
export function fetchFaveStar(id) {
return function (dispatch) {
const url = `${FAVESTAR_BASE_URL}/${id}/count`;
return $.get(url)
.done((data) => {
if (data.count > 0) {
dispatch(toggleFaveStar(true));
}
});
};
}
export const SAVE_FAVE_STAR = 'SAVE_FAVE_STAR';
export function saveFaveStar(id, isStarred) {
return function (dispatch) {
const urlSuffix = isStarred ? 'unselect' : 'select';
const url = `${FAVESTAR_BASE_URL}/${id}/${urlSuffix}/`;
$.get(url);
dispatch(toggleFaveStar(!isStarred));
};
}
export const TOGGLE_EXPAND_SLICE = 'TOGGLE_EXPAND_SLICE';
export function toggleExpandSlice(slice, isExpanded) {
return { type: TOGGLE_EXPAND_SLICE, slice, isExpanded };
}
export const SET_EDIT_MODE = 'SET_EDIT_MODE';
export function setEditMode(editMode) {
return { type: SET_EDIT_MODE, editMode };
}

View File

@@ -1,212 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { DropdownButton, MenuItem } from 'react-bootstrap';
import CssEditor from './CssEditor';
import RefreshIntervalModal from './RefreshIntervalModal';
import SaveModal from './SaveModal';
import SliceAdder from './SliceAdder';
import { t } from '../../locales';
import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
const $ = window.$ = require('jquery');
const propTypes = {
dashboard: PropTypes.object.isRequired,
filters: PropTypes.object.isRequired,
slices: PropTypes.array,
userId: PropTypes.string.isRequired,
addSlicesToDashboard: PropTypes.func,
onSave: PropTypes.func,
onChange: PropTypes.func,
renderSlices: PropTypes.func,
serialize: PropTypes.func,
startPeriodicRender: PropTypes.func,
editMode: PropTypes.bool,
};
function MenuItemContent({ faIcon, text, tooltip, children }) {
return (
<span>
<i className={`fa fa-${faIcon}`} /> {text} {''}
<InfoTooltipWithTrigger
tooltip={tooltip}
label={`dash-${faIcon}`}
placement="top"
/>
{children}
</span>
);
}
MenuItemContent.propTypes = {
faIcon: PropTypes.string.isRequired,
text: PropTypes.string,
tooltip: PropTypes.string,
children: PropTypes.node,
};
function ActionMenuItem(props) {
return (
<MenuItem onClick={props.onClick}>
<MenuItemContent {...props} />
</MenuItem>
);
}
ActionMenuItem.propTypes = {
onClick: PropTypes.func,
};
class Controls extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
css: props.dashboard.css || '',
cssTemplates: [],
};
this.refresh = this.refresh.bind(this);
this.toggleModal = this.toggleModal.bind(this);
this.updateDom = this.updateDom.bind(this);
}
componentWillMount() {
this.updateDom(this.state.css);
$.get('/csstemplateasyncmodelview/api/read', (data) => {
const cssTemplates = data.result.map(row => ({
value: row.template_name,
css: row.css,
label: row.template_name,
}));
this.setState({ cssTemplates });
});
}
refresh() {
// Force refresh all slices
this.props.renderSlices(true);
}
toggleModal(modal) {
let currentModal;
if (modal !== this.state.currentModal) {
currentModal = modal;
}
this.setState({ currentModal });
}
changeCss(css) {
this.setState({ css }, () => {
this.updateDom(css);
});
this.props.onChange();
}
updateDom(css) {
const className = 'CssEditor-css';
const head = document.head || document.getElementsByTagName('head')[0];
let style = document.querySelector('.' + className);
if (!style) {
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;
}
}
render() {
const { dashboard, userId, filters,
addSlicesToDashboard, startPeriodicRender,
serialize, onSave, editMode } = this.props;
const emailBody = t('Checkout this dashboard: %s', window.location.href);
const emailLink = 'mailto:?Subject=Superset%20Dashboard%20'
+ `${dashboard.dashboard_title}&Body=${emailBody}`;
let saveText = t('Save as');
if (editMode) {
saveText = t('Save');
}
return (
<span>
<DropdownButton title="Actions" bsSize="small" id="bg-nested-dropdown" pullRight>
<ActionMenuItem
text={t('Force Refresh')}
tooltip={t('Force refresh the whole dashboard')}
faIcon="refresh"
onClick={this.refresh}
/>
<RefreshIntervalModal
onChange={refreshInterval => startPeriodicRender(refreshInterval * 1000)}
triggerNode={
<MenuItemContent
text={t('Set autorefresh')}
tooltip={t('Set the auto-refresh interval for this session')}
faIcon="clock-o"
/>
}
/>
<SaveModal
dashboard={dashboard}
filters={filters}
serialize={serialize}
onSave={onSave}
css={this.state.css}
triggerNode={
<MenuItemContent
text={saveText}
tooltip={t('Save the dashboard')}
faIcon="save"
/>
}
/>
{editMode &&
<ActionMenuItem
text={t('Edit properties')}
tooltip={t("Edit the dashboards's properties")}
faIcon="edit"
onClick={() => { window.location = `/dashboardmodelview/edit/${dashboard.id}`; }}
/>
}
{editMode &&
<ActionMenuItem
text={t('Email')}
tooltip={t('Email a link to this dashboard')}
onClick={() => { window.location = emailLink; }}
faIcon="envelope"
/>
}
{editMode &&
<SliceAdder
dashboard={dashboard}
addSlicesToDashboard={addSlicesToDashboard}
userId={userId}
triggerNode={
<MenuItemContent
text={t('Add Slices')}
tooltip={t('Add some slices to this dashboard')}
faIcon="plus"
/>
}
/>
}
{editMode &&
<CssEditor
dashboard={dashboard}
triggerNode={
<MenuItemContent
text={t('Edit CSS')}
tooltip={t('Change the style of the dashboard using CSS code')}
faIcon="css3"
/>
}
initialCss={this.state.css}
templates={this.state.cssTemplates}
onChange={this.changeCss.bind(this)}
/>
}
</DropdownButton>
</span>
);
}
}
Controls.propTypes = propTypes;
export default Controls;

View File

@@ -1,355 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import AlertsWrapper from '../../components/AlertsWrapper';
import GridLayout from './GridLayout';
import Header from './Header';
import { exportChart } from '../../explore/exploreUtils';
import { areObjectsEqual } from '../../reduxUtils';
import { Logger, ActionLog, LOG_ACTIONS_PAGE_LOAD,
LOG_ACTIONS_LOAD_EVENT, LOG_ACTIONS_RENDER_EVENT } from '../../logger';
import { t } from '../../locales';
import '../../../stylesheets/dashboard.css';
const propTypes = {
actions: PropTypes.object,
initMessages: PropTypes.array,
dashboard: PropTypes.object.isRequired,
slices: PropTypes.object,
datasources: PropTypes.object,
filters: PropTypes.object,
refresh: PropTypes.bool,
timeout: PropTypes.number,
userId: PropTypes.string,
isStarred: PropTypes.bool,
editMode: PropTypes.bool,
impressionId: PropTypes.string,
};
const defaultProps = {
initMessages: [],
dashboard: {},
slices: {},
datasources: {},
filters: {},
refresh: false,
timeout: 60,
userId: '',
isStarred: false,
editMode: false,
};
class Dashboard extends React.PureComponent {
constructor(props) {
super(props);
this.refreshTimer = null;
this.firstLoad = true;
this.loadingLog = new ActionLog({
impressionId: props.impressionId,
actionType: LOG_ACTIONS_PAGE_LOAD,
source: 'dashboard',
sourceId: props.dashboard.id,
eventNames: [LOG_ACTIONS_LOAD_EVENT, LOG_ACTIONS_RENDER_EVENT],
});
Logger.start(this.loadingLog);
// alert for unsaved changes
this.state = { unsavedChanges: false };
this.rerenderCharts = this.rerenderCharts.bind(this);
this.updateDashboardTitle = this.updateDashboardTitle.bind(this);
this.onSave = this.onSave.bind(this);
this.onChange = this.onChange.bind(this);
this.serialize = this.serialize.bind(this);
this.fetchAllSlices = this.fetchSlices.bind(this, this.getAllSlices());
this.startPeriodicRender = this.startPeriodicRender.bind(this);
this.addSlicesToDashboard = this.addSlicesToDashboard.bind(this);
this.fetchSlice = this.fetchSlice.bind(this);
this.getFormDataExtra = this.getFormDataExtra.bind(this);
this.exploreChart = this.exploreChart.bind(this);
this.exportCSV = this.exportCSV.bind(this);
this.props.actions.fetchFaveStar = this.props.actions.fetchFaveStar.bind(this);
this.props.actions.saveFaveStar = this.props.actions.saveFaveStar.bind(this);
this.props.actions.saveSlice = this.props.actions.saveSlice.bind(this);
this.props.actions.removeSlice = this.props.actions.removeSlice.bind(this);
this.props.actions.removeChart = this.props.actions.removeChart.bind(this);
this.props.actions.updateDashboardLayout = this.props.actions.updateDashboardLayout.bind(this);
this.props.actions.toggleExpandSlice = this.props.actions.toggleExpandSlice.bind(this);
this.props.actions.addFilter = this.props.actions.addFilter.bind(this);
this.props.actions.clearFilter = this.props.actions.clearFilter.bind(this);
this.props.actions.removeFilter = this.props.actions.removeFilter.bind(this);
}
componentDidMount() {
window.addEventListener('resize', this.rerenderCharts);
}
componentWillReceiveProps(nextProps) {
if (this.firstLoad &&
Object.values(nextProps.slices)
.every(slice => (['rendered', 'failed', 'stopped'].indexOf(slice.chartStatus) > -1))
) {
Logger.end(this.loadingLog);
this.firstLoad = false;
}
}
componentDidUpdate(prevProps) {
if (this.props.refresh) {
let changedFilterKey;
const prevFiltersKeySet = new Set(Object.keys(prevProps.filters));
Object.keys(this.props.filters).some((key) => {
prevFiltersKeySet.delete(key);
if (prevProps.filters[key] === undefined ||
!areObjectsEqual(prevProps.filters[key], this.props.filters[key])) {
changedFilterKey = key;
return true;
}
return false;
});
// has changed filter or removed a filter?
if (!!changedFilterKey || prevFiltersKeySet.size) {
this.refreshExcept(changedFilterKey);
}
}
}
componentWillUnmount() {
window.removeEventListener('resize', this.rerenderCharts);
}
onBeforeUnload(hasChanged) {
if (hasChanged) {
window.addEventListener('beforeunload', this.unload);
} else {
window.removeEventListener('beforeunload', this.unload);
}
}
onChange() {
this.onBeforeUnload(true);
this.setState({ unsavedChanges: true });
}
onSave() {
this.onBeforeUnload(false);
this.setState({ unsavedChanges: false });
}
// return charts in array
getAllSlices() {
return Object.values(this.props.slices);
}
getFormDataExtra(slice) {
const formDataExtra = Object.assign({}, slice.formData);
const extraFilters = this.effectiveExtraFilters(slice.slice_id);
formDataExtra.extra_filters = formDataExtra.filters.concat(extraFilters);
return formDataExtra;
}
getFilters(sliceId) {
return this.props.filters[sliceId];
}
unload() {
const message = t('You have unsaved changes.');
window.event.returnValue = message; // Gecko + IE
return message; // Gecko + Webkit, Safari, Chrome etc.
}
effectiveExtraFilters(sliceId) {
const metadata = this.props.dashboard.metadata;
const filters = this.props.filters;
const f = [];
const immuneSlices = metadata.filter_immune_slices || [];
if (sliceId && immuneSlices.includes(sliceId)) {
// The slice is immune to dashboard filters
return f;
}
// Building a list of fields the slice is immune to filters on
let immuneToFields = [];
if (
sliceId &&
metadata.filter_immune_slice_fields &&
metadata.filter_immune_slice_fields[sliceId]) {
immuneToFields = metadata.filter_immune_slice_fields[sliceId];
}
for (const filteringSliceId in filters) {
if (filteringSliceId === sliceId.toString()) {
// Filters applied by the slice don't apply to itself
continue;
}
for (const field in filters[filteringSliceId]) {
if (!immuneToFields.includes(field)) {
f.push({
col: field,
op: 'in',
val: filters[filteringSliceId][field],
});
}
}
}
return f;
}
refreshExcept(filterKey) {
const immune = this.props.dashboard.metadata.filter_immune_slices || [];
let slices = this.getAllSlices();
if (filterKey) {
slices = slices.filter(slice => (
String(slice.slice_id) !== filterKey &&
immune.indexOf(slice.slice_id) === -1
));
}
this.fetchSlices(slices);
}
stopPeriodicRender() {
if (this.refreshTimer) {
clearTimeout(this.refreshTimer);
this.refreshTimer = null;
}
}
startPeriodicRender(interval) {
this.stopPeriodicRender();
const immune = this.props.dashboard.metadata.timed_refresh_immune_slices || [];
const refreshAll = () => {
const affectedSlices = this.getAllSlices()
.filter(slice => immune.indexOf(slice.slice_id) === -1);
this.fetchSlices(affectedSlices, true, interval * 0.2);
};
const fetchAndRender = () => {
refreshAll();
if (interval > 0) {
this.refreshTimer = setTimeout(fetchAndRender, interval);
}
};
fetchAndRender();
}
updateDashboardTitle(title) {
this.props.actions.updateDashboardTitle(title);
this.onChange();
}
serialize() {
return this.props.dashboard.layout.map(reactPos => ({
slice_id: reactPos.i,
col: reactPos.x + 1,
row: reactPos.y,
size_x: reactPos.w,
size_y: reactPos.h,
}));
}
addSlicesToDashboard(sliceIds) {
return this.props.actions.addSlicesToDashboard(this.props.dashboard.id, sliceIds);
}
fetchSlice(slice, force = false) {
return this.props.actions.runQuery(
this.getFormDataExtra(slice), force, this.props.timeout, slice.chartKey,
);
}
// fetch and render an list of slices
fetchSlices(slc, force = false, interval = 0) {
const slices = slc || this.getAllSlices();
if (!interval) {
slices.forEach((slice) => { this.fetchSlice(slice, force); });
return;
}
const meta = this.props.dashboard.metadata;
const refreshTime = Math.max(interval, meta.stagger_time || 5000); // default 5 seconds
if (typeof meta.stagger_refresh !== 'boolean') {
meta.stagger_refresh = meta.stagger_refresh === undefined ?
true : meta.stagger_refresh === 'true';
}
const delay = meta.stagger_refresh ? refreshTime / (slices.length - 1) : 0;
slices.forEach((slice, i) => {
setTimeout(() => { this.fetchSlice(slice, force); }, delay * i);
});
}
exploreChart(slice) {
const formData = this.getFormDataExtra(slice);
exportChart(formData);
}
exportCSV(slice) {
const formData = this.getFormDataExtra(slice);
exportChart(formData, 'csv');
}
// re-render chart without fetch
rerenderCharts() {
this.getAllSlices().forEach((slice) => {
setTimeout(() => {
this.props.actions.renderTriggered(new Date().getTime(), slice.chartKey);
}, 50);
});
}
render() {
return (
<div id="dashboard-container">
<div id="dashboard-header">
<AlertsWrapper initMessages={this.props.initMessages} />
<Header
dashboard={this.props.dashboard}
unsavedChanges={this.state.unsavedChanges}
filters={this.props.filters}
userId={this.props.userId}
isStarred={this.props.isStarred}
updateDashboardTitle={this.updateDashboardTitle}
onSave={this.onSave}
onChange={this.onChange}
serialize={this.serialize}
fetchFaveStar={this.props.actions.fetchFaveStar}
saveFaveStar={this.props.actions.saveFaveStar}
renderSlices={this.fetchAllSlices}
startPeriodicRender={this.startPeriodicRender}
addSlicesToDashboard={this.addSlicesToDashboard}
editMode={this.props.editMode}
setEditMode={this.props.actions.setEditMode}
/>
</div>
<div id="grid-container" className="slice-grid gridster">
<GridLayout
dashboard={this.props.dashboard}
datasources={this.props.datasources}
filters={this.props.filters}
charts={this.props.slices}
timeout={this.props.timeout}
onChange={this.onChange}
getFormDataExtra={this.getFormDataExtra}
exploreChart={this.exploreChart}
exportCSV={this.exportCSV}
fetchSlice={this.fetchSlice}
saveSlice={this.props.actions.saveSlice}
removeSlice={this.props.actions.removeSlice}
removeChart={this.props.actions.removeChart}
updateDashboardLayout={this.props.actions.updateDashboardLayout}
toggleExpandSlice={this.props.actions.toggleExpandSlice}
addFilter={this.props.actions.addFilter}
getFilters={this.getFilters}
clearFilter={this.props.actions.clearFilter}
removeFilter={this.props.actions.removeFilter}
editMode={this.props.editMode}
/>
</div>
</div>
);
}
}
Dashboard.propTypes = propTypes;
Dashboard.defaultProps = defaultProps;
export default Dashboard;

View File

@@ -1,31 +0,0 @@
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as dashboardActions from '../actions';
import * as chartActions from '../../chart/chartAction';
import Dashboard from './Dashboard';
function mapStateToProps({ charts, dashboard, impressionId }) {
return {
initMessages: dashboard.common.flash_messages,
timeout: dashboard.common.conf.SUPERSET_WEBSERVER_TIMEOUT,
dashboard: dashboard.dashboard,
slices: charts,
datasources: dashboard.datasources,
filters: dashboard.filters,
refresh: !!dashboard.refresh,
userId: dashboard.userId,
isStarred: !!dashboard.isStarred,
editMode: dashboard.editMode,
impressionId,
};
}
function mapDispatchToProps(dispatch) {
const actions = { ...chartActions, ...dashboardActions };
return {
actions: bindActionCreators(actions, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);

View File

@@ -1,157 +0,0 @@
/* eslint-disable react/no-danger */
import React from 'react';
import PropTypes from 'prop-types';
import SliceHeader from './SliceHeader';
import ChartContainer from '../../chart/ChartContainer';
import '../../../stylesheets/dashboard.css';
const propTypes = {
timeout: PropTypes.number,
datasource: PropTypes.object,
isLoading: PropTypes.bool,
isCached: PropTypes.bool,
cachedDttm: PropTypes.string,
isExpanded: PropTypes.bool,
widgetHeight: PropTypes.number,
widgetWidth: PropTypes.number,
slice: PropTypes.object,
chartKey: PropTypes.string,
formData: PropTypes.object,
filters: PropTypes.object,
forceRefresh: PropTypes.func,
removeSlice: PropTypes.func,
updateSliceName: PropTypes.func,
toggleExpandSlice: PropTypes.func,
exploreChart: PropTypes.func,
exportCSV: PropTypes.func,
addFilter: PropTypes.func,
getFilters: PropTypes.func,
clearFilter: PropTypes.func,
removeFilter: PropTypes.func,
editMode: PropTypes.bool,
annotationQuery: PropTypes.object,
};
const defaultProps = {
forceRefresh: () => ({}),
removeSlice: () => ({}),
updateSliceName: () => ({}),
toggleExpandSlice: () => ({}),
exploreChart: () => ({}),
exportCSV: () => ({}),
addFilter: () => ({}),
getFilters: () => ({}),
clearFilter: () => ({}),
removeFilter: () => ({}),
editMode: false,
};
class GridCell extends React.PureComponent {
constructor(props) {
super(props);
const sliceId = this.props.slice.slice_id;
this.addFilter = this.props.addFilter.bind(this, sliceId);
this.getFilters = this.props.getFilters.bind(this, sliceId);
this.clearFilter = this.props.clearFilter.bind(this, sliceId);
this.removeFilter = this.props.removeFilter.bind(this, sliceId);
}
getDescriptionId(slice) {
return 'description_' + slice.slice_id;
}
getHeaderId(slice) {
return 'header_' + slice.slice_id;
}
width() {
return this.props.widgetWidth - 10;
}
height(slice) {
const widgetHeight = this.props.widgetHeight;
const headerHeight = this.headerHeight(slice);
const descriptionId = this.getDescriptionId(slice);
let descriptionHeight = 0;
if (this.props.isExpanded && this.refs[descriptionId]) {
descriptionHeight = this.refs[descriptionId].offsetHeight + 10;
}
return widgetHeight - headerHeight - descriptionHeight;
}
headerHeight(slice) {
const headerId = this.getHeaderId(slice);
return this.refs[headerId] ? this.refs[headerId].offsetHeight : 30;
}
render() {
const {
isExpanded, isLoading, isCached, cachedDttm,
removeSlice, updateSliceName, toggleExpandSlice, forceRefresh,
chartKey, slice, datasource, formData, timeout, annotationQuery,
exploreChart, exportCSV,
} = this.props;
return (
<div
className={isLoading ? 'slice-cell-highlight' : 'slice-cell'}
id={`${slice.slice_id}-cell`}
>
<div ref={this.getHeaderId(slice)}>
<SliceHeader
slice={slice}
isExpanded={isExpanded}
isCached={isCached}
cachedDttm={cachedDttm}
removeSlice={removeSlice}
updateSliceName={updateSliceName}
toggleExpandSlice={toggleExpandSlice}
forceRefresh={forceRefresh}
editMode={this.props.editMode}
annotationQuery={annotationQuery}
exploreChart={exploreChart}
exportCSV={exportCSV}
/>
</div>
{
/* This usage of dangerouslySetInnerHTML is safe since it is being used to render
markdown that is sanitized with bleach. See:
https://github.com/apache/incubator-superset/pull/4390
and
https://github.com/apache/incubator-superset/commit/b6fcc22d5a2cb7a5e92599ed5795a0169385a825 */}
<div
className="slice_description bs-callout bs-callout-default"
style={isExpanded ? {} : { display: 'none' }}
ref={this.getDescriptionId(slice)}
dangerouslySetInnerHTML={{ __html: slice.description_markeddown }}
/>
<div className="row chart-container">
<input type="hidden" value="false" />
<ChartContainer
containerId={`slice-container-${slice.slice_id}`}
chartKey={chartKey}
datasource={datasource}
formData={formData}
headerHeight={this.headerHeight(slice)}
height={this.height(slice)}
width={this.width()}
timeout={timeout}
vizType={slice.formData.viz_type}
addFilter={this.addFilter}
getFilters={this.getFilters}
clearFilter={this.clearFilter}
removeFilter={this.removeFilter}
/>
</div>
</div>
);
}
}
GridCell.propTypes = propTypes;
GridCell.defaultProps = defaultProps;
export default GridCell;

View File

@@ -1,198 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Responsive, WidthProvider } from 'react-grid-layout';
import GridCell from './GridCell';
require('react-grid-layout/css/styles.css');
require('react-resizable/css/styles.css');
const ResponsiveReactGridLayout = WidthProvider(Responsive);
const propTypes = {
dashboard: PropTypes.object.isRequired,
datasources: PropTypes.object,
charts: PropTypes.object.isRequired,
filters: PropTypes.object,
timeout: PropTypes.number,
onChange: PropTypes.func,
getFormDataExtra: PropTypes.func,
exploreChart: PropTypes.func,
exportCSV: PropTypes.func,
fetchSlice: PropTypes.func,
saveSlice: PropTypes.func,
removeSlice: PropTypes.func,
removeChart: PropTypes.func,
updateDashboardLayout: PropTypes.func,
toggleExpandSlice: PropTypes.func,
addFilter: PropTypes.func,
getFilters: PropTypes.func,
clearFilter: PropTypes.func,
removeFilter: PropTypes.func,
editMode: PropTypes.bool.isRequired,
};
const defaultProps = {
onChange: () => ({}),
getFormDataExtra: () => ({}),
exploreChart: () => ({}),
exportCSV: () => ({}),
fetchSlice: () => ({}),
saveSlice: () => ({}),
removeSlice: () => ({}),
removeChart: () => ({}),
updateDashboardLayout: () => ({}),
toggleExpandSlice: () => ({}),
addFilter: () => ({}),
getFilters: () => ({}),
clearFilter: () => ({}),
removeFilter: () => ({}),
};
class GridLayout extends React.Component {
constructor(props) {
super(props);
this.onResizeStop = this.onResizeStop.bind(this);
this.onDragStop = this.onDragStop.bind(this);
this.forceRefresh = this.forceRefresh.bind(this);
this.removeSlice = this.removeSlice.bind(this);
this.updateSliceName = this.props.dashboard.dash_edit_perm ?
this.updateSliceName.bind(this) : null;
}
onResizeStop(layout) {
this.props.updateDashboardLayout(layout);
this.props.onChange();
}
onDragStop(layout) {
this.props.updateDashboardLayout(layout);
this.props.onChange();
}
getWidgetId(slice) {
return 'widget_' + slice.slice_id;
}
getWidgetHeight(slice) {
const widgetId = this.getWidgetId(slice);
if (!widgetId || !this.refs[widgetId]) {
return 400;
}
return this.refs[widgetId].offsetHeight;
}
getWidgetWidth(slice) {
const widgetId = this.getWidgetId(slice);
if (!widgetId || !this.refs[widgetId]) {
return 400;
}
return this.refs[widgetId].offsetWidth;
}
findSliceIndexById(sliceId) {
return this.props.dashboard.slices
.map(slice => (slice.slice_id)).indexOf(sliceId);
}
forceRefresh(sliceId) {
return this.props.fetchSlice(this.props.charts['slice_' + sliceId], true);
}
removeSlice(slice) {
if (!slice) {
return;
}
// remove slice dashboard and charts
this.props.removeSlice(slice);
this.props.removeChart(this.props.charts['slice_' + slice.slice_id].chartKey);
this.props.onChange();
}
updateSliceName(sliceId, sliceName) {
const index = this.findSliceIndexById(sliceId);
if (index === -1) {
return;
}
const currentSlice = this.props.dashboard.slices[index];
if (currentSlice.slice_name === sliceName) {
return;
}
this.props.saveSlice(currentSlice, sliceName);
}
isExpanded(slice) {
return this.props.dashboard.metadata.expanded_slices &&
this.props.dashboard.metadata.expanded_slices[slice.slice_id];
}
render() {
const cells = this.props.dashboard.slices.map((slice) => {
const chartKey = `slice_${slice.slice_id}`;
const currentChart = this.props.charts[chartKey];
const queryResponse = currentChart.queryResponse || {};
return (
<div
id={'slice_' + slice.slice_id}
key={slice.slice_id}
data-slice-id={slice.slice_id}
className={`widget ${slice.form_data.viz_type}`}
ref={this.getWidgetId(slice)}
>
<GridCell
slice={slice}
chartKey={chartKey}
datasource={this.props.datasources[slice.form_data.datasource]}
filters={this.props.filters}
formData={this.props.getFormDataExtra(slice)}
timeout={this.props.timeout}
widgetHeight={this.getWidgetHeight(slice)}
widgetWidth={this.getWidgetWidth(slice)}
exploreChart={this.props.exploreChart}
exportCSV={this.props.exportCSV}
isExpanded={!!this.isExpanded(slice)}
isLoading={currentChart.chartStatus === 'loading'}
isCached={queryResponse.is_cached}
cachedDttm={queryResponse.cached_dttm}
toggleExpandSlice={this.props.toggleExpandSlice}
forceRefresh={this.forceRefresh}
removeSlice={this.removeSlice}
updateSliceName={this.updateSliceName}
addFilter={this.props.addFilter}
getFilters={this.props.getFilters}
clearFilter={this.props.clearFilter}
removeFilter={this.props.removeFilter}
editMode={this.props.editMode}
annotationQuery={currentChart.annotationQuery}
annotationError={currentChart.annotationError}
/>
</div>);
});
return (
<ResponsiveReactGridLayout
className="layout"
layouts={{ lg: this.props.dashboard.layout }}
onResizeStop={this.onResizeStop}
onDragStop={this.onDragStop}
cols={{ lg: 48, md: 48, sm: 40, xs: 32, xxs: 24 }}
rowHeight={10}
autoSize
margin={[20, 20]}
useCSSTransforms
draggableHandle=".drag"
>
{cells}
</ResponsiveReactGridLayout>
);
}
}
GridLayout.propTypes = propTypes;
GridLayout.defaultProps = defaultProps;
export default GridLayout;

View File

@@ -1,116 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import Controls from './Controls';
import EditableTitle from '../../components/EditableTitle';
import Button from '../../components/Button';
import FaveStar from '../../components/FaveStar';
import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
import { t } from '../../locales';
const propTypes = {
dashboard: PropTypes.object.isRequired,
filters: PropTypes.object.isRequired,
userId: PropTypes.string.isRequired,
isStarred: PropTypes.bool,
addSlicesToDashboard: PropTypes.func,
onSave: PropTypes.func,
onChange: PropTypes.func,
fetchFaveStar: PropTypes.func,
renderSlices: PropTypes.func,
saveFaveStar: PropTypes.func,
serialize: PropTypes.func,
startPeriodicRender: PropTypes.func,
updateDashboardTitle: PropTypes.func,
editMode: PropTypes.bool.isRequired,
setEditMode: PropTypes.func.isRequired,
unsavedChanges: PropTypes.bool.isRequired,
};
class Header extends React.PureComponent {
constructor(props) {
super(props);
this.handleSaveTitle = this.handleSaveTitle.bind(this);
this.toggleEditMode = this.toggleEditMode.bind(this);
}
handleSaveTitle(title) {
this.props.updateDashboardTitle(title);
}
toggleEditMode() {
this.props.setEditMode(!this.props.editMode);
}
renderUnsaved() {
if (!this.props.unsavedChanges) {
return null;
}
return (
<InfoTooltipWithTrigger
label="unsaved"
tooltip={t('Unsaved changes')}
icon="exclamation-triangle"
className="text-danger m-r-5"
placement="top"
/>
);
}
renderEditButton() {
if (!this.props.dashboard.dash_save_perm) {
return null;
}
const btnText = this.props.editMode ? 'Switch to View Mode' : 'Edit Dashboard';
return (
<Button
bsStyle="default"
className="m-r-5"
style={{ width: '150px' }}
onClick={this.toggleEditMode}
>
{btnText}
</Button>);
}
render() {
const dashboard = this.props.dashboard;
return (
<div className="title">
<div className="pull-left">
<h1 className="outer-container pull-left">
<EditableTitle
title={dashboard.dashboard_title}
canEdit={dashboard.dash_save_perm && this.props.editMode}
onSaveTitle={this.handleSaveTitle}
showTooltip={this.props.editMode}
/>
<span className="favstar m-r-5">
<FaveStar
itemId={dashboard.id}
fetchFaveStar={this.props.fetchFaveStar}
saveFaveStar={this.props.saveFaveStar}
isStarred={this.props.isStarred}
/>
</span>
{this.renderUnsaved()}
</h1>
</div>
<div className="pull-right" style={{ marginTop: '35px' }}>
{this.renderEditButton()}
<Controls
dashboard={dashboard}
filters={this.props.filters}
userId={this.props.userId}
addSlicesToDashboard={this.props.addSlicesToDashboard}
onSave={this.props.onSave}
onChange={this.props.onChange}
renderSlices={this.props.renderSlices}
serialize={this.props.serialize}
startPeriodicRender={this.props.startPeriodicRender}
editMode={this.props.editMode}
/>
</div>
<div className="clearfix" />
</div>
);
}
}
Header.propTypes = propTypes;
export default Header;

View File

@@ -1,161 +0,0 @@
/* global notify */
import React from 'react';
import PropTypes from 'prop-types';
import { Button, FormControl, FormGroup, Radio } from 'react-bootstrap';
import { getAjaxErrorMsg } from '../../modules/utils';
import ModalTrigger from '../../components/ModalTrigger';
import { t } from '../../locales';
import Checkbox from '../../components/Checkbox';
const $ = window.$ = require('jquery');
const propTypes = {
css: PropTypes.string,
dashboard: PropTypes.object.isRequired,
triggerNode: PropTypes.node.isRequired,
filters: PropTypes.object.isRequired,
serialize: PropTypes.func,
onSave: PropTypes.func,
};
class SaveModal extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
dashboard: props.dashboard,
css: props.css,
saveType: 'overwrite',
newDashName: props.dashboard.dashboard_title + ' [copy]',
duplicateSlices: false,
};
this.modal = null;
this.handleSaveTypeChange = this.handleSaveTypeChange.bind(this);
this.handleNameChange = this.handleNameChange.bind(this);
this.saveDashboard = this.saveDashboard.bind(this);
}
toggleDuplicateSlices() {
this.setState({ duplicateSlices: !this.state.duplicateSlices });
}
handleSaveTypeChange(event) {
this.setState({
saveType: event.target.value,
});
}
handleNameChange(event) {
this.setState({
newDashName: event.target.value,
saveType: 'newDashboard',
});
}
saveDashboardRequest(data, url, saveType) {
const saveModal = this.modal;
const onSaveDashboard = this.props.onSave;
Object.assign(data, { css: this.props.css });
$.ajax({
type: 'POST',
url,
data: {
data: JSON.stringify(data),
},
success(resp) {
saveModal.close();
onSaveDashboard();
if (saveType === 'newDashboard') {
window.location = `/superset/dashboard/${resp.id}/`;
} else {
notify.success(t('This dashboard was saved successfully.'));
}
},
error(error) {
saveModal.close();
const errorMsg = getAjaxErrorMsg(error);
notify.error(t('Sorry, there was an error saving this dashboard: ') + '</ br>' + errorMsg);
},
});
}
saveDashboard(saveType, newDashboardTitle) {
const dashboard = this.props.dashboard;
const positions = this.props.serialize();
const data = {
positions,
css: this.state.css,
expanded_slices: dashboard.metadata.expanded_slices || {},
dashboard_title: dashboard.dashboard_title,
default_filters: JSON.stringify(this.props.filters),
duplicate_slices: this.state.duplicateSlices,
};
let url = null;
if (saveType === 'overwrite') {
url = `/superset/save_dash/${dashboard.id}/`;
this.saveDashboardRequest(data, url, saveType);
} else if (saveType === 'newDashboard') {
if (!newDashboardTitle) {
this.modal.close();
showModal({
title: t('Error'),
body: t('You must pick a name for the new dashboard'),
});
} else {
data.dashboard_title = newDashboardTitle;
url = `/superset/copy_dash/${dashboard.id}/`;
this.saveDashboardRequest(data, url, saveType);
}
}
}
render() {
return (
<ModalTrigger
ref={(modal) => { this.modal = modal; }}
isMenuItem
triggerNode={this.props.triggerNode}
modalTitle={t('Save Dashboard')}
modalBody={
<FormGroup>
<Radio
value="overwrite"
onChange={this.handleSaveTypeChange}
checked={this.state.saveType === 'overwrite'}
>
{t('Overwrite Dashboard [%s]', this.props.dashboard.dashboard_title)}
</Radio>
<hr />
<Radio
value="newDashboard"
onChange={this.handleSaveTypeChange}
checked={this.state.saveType === 'newDashboard'}
>
{t('Save as:')}
</Radio>
<FormControl
type="text"
placeholder={t('[dashboard name]')}
value={this.state.newDashName}
onFocus={this.handleNameChange}
onChange={this.handleNameChange}
/>
<div className="m-l-25 m-t-5">
<Checkbox
checked={this.state.duplicateSlices}
onChange={this.toggleDuplicateSlices.bind(this)}
/>
<span className="m-l-5">also copy (duplicate) slices</span>
</div>
</FormGroup>
}
modalFooter={
<div>
<Button
bsStyle="primary"
onClick={() => { this.saveDashboard(this.state.saveType, this.state.newDashName); }}
>
{t('Save')}
</Button>
</div>
}
/>
);
}
}
SaveModal.propTypes = propTypes;
export default SaveModal;

View File

@@ -1,219 +0,0 @@
import React from 'react';
import $ from 'jquery';
import PropTypes from 'prop-types';
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
import ModalTrigger from '../../components/ModalTrigger';
import { t } from '../../locales';
require('react-bootstrap-table/css/react-bootstrap-table.css');
const propTypes = {
dashboard: PropTypes.object.isRequired,
triggerNode: PropTypes.node.isRequired,
userId: PropTypes.string.isRequired,
addSlicesToDashboard: PropTypes.func,
};
class SliceAdder extends React.Component {
constructor(props) {
super(props);
this.state = {
slices: [],
slicesLoaded: false,
selectionMap: {},
};
this.options = {
defaultSortOrder: 'desc',
defaultSortName: 'modified',
sizePerPage: 10,
};
this.addSlices = this.addSlices.bind(this);
this.toggleSlice = this.toggleSlice.bind(this);
this.selectRowProp = {
mode: 'checkbox',
clickToSelect: true,
onSelect: this.toggleSlice,
};
}
componentWillUnmount() {
if (this.slicesRequest) {
this.slicesRequest.abort();
}
}
onEnterModal() {
const uri = `/sliceaddview/api/read?_flt_0_created_by=${this.props.userId}`;
this.slicesRequest = $.ajax({
url: uri,
type: 'GET',
success: (response) => {
// Prepare slice data for table
const slices = response.result.map(slice => ({
id: slice.id,
sliceName: slice.slice_name,
vizType: slice.viz_type,
datasourceLink: slice.datasource_link,
modified: slice.modified,
}));
this.setState({
slices,
selectionMap: {},
slicesLoaded: true,
});
},
error: (error) => {
this.errored = true;
this.setState({
errorMsg: t('Sorry, there was an error fetching slices to this dashboard: ') +
this.getAjaxErrorMsg(error),
});
},
});
}
getAjaxErrorMsg(error) {
const respJSON = error.responseJSON;
return (respJSON && respJSON.message) ? respJSON.message :
error.responseText;
}
addSlices() {
const adder = this;
this.props.addSlicesToDashboard(Object.keys(this.state.selectionMap))
// if successful, page will be reloaded.
.fail((error) => {
adder.errored = true;
adder.setState({
errorMsg: t('Sorry, there was an error adding slices to this dashboard: ') +
this.getAjaxErrorMsg(error),
});
});
}
toggleSlice(slice) {
const selectionMap = Object.assign({}, this.state.selectionMap);
selectionMap[slice.id] = !selectionMap[slice.id];
this.setState({ selectionMap });
}
modifiedDateComparator(a, b, order) {
if (order === 'desc') {
if (a.changed_on > b.changed_on) {
return -1;
} else if (a.changed_on < b.changed_on) {
return 1;
}
return 0;
}
if (a.changed_on < b.changed_on) {
return -1;
} else if (a.changed_on > b.changed_on) {
return 1;
}
return 0;
}
render() {
const hideLoad = this.state.slicesLoaded || this.errored;
let enableAddSlice = this.state.selectionMap && Object.keys(this.state.selectionMap);
if (enableAddSlice) {
enableAddSlice = enableAddSlice.some(function (key) {
return this.state.selectionMap[key];
}, this);
}
const modalContent = (
<div>
<img
src="/static/assets/images/loading.gif"
className={'loading ' + (hideLoad ? 'hidden' : '')}
alt={hideLoad ? '' : 'loading'}
/>
<div className={this.errored ? '' : 'hidden'}>
{this.state.errorMsg}
</div>
<div className={this.state.slicesLoaded ? '' : 'hidden'}>
<BootstrapTable
ref="table"
data={this.state.slices}
selectRow={this.selectRowProp}
options={this.options}
hover
search
pagination
condensed
height="auto"
>
<TableHeaderColumn
dataField="id"
isKey
dataSort
hidden
/>
<TableHeaderColumn
dataField="sliceName"
dataSort
>
{t('Name')}
</TableHeaderColumn>
<TableHeaderColumn
dataField="vizType"
dataSort
>
{t('Viz')}
</TableHeaderColumn>
<TableHeaderColumn
dataField="datasourceLink"
dataSort
// Will cause react-bootstrap-table to interpret the HTML returned
dataFormat={datasourceLink => datasourceLink}
>
{t('Datasource')}
</TableHeaderColumn>
<TableHeaderColumn
dataField="modified"
dataSort
sortFunc={this.modifiedDateComparator}
// Will cause react-bootstrap-table to interpret the HTML returned
dataFormat={modified => modified}
>
{t('Modified')}
</TableHeaderColumn>
</BootstrapTable>
<button
type="button"
className="btn btn-default"
data-dismiss="modal"
onClick={this.addSlices}
disabled={!enableAddSlice}
>
{t('Add Slices')}
</button>
</div>
</div>
);
return (
<ModalTrigger
triggerNode={this.props.triggerNode}
tooltip={t('Add a new slice to the dashboard')}
beforeOpen={this.onEnterModal.bind(this)}
isMenuItem
modalBody={modalContent}
bsSize="large"
setModalAsTriggerChildren
modalTitle={t('Add Slices to Dashboard')}
/>
);
}
}
SliceAdder.propTypes = propTypes;
export default SliceAdder;

View File

@@ -1,178 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { t } from '../../locales';
import EditableTitle from '../../components/EditableTitle';
import TooltipWrapper from '../../components/TooltipWrapper';
const propTypes = {
slice: PropTypes.object.isRequired,
isExpanded: PropTypes.bool,
isCached: PropTypes.bool,
cachedDttm: PropTypes.string,
removeSlice: PropTypes.func,
updateSliceName: PropTypes.func,
toggleExpandSlice: PropTypes.func,
forceRefresh: PropTypes.func,
exploreChart: PropTypes.func,
exportCSV: PropTypes.func,
editMode: PropTypes.bool,
annotationQuery: PropTypes.object,
annotationError: PropTypes.object,
};
const defaultProps = {
forceRefresh: () => ({}),
removeSlice: () => ({}),
updateSliceName: () => ({}),
toggleExpandSlice: () => ({}),
exploreChart: () => ({}),
exportCSV: () => ({}),
editMode: false,
};
class SliceHeader extends React.PureComponent {
constructor(props) {
super(props);
this.onSaveTitle = this.onSaveTitle.bind(this);
this.onToggleExpandSlice = this.onToggleExpandSlice.bind(this);
this.exportCSV = this.props.exportCSV.bind(this, this.props.slice);
this.exploreChart = this.props.exploreChart.bind(this, this.props.slice);
this.forceRefresh = this.props.forceRefresh.bind(this, this.props.slice.slice_id);
this.removeSlice = this.props.removeSlice.bind(this, this.props.slice);
}
onSaveTitle(newTitle) {
if (this.props.updateSliceName) {
this.props.updateSliceName(this.props.slice.slice_id, newTitle);
}
}
onToggleExpandSlice() {
this.props.toggleExpandSlice(this.props.slice, !this.props.isExpanded);
}
render() {
const slice = this.props.slice;
const isCached = this.props.isCached;
const cachedWhen = moment.utc(this.props.cachedDttm).fromNow();
const refreshTooltip = isCached ?
t('Served from data cached %s . Click to force refresh.', cachedWhen) :
t('Force refresh data');
const annoationsLoading = t('Annotation layers are still loading.');
const annoationsError = t('One ore more annotation layers failed loading.');
return (
<div className="row chart-header">
<div className="col-md-12">
<div className="header">
<EditableTitle
title={slice.slice_name}
canEdit={!!this.props.updateSliceName && this.props.editMode}
onSaveTitle={this.onSaveTitle}
noPermitTooltip={'You don\'t have the rights to alter this dashboard.'}
/>
{!!Object.values(this.props.annotationQuery || {}).length &&
<TooltipWrapper
label="annotations-loading"
placement="top"
tooltip={annoationsLoading}
>
<i className="fa fa-refresh warning" />
</TooltipWrapper>
}
{!!Object.values(this.props.annotationError || {}).length &&
<TooltipWrapper
label="annoation-errors"
placement="top"
tooltip={annoationsError}
>
<i className="fa fa-exclamation-circle danger" />
</TooltipWrapper>
}
</div>
<div className="chart-controls">
<div id={'controls_' + slice.slice_id} className="pull-right">
{this.props.editMode &&
<a>
<TooltipWrapper
placement="top"
label="move"
tooltip={t('Move chart')}
>
<i className="fa fa-arrows drag" />
</TooltipWrapper>
</a>
}
<a className={`refresh ${isCached ? 'danger' : ''}`} onClick={this.forceRefresh}>
<TooltipWrapper
placement="top"
label="refresh"
tooltip={refreshTooltip}
>
<i className="fa fa-repeat" />
</TooltipWrapper>
</a>
{slice.description &&
<a onClick={this.onToggleExpandSlice}>
<TooltipWrapper
placement="top"
label="description"
tooltip={t('Toggle chart description')}
>
<i className="fa fa-info-circle slice_info" />
</TooltipWrapper>
</a>
}
<a href={slice.edit_url} target="_blank">
<TooltipWrapper
placement="top"
label="edit"
tooltip={t('Edit chart')}
>
<i className="fa fa-pencil" />
</TooltipWrapper>
</a>
<a className="exportCSV" onClick={this.exportCSV}>
<TooltipWrapper
placement="top"
label="exportCSV"
tooltip={t('Export CSV')}
>
<i className="fa fa-table" />
</TooltipWrapper>
</a>
<a className="exploreChart" onClick={this.exploreChart}>
<TooltipWrapper
placement="top"
label="exploreChart"
tooltip={t('Explore chart')}
>
<i className="fa fa-share" />
</TooltipWrapper>
</a>
{this.props.editMode &&
<a className="remove-chart" onClick={this.removeSlice}>
<TooltipWrapper
placement="top"
label="close"
tooltip={t('Remove chart from dashboard')}
>
<i className="fa fa-close" />
</TooltipWrapper>
</a>
}
</div>
</div>
</div>
</div>
);
}
}
SliceHeader.propTypes = propTypes;
SliceHeader.defaultProps = defaultProps;
export default SliceHeader;

View File

@@ -1,210 +0,0 @@
import { combineReducers } from 'redux';
import d3 from 'd3';
import shortid from 'shortid';
import charts, { chart } from '../chart/chartReducer';
import * as actions from './actions';
import { getParam } from '../modules/utils';
import { alterInArr, removeFromArr } from '../reduxUtils';
import { applyDefaultFormData } from '../explore/stores/store';
import { getColorFromScheme } from '../modules/colors';
export function getInitialState(bootstrapData) {
const { user_id, datasources, common } = bootstrapData;
delete common.locale;
delete common.language_pack;
const dashboard = { ...bootstrapData.dashboard_data };
let filters = {};
try {
// allow request parameter overwrite dashboard metadata
filters = JSON.parse(getParam('preselect_filters') || dashboard.metadata.default_filters);
} catch (e) {
//
}
// Priming the color palette with user's label-color mapping provided in
// the dashboard's JSON metadata
if (dashboard.metadata && dashboard.metadata.label_colors) {
const colorMap = dashboard.metadata.label_colors;
for (const label in colorMap) {
getColorFromScheme(label, null, colorMap[label]);
}
}
dashboard.posDict = {};
dashboard.layout = [];
if (dashboard.position_json) {
dashboard.position_json.forEach((position) => {
dashboard.posDict[position.slice_id] = position;
});
}
const lastRowId = Math.max.apply(null,
dashboard.position_json.map(pos => (pos.row + pos.size_y)));
let newSliceCounter = 0;
dashboard.slices.forEach((slice) => {
const sliceId = slice.slice_id;
let pos = dashboard.posDict[sliceId];
if (!pos) {
// append new slices to dashboard bottom, 3 slices per row
pos = {
col: (newSliceCounter % 3) * 16 + 1,
row: lastRowId + Math.floor(newSliceCounter / 3) * 16,
size_x: 16,
size_y: 16,
};
newSliceCounter++;
}
dashboard.layout.push({
i: String(sliceId),
x: pos.col - 1,
y: pos.row,
w: pos.size_x,
minW: 2,
h: pos.size_y,
});
});
// will use charts action/reducers to handle chart render
const initCharts = {};
dashboard.slices.forEach((slice) => {
const chartKey = 'slice_' + slice.slice_id;
initCharts[chartKey] = { ...chart,
chartKey,
slice_id: slice.slice_id,
form_data: slice.form_data,
formData: applyDefaultFormData(slice.form_data),
};
});
// also need to add formData for dashboard.slices
dashboard.slices = dashboard.slices.map(slice =>
({ ...slice, formData: applyDefaultFormData(slice.form_data) }),
);
return {
charts: initCharts,
dashboard: { filters, dashboard, userId: user_id, datasources, common, editMode: false },
};
}
export const dashboard = function (state = {}, action) {
const actionHandlers = {
[actions.UPDATE_DASHBOARD_TITLE]() {
const newDashboard = { ...state.dashboard, dashboard_title: action.title };
return { ...state, dashboard: newDashboard };
},
[actions.UPDATE_DASHBOARD_LAYOUT]() {
const newDashboard = { ...state.dashboard, layout: action.layout };
return { ...state, dashboard: newDashboard };
},
[actions.REMOVE_SLICE]() {
const key = String(action.slice.slice_id);
const newLayout = state.dashboard.layout.filter(reactPos => (reactPos.i !== key));
const newDashboard = removeFromArr(state.dashboard, 'slices', action.slice, 'slice_id');
// if this slice is a filter
const newFilter = { ...state.filters };
let refresh = false;
if (state.filters[key]) {
delete newFilter[key];
refresh = true;
}
return {
...state,
dashboard: { ...newDashboard, layout: newLayout },
filters: newFilter,
refresh,
};
},
[actions.TOGGLE_FAVE_STAR]() {
return { ...state, isStarred: action.isStarred };
},
[actions.SET_EDIT_MODE]() {
return { ...state, editMode: action.editMode };
},
[actions.TOGGLE_EXPAND_SLICE]() {
const updatedExpandedSlices = { ...state.dashboard.metadata.expanded_slices };
const sliceId = action.slice.slice_id;
if (action.isExpanded) {
updatedExpandedSlices[sliceId] = true;
} else {
delete updatedExpandedSlices[sliceId];
}
const metadata = { ...state.dashboard.metadata, expanded_slices: updatedExpandedSlices };
const newDashboard = { ...state.dashboard, metadata };
return { ...state, dashboard: newDashboard };
},
// filters
[actions.ADD_FILTER]() {
const selectedSlice = state.dashboard.slices
.find(slice => (slice.slice_id === action.sliceId));
if (!selectedSlice) {
return state;
}
let filters = state.filters;
const { sliceId, col, vals, merge, refresh } = action;
const filterKeys = ['__from', '__to', '__time_col',
'__time_grain', '__time_origin', '__granularity'];
if (filterKeys.indexOf(col) >= 0 ||
selectedSlice.formData.groupby.indexOf(col) !== -1) {
let newFilter = {};
if (!(sliceId in filters)) {
// Straight up set the filters if none existed for the slice
newFilter = { [col]: vals };
} else if (filters[sliceId] && !(col in filters[sliceId]) || !merge) {
newFilter = { ...filters[sliceId], [col]: vals };
// d3.merge pass in array of arrays while some value form filter components
// from and to filter box require string to be process and return
} else if (filters[sliceId][col] instanceof Array) {
newFilter[col] = d3.merge([filters[sliceId][col], vals]);
} else {
newFilter[col] = d3.merge([[filters[sliceId][col]], vals])[0] || '';
}
filters = { ...filters, [sliceId]: newFilter };
}
return { ...state, filters, refresh };
},
[actions.CLEAR_FILTER]() {
const newFilters = { ...state.filters };
delete newFilters[action.sliceId];
return { ...state, filter: newFilters, refresh: true };
},
[actions.REMOVE_FILTER]() {
const { sliceId, col, vals, refresh } = action;
const excluded = new Set(vals);
const valFilter = val => !excluded.has(val);
let filters = state.filters;
// Have to be careful not to modify the dashboard state so that
// the render actually triggers
if (sliceId in state.filters && col in state.filters[sliceId]) {
const newFilter = filters[sliceId][col].filter(valFilter);
filters = { ...filters, [sliceId]: newFilter };
}
return { ...state, filters, refresh };
},
// slice reducer
[actions.UPDATE_SLICE_NAME]() {
const newDashboard = alterInArr(
state.dashboard, 'slices',
action.slice, { slice_name: action.sliceName },
'slice_id');
return { ...state, dashboard: newDashboard };
},
};
if (action.type in actionHandlers) {
return actionHandlers[action.type]();
}
return state;
};
export default combineReducers({
charts,
dashboard,
impressionId: () => (shortid.generate()),
});

View File

@@ -1,126 +0,0 @@
/* eslint camelcase: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Alert } from 'react-bootstrap';
import visTypes, { sectionsToRender } from '../stores/visTypes';
import ControlPanelSection from './ControlPanelSection';
import ControlRow from './ControlRow';
import Control from './Control';
import controls from '../stores/controls';
import * as actions from '../actions/exploreActions';
const propTypes = {
actions: PropTypes.object.isRequired,
alert: PropTypes.string,
datasource_type: PropTypes.string.isRequired,
exploreState: PropTypes.object.isRequired,
controls: PropTypes.object.isRequired,
form_data: PropTypes.object.isRequired,
isDatasourceMetaLoading: PropTypes.bool.isRequired,
};
class ControlPanelsContainer extends React.Component {
constructor(props) {
super(props);
this.removeAlert = this.removeAlert.bind(this);
this.getControlData = this.getControlData.bind(this);
}
getControlData(controlName) {
const control = this.props.controls[controlName];
// Identifying mapStateToProps function to apply (logic can't be in store)
let mapF = controls[controlName].mapStateToProps;
// Looking to find mapStateToProps override for this viz type
const controlOverrides = visTypes[this.props.controls.viz_type.value].controlOverrides || {};
if (controlOverrides[controlName] && controlOverrides[controlName].mapStateToProps) {
mapF = controlOverrides[controlName].mapStateToProps;
}
// Applying mapStateToProps if needed
if (mapF) {
return Object.assign({}, control, mapF(this.props.exploreState, control));
}
return control;
}
sectionsToRender() {
return sectionsToRender(this.props.form_data.viz_type, this.props.datasource_type);
}
removeAlert() {
this.props.actions.removeControlPanelAlert();
}
render() {
const ctrls = this.props.controls;
return (
<div className="scrollbar-container">
<div className="scrollbar-content">
{this.props.alert &&
<Alert bsStyle="warning">
{this.props.alert}
<i
className="fa fa-close pull-right"
onClick={this.removeAlert}
style={{ cursor: 'pointer' }}
/>
</Alert>
}
{this.sectionsToRender().map((section) => {
const hasErrors = section.controlSetRows.some(rows => rows.some(s => (
ctrls[s] &&
ctrls[s].validationErrors &&
(ctrls[s].validationErrors.length > 0)
)));
return (
<ControlPanelSection
key={section.label}
label={section.label}
startExpanded={section.expanded}
hasErrors={hasErrors}
description={section.description}
>
{section.controlSetRows.map((controlSets, i) => (
<ControlRow
key={`controlsetrow-${i}`}
className="control-row"
controls={controlSets.map(controlName => (
controlName &&
ctrls[controlName] &&
<Control
name={controlName}
key={`control-${controlName}`}
value={this.props.form_data[controlName]}
validationErrors={ctrls[controlName].validationErrors}
actions={this.props.actions}
{...this.getControlData(controlName)}
/>
))}
/>
))}
</ControlPanelSection>);
})}
</div>
</div>
);
}
}
ControlPanelsContainer.propTypes = propTypes;
function mapStateToProps({ explore }) {
return {
alert: explore.controlPanelAlert,
isDatasourceMetaLoading: explore.isDatasourceMetaLoading,
controls: explore.controls,
exploreState: explore,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch),
};
}
export { ControlPanelsContainer };
export default connect(mapStateToProps, mapDispatchToProps)(ControlPanelsContainer);

View File

@@ -1,219 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Button, ButtonGroup, FormControl, InputGroup,
Label, OverlayTrigger, Popover, Glyphicon,
} from 'react-bootstrap';
import Select from 'react-select';
import Datetime from 'react-datetime';
import 'react-datetime/css/react-datetime.css';
import moment from 'moment';
import ControlHeader from '../ControlHeader';
import PopoverSection from '../../../components/PopoverSection';
const RELATIVE_TIME_OPTIONS = ['ago', 'from now'];
const TIME_GRAIN_OPTIONS = ['seconds', 'minutes', 'days', 'weeks', 'months', 'years'];
const propTypes = {
animation: PropTypes.bool,
name: PropTypes.string.isRequired,
label: PropTypes.string,
description: PropTypes.string,
onChange: PropTypes.func,
value: PropTypes.string,
height: PropTypes.number,
};
const defaultProps = {
animation: true,
onChange: () => {},
value: '',
};
export default class DateFilterControl extends React.Component {
constructor(props) {
super(props);
const value = props.value || '';
this.state = {
num: '7',
grain: 'days',
rel: 'ago',
dttm: '',
type: 'free',
free: '',
};
const words = value.split(' ');
if (words.length >= 3 && RELATIVE_TIME_OPTIONS.indexOf(words[2]) >= 0) {
this.state.num = words[0];
this.state.grain = words[1];
this.state.rel = words[2];
this.state.type = 'rel';
} else if (moment(value).isValid()) {
this.state.dttm = value;
this.state.type = 'fix';
} else {
this.state.free = value;
this.state.type = 'free';
}
}
onControlChange(target, opt) {
this.setState({ [target]: opt.value });
}
onNumberChange(event) {
this.setState({ num: event.target.value });
}
onFreeChange(event) {
this.setState({ free: event.target.value });
}
setType(type) {
this.setState({ type });
}
setValueAndClose(val) {
this.setState({ type: 'free', free: val }, this.close);
}
setDatetime(dttm) {
this.setState({ dttm: dttm.format().substring(0, 19) });
}
close() {
let val;
if (this.state.type === 'rel') {
val = `${this.state.num} ${this.state.grain} ${this.state.rel}`;
} else if (this.state.type === 'fix') {
val = this.state.dttm;
} else if (this.state.type === 'free') {
val = this.state.free;
}
this.props.onChange(val);
this.refs.trigger.hide();
}
renderPopover() {
return (
<Popover id="filter-popover">
<div style={{ width: '250px' }}>
<PopoverSection
title="Fixed"
isSelected={this.state.type === 'fix'}
onSelect={this.setType.bind(this, 'fix')}
>
<InputGroup bsSize="small">
<InputGroup.Addon>
<Glyphicon glyph="calendar" />
</InputGroup.Addon>
<Datetime
inputProps={{ className: 'form-control input-sm' }}
dateFormat="YYYY-MM-DD"
defaultValue={this.state.dttm}
onFocus={this.setType.bind(this, 'fix')}
onChange={this.setDatetime.bind(this)}
timeFormat="h:mm:ss"
/>
</InputGroup>
</PopoverSection>
<PopoverSection
title="Relative"
isSelected={this.state.type === 'rel'}
onSelect={this.setType.bind(this, 'rel')}
>
<div className="clearfix">
<div style={{ width: '50px' }} className="input-inline">
<FormControl
onFocus={this.setType.bind(this, 'rel')}
value={this.state.num}
onChange={this.onNumberChange.bind(this)}
bsSize="small"
/>
</div>
<div style={{ width: '95px' }} className="input-inline">
<Select
onFocus={this.setType.bind(this, 'rel')}
value={this.state.grain}
clearable={false}
options={TIME_GRAIN_OPTIONS.map(s => ({ label: s, value: s }))}
onChange={this.onControlChange.bind(this, 'grain')}
/>
</div>
<div style={{ width: '95px' }} className="input-inline">
<Select
value={this.state.rel}
onFocus={this.setType.bind(this, 'rel')}
clearable={false}
options={RELATIVE_TIME_OPTIONS.map(s => ({ label: s, value: s }))}
onChange={this.onControlChange.bind(this, 'rel')}
/>
</div>
</div>
</PopoverSection>
<PopoverSection
title="Free form"
isSelected={this.state.type === 'free'}
onSelect={this.setType.bind(this, 'free')}
info={
'Superset supports smart date parsing. Strings like `last sunday` or ' +
'`last october` can be used.'
}
>
<FormControl
onFocus={this.setType.bind(this, 'free')}
value={this.state.free}
onChange={this.onFreeChange.bind(this)}
bsSize="small"
/>
</PopoverSection>
<div className="clearfix">
<Button
bsSize="small"
className="float-left ok"
bsStyle="primary"
onClick={this.close.bind(this)}
>
Ok
</Button>
<ButtonGroup
className="float-right"
>
<Button
bsSize="small"
className="now"
onClick={this.setValueAndClose.bind(this, 'now')}
>
now
</Button>
<Button
bsSize="small"
className="clear"
onClick={this.setValueAndClose.bind(this, '')}
>
clear
</Button>
</ButtonGroup>
</div>
</div>
</Popover>
);
}
render() {
const value = this.props.value || '';
return (
<div>
<ControlHeader {...this.props} />
<OverlayTrigger
animation={this.props.animation}
container={document.body}
trigger="click"
rootClose
ref="trigger"
placement="right"
overlay={this.renderPopover()}
>
<Label style={{ cursor: 'pointer' }}>
{value.replace('T00:00:00', '') || '∞'}
</Label>
</OverlayTrigger>
</div>
);
}
}
DateFilterControl.propTypes = propTypes;
DateFilterControl.defaultProps = defaultProps;

View File

@@ -1,181 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import Select from 'react-select';
import { Button, Row, Col } from 'react-bootstrap';
import SelectControl from './SelectControl';
import { t } from '../../../locales';
const operatorsArr = [
{ val: 'in', type: 'array', useSelect: true, multi: true },
{ val: 'not in', type: 'array', useSelect: true, multi: true },
{ val: '==', type: 'string', useSelect: true, multi: false, havingOnly: true },
{ val: '!=', type: 'string', useSelect: true, multi: false, havingOnly: true },
{ val: '>=', type: 'string', havingOnly: true },
{ val: '<=', type: 'string', havingOnly: true },
{ val: '>', type: 'string', havingOnly: true },
{ val: '<', type: 'string', havingOnly: true },
{ val: 'regex', type: 'string', datasourceTypes: ['druid'] },
{ val: 'LIKE', type: 'string', datasourceTypes: ['table'] },
];
const operators = {};
operatorsArr.forEach((op) => {
operators[op.val] = op;
});
const propTypes = {
changeFilter: PropTypes.func,
removeFilter: PropTypes.func,
filter: PropTypes.object.isRequired,
datasource: PropTypes.object,
having: PropTypes.bool,
valuesLoading: PropTypes.bool,
valueChoices: PropTypes.array,
};
const defaultProps = {
changeFilter: () => {},
removeFilter: () => {},
datasource: null,
having: false,
valuesLoading: false,
valueChoices: [],
};
export default class Filter extends React.Component {
switchFilterValue(prevOp, nextOp) {
if (operators[prevOp].type !== operators[nextOp].type) {
// Switch from array to string or vice versa
const val = this.props.filter.val;
let newVal;
if (operators[nextOp].type === 'string') {
if (!val || !val.length) {
newVal = '';
} else {
newVal = val[0];
}
} else if (operators[nextOp].type === 'array') {
if (!val || !val.length) {
newVal = [];
} else {
newVal = [val];
}
}
this.props.changeFilter(['val', 'op'], [newVal, nextOp]);
} else {
// No value type change
this.props.changeFilter('op', nextOp);
}
}
changeText(event) {
this.props.changeFilter('val', event.target.value);
}
changeSelect(value) {
this.props.changeFilter('val', value);
}
changeColumn(event) {
this.props.changeFilter('col', event.value);
}
changeOp(event) {
this.switchFilterValue(this.props.filter.op, event.value);
}
removeFilter(filter) {
this.props.removeFilter(filter);
}
renderFilterFormControl(filter) {
const operator = operators[filter.op];
if (operator.useSelect && !this.props.having) {
// TODO should use a simple Select, not a control here...
return (
<SelectControl
multi={operator.multi}
freeForm
name="filter-value"
value={filter.val}
isLoading={this.props.valuesLoading}
choices={this.props.valueChoices}
onChange={this.changeSelect.bind(this)}
showHeader={false}
/>
);
}
return (
<input
type="text"
onChange={this.changeText.bind(this)}
value={filter.val || ''}
className="form-control input-sm"
placeholder={t('Filter value')}
/>
);
}
render() {
const datasource = this.props.datasource;
const filter = this.props.filter;
const opsChoices = operatorsArr
.filter((o) => {
if (this.props.having) {
return !!o.havingOnly;
}
return (!o.datasourceTypes || o.datasourceTypes.indexOf(datasource.type) >= 0);
})
.map(o => ({ value: o.val, label: o.val }));
let colChoices;
if (datasource) {
if (this.props.having) {
colChoices = datasource.metrics_combo.map(c => ({ value: c[0], label: c[1] }));
} else {
colChoices = datasource.filterable_cols.map(c => ({ value: c[0], label: c[1] }));
}
}
return (
<div>
<Row className="space-1">
<Col md={12}>
<Select
id="select-col"
placeholder={this.props.having ? t('Select metric') : t('Select column')}
clearable={false}
options={colChoices}
value={filter.col}
onChange={this.changeColumn.bind(this)}
/>
</Col>
</Row>
<Row className="space-1">
<Col md={3}>
<Select
id="select-op"
placeholder={t('Select operator')}
options={opsChoices}
clearable={false}
value={filter.op}
onChange={this.changeOp.bind(this)}
/>
</Col>
<Col md={7}>
{this.renderFilterFormControl(filter)}
</Col>
<Col md={2}>
<Button
id="remove-button"
bsSize="small"
onClick={this.removeFilter.bind(this)}
>
<i className="fa fa-minus" />
</Button>
</Col>
</Row>
</div>
);
}
}
Filter.propTypes = propTypes;
Filter.defaultProps = defaultProps;

View File

@@ -1,155 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Row, Col } from 'react-bootstrap';
import Filter from './Filter';
import { t } from '../../../locales';
const $ = window.$ = require('jquery');
const propTypes = {
name: PropTypes.string,
onChange: PropTypes.func,
value: PropTypes.array,
datasource: PropTypes.object,
};
const defaultProps = {
onChange: () => {},
value: [],
};
export default class FilterControl extends React.Component {
constructor(props) {
super(props);
const initialFilters = props.value.map(() => ({
valuesLoading: false,
valueChoices: [],
}));
this.state = {
filters: initialFilters,
activeRequest: null,
};
}
componentDidMount() {
this.state.filters.forEach((filter, index) => this.fetchFilterValues(index));
}
fetchFilterValues(index, column) {
const datasource = this.props.datasource;
const col = column || this.props.value[index].col;
const having = this.props.name === 'having_filters';
if (col && this.props.datasource && this.props.datasource.filter_select && !having) {
this.setState((prevState) => {
const newStateFilters = Object.assign([], prevState.filters);
newStateFilters[index].valuesLoading = true;
return { filters: newStateFilters };
});
// if there is an outstanding request to fetch values, cancel it.
if (this.state.activeRequest) {
this.state.activeRequest.abort();
}
this.setState({
activeRequest: $.ajax({
type: 'GET',
url: `/superset/filter/${datasource.type}/${datasource.id}/${col}/`,
success: (data) => {
this.setState((prevState) => {
const newStateFilters = Object.assign([], prevState.filters);
newStateFilters[index] = { valuesLoading: false, valueChoices: data };
return { filters: newStateFilters, activeRequest: null };
});
},
}),
});
}
}
addFilter() {
const newFilters = Object.assign([], this.props.value);
const col = this.props.datasource && this.props.datasource.filterable_cols.length > 0 ?
this.props.datasource.filterable_cols[0][0] :
null;
newFilters.push({
col,
op: 'in',
val: this.props.datasource.filter_select ? [] : '',
});
this.props.onChange(newFilters);
const nextIndex = this.state.filters.length;
this.setState((prevState) => {
const newStateFilters = Object.assign([], prevState.filters);
newStateFilters.push({ valuesLoading: false, valueChoices: [] });
return { filters: newStateFilters };
});
this.fetchFilterValues(nextIndex, col);
}
changeFilter(index, control, value) {
const newFilters = Object.assign([], this.props.value);
const modifiedFilter = Object.assign({}, newFilters[index]);
if (typeof control === 'string') {
modifiedFilter[control] = value;
} else {
control.forEach((c, i) => {
modifiedFilter[c] = value[i];
});
}
// Clear selected values and refresh upon column change
if (control === 'col') {
if (modifiedFilter.val.constructor === Array) {
modifiedFilter.val = [];
} else if (typeof modifiedFilter.val === 'string') {
modifiedFilter.val = '';
}
this.fetchFilterValues(index, value);
}
newFilters.splice(index, 1, modifiedFilter);
this.props.onChange(newFilters);
}
removeFilter(index) {
this.props.onChange(this.props.value.filter((f, i) => i !== index));
this.setState((prevState) => {
const newStateFilters = Object.assign([], prevState.filters);
newStateFilters.splice(index, 1);
return { filters: newStateFilters };
});
}
render() {
const filters = this.props.value.map((filter, i) => (
<div key={i}>
<Filter
having={this.props.name === 'having_filters'}
filter={filter}
datasource={this.props.datasource}
removeFilter={this.removeFilter.bind(this, i)}
changeFilter={this.changeFilter.bind(this, i)}
valuesLoading={this.state.filters[i].valuesLoading}
valueChoices={this.state.filters[i].valueChoices}
/>
</div>
));
return (
<div>
{filters}
<Row className="space-2">
<Col md={2}>
<Button
id="add-button"
bsSize="sm"
onClick={this.addFilter.bind(this)}
>
<i className="fa fa-plus" /> &nbsp; {t('Add Filter')}
</Button>
</Col>
</Row>
</div>
);
}
}
FilterControl.propTypes = propTypes;
FilterControl.defaultProps = defaultProps;

View File

@@ -1,53 +0,0 @@
/* global notify */
import React from 'react';
import PropTypes from 'prop-types';
import Select from '../../../components/AsyncSelect';
import { t } from '../../../locales';
const propTypes = {
dataEndpoint: PropTypes.string.isRequired,
multi: PropTypes.bool,
mutator: PropTypes.func,
onAsyncErrorMessage: PropTypes.string,
onChange: PropTypes.func,
placeholder: PropTypes.string,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.arrayOf(PropTypes.string),
PropTypes.arrayOf(PropTypes.number),
]),
};
const defaultProps = {
multi: true,
onAsyncErrorMessage: t('Error while fetching data'),
onChange: () => {},
placeholder: t('Select ...'),
};
const SelectAsyncControl = ({ value, onChange, dataEndpoint,
multi, mutator, placeholder, onAsyncErrorMessage }) => {
const onSelectionChange = (options) => {
const optionValues = options.map(option => option.value);
onChange(optionValues);
};
return (
<Select
dataEndpoint={dataEndpoint}
onChange={onSelectionChange}
onAsyncError={errorMsg => notify.error(onAsyncErrorMessage + ': ' + errorMsg)}
mutator={mutator}
multi={multi}
value={value}
placeholder={placeholder}
valueRenderer={v => (<div>{v.label}</div>)}
/>
);
};
SelectAsyncControl.propTypes = propTypes;
SelectAsyncControl.defaultProps = defaultProps;
export default SelectAsyncControl;

View File

@@ -1,85 +0,0 @@
/* eslint camelcase: 0 */
import { getControlsState, getFormDataFromControls } from '../stores/store';
import * as actions from '../actions/exploreActions';
export default function exploreReducer(state = {}, action) {
const actionHandlers = {
[actions.TOGGLE_FAVE_STAR]() {
return Object.assign({}, state, { isStarred: action.isStarred });
},
[actions.FETCH_DATASOURCE_STARTED]() {
return Object.assign({}, state, { isDatasourceMetaLoading: true });
},
[actions.FETCH_DATASOURCE_SUCCEEDED]() {
return Object.assign({}, state, { isDatasourceMetaLoading: false });
},
[actions.FETCH_DATASOURCE_FAILED]() {
// todo(alanna) handle failure/error state
return Object.assign({}, state,
{
isDatasourceMetaLoading: false,
controlPanelAlert: action.error,
});
},
[actions.SET_DATASOURCE]() {
return Object.assign({}, state, { datasource: action.datasource });
},
[actions.FETCH_DATASOURCES_STARTED]() {
return Object.assign({}, state, { isDatasourcesLoading: true });
},
[actions.FETCH_DATASOURCES_SUCCEEDED]() {
return Object.assign({}, state, { isDatasourcesLoading: false });
},
[actions.FETCH_DATASOURCES_FAILED]() {
// todo(alanna) handle failure/error state
return Object.assign({}, state,
{
isDatasourcesLoading: false,
controlPanelAlert: action.error,
});
},
[actions.SET_DATASOURCES]() {
return Object.assign({}, state, { datasources: action.datasources });
},
[actions.REMOVE_CONTROL_PANEL_ALERT]() {
return Object.assign({}, state, { controlPanelAlert: null });
},
[actions.SET_FIELD_VALUE]() {
const controls = Object.assign({}, state.controls);
const control = Object.assign({}, controls[action.controlName]);
control.value = action.value;
control.validationErrors = action.validationErrors;
controls[action.controlName] = control;
const changes = { controls };
if (control.renderTrigger) {
changes.triggerRender = true;
}
return Object.assign({}, state, changes);
},
[actions.SET_EXPLORE_CONTROLS]() {
const controls = getControlsState(state, action.formData);
return Object.assign({}, state, { controls });
},
[actions.UPDATE_CHART_TITLE]() {
const updatedSlice = Object.assign({}, state.slice, { slice_name: action.slice_name });
return Object.assign({}, state, { slice: updatedSlice });
},
[actions.RESET_FIELDS]() {
const controls = getControlsState(state, getFormDataFromControls(state.controls));
return Object.assign({}, state, { controls });
},
[actions.CREATE_NEW_SLICE]() {
return Object.assign({}, state, {
slice: action.slice,
controls: getControlsState(state, action.form_data),
can_add: action.can_add,
can_download: action.can_download,
can_overwrite: action.can_overwrite,
});
},
};
if (action.type in actionHandlers) {
return actionHandlers[action.type]();
}
return state;
}

View File

@@ -1,114 +0,0 @@
import $ from 'jquery';
export const LOG_ACTIONS_PAGE_LOAD = 'page_load_perf';
export const LOG_ACTIONS_LOAD_EVENT = 'load_events';
export const LOG_ACTIONS_RENDER_EVENT = 'render_events';
const handlers = {};
export const Logger = {
start(log) {
log.setAttribute('startAt', new Date().getTime() - this.getTimestamp());
log.eventNames.forEach((eventName) => {
if (!handlers[eventName]) {
handlers[eventName] = [];
}
handlers[eventName].push(log.addEvent.bind(log));
});
},
append(eventName, eventBody) {
return handlers[eventName].length &&
handlers[eventName].forEach(handler => (handler(eventName, eventBody)));
},
end(log) {
log.setAttribute('duration', new Date().getTime() - log.startAt);
this.send(log);
log.eventNames.forEach((eventName) => {
if (handlers[eventName].length) {
const index = handlers[eventName]
.findIndex(handler => (handler === log.addEvent));
handlers[eventName].splice(index, 1);
}
});
},
send(log) {
const { impressionId, actionType, source, sourceId, events, startAt, duration } = log;
const requestPrams = [];
requestPrams.push(['impression_id', impressionId]);
switch (source) {
case 'dashboard':
requestPrams.push(['dashboard_id', sourceId]);
break;
case 'slice':
requestPrams.push(['slice_id', sourceId]);
break;
default:
break;
}
let url = '/superset/log/';
if (requestPrams.length) {
url += '?' + requestPrams.map(([k, v]) => (k + '=' + v)).join('&');
}
const eventData = {};
for (const eventName in events) {
eventData[eventName] = [];
events[eventName].forEach((event) => {
eventData[eventName].push(event);
});
}
$.ajax({
url,
method: 'POST',
dataType: 'json',
data: {
source: 'client',
type: actionType,
started_time: startAt,
duration,
events: JSON.stringify(eventData),
},
});
},
getTimestamp() {
return Math.round(window.performance.now());
},
};
export class ActionLog {
constructor({ impressionId, actionType, source, sourceId, eventNames, sendNow }) {
this.impressionId = impressionId;
this.source = source;
this.sourceId = sourceId;
this.actionType = actionType;
this.eventNames = eventNames;
this.sendNow = sendNow || false;
this.startAt = 0;
this.duration = 0;
this.events = {};
this.addEvent = this.addEvent.bind(this);
}
setAttribute(name, value) {
this[name] = value;
}
addEvent(eventName, eventBody) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(eventBody);
if (this.sendNow) {
this.setAttribute('duration', new Date().getTime() - this.startAt);
Logger.send(this);
this.events = {};
}
}
}

View File

@@ -1,179 +0,0 @@
import d3 from 'd3';
export const brandColor = '#00A699';
export const colorPrimary = { r: 0, g: 122, b: 135, a: 1 };
// Color related utility functions go in this object
export const bnbColors = [
'#ff5a5f', // rausch
'#7b0051', // hackb
'#007A87', // kazan
'#00d1c1', // babu
'#8ce071', // lima
'#ffb400', // beach
'#b4a76c', // barol
'#ff8083',
'#cc0086',
'#00a1b3',
'#00ffeb',
'#bbedab',
'#ffd266',
'#cbc29a',
'#ff3339',
'#ff1ab1',
'#005c66',
'#00b3a5',
'#55d12e',
'#b37e00',
'#988b4e',
];
const d3Category10 = d3.scale.category10().range();
const d3Category20 = d3.scale.category20().range();
const d3Category20b = d3.scale.category20b().range();
const d3Category20c = d3.scale.category20c().range();
const googleCategory10c = [
'#3366cc',
'#dc3912',
'#ff9900',
'#109618',
'#990099',
'#0099c6',
'#dd4477',
'#66aa00',
'#b82e2e',
'#316395',
];
const googleCategory20c = [
'#3366cc',
'#dc3912',
'#ff9900',
'#109618',
'#990099',
'#0099c6',
'#dd4477',
'#66aa00',
'#b82e2e',
'#316395',
'#994499',
'#22aa99',
'#aaaa11',
'#6633cc',
'#e67300',
'#8b0707',
'#651067',
'#329262',
'#5574a6',
'#3b3eac',
];
export const ALL_COLOR_SCHEMES = {
bnbColors,
d3Category10,
d3Category20,
d3Category20b,
d3Category20c,
googleCategory10c,
googleCategory20c,
};
export const spectrums = {
blue_white_yellow: [
'#00d1c1',
'white',
'#ffb400',
],
fire: [
'white',
'yellow',
'red',
'black',
],
white_black: [
'white',
'black',
],
black_white: [
'black',
'white',
],
dark_blue: [
'#EBF5F8',
'#6BB1CC',
'#357E9B',
'#1B4150',
'#092935',
],
pink_grey: [
'#E70B81',
'#FAFAFA',
'#666666',
],
};
/**
* Get a color from a scheme specific palette (scheme)
* The function cycles through the palette while memoizing labels
* association to colors. If the function is called twice with the
* same string, it will return the same color.
*
* @param {string} s - The label for which we want to get a color
* @param {string} scheme - The palette name, or "scheme"
* @param {string} forcedColor - A color that the caller wants to
forcibly associate to a label.
*/
export const getColorFromScheme = (function () {
const seen = {};
const forcedColors = {};
return function (s, scheme, forcedColor) {
if (!s) {
return;
}
const selectedScheme = scheme ? ALL_COLOR_SCHEMES[scheme] : ALL_COLOR_SCHEMES.bnbColors;
let stringifyS = String(s).toLowerCase();
// next line is for superset series that should have the same color
stringifyS = stringifyS.replace('---', '');
if (forcedColor && !forcedColors[stringifyS]) {
forcedColors[stringifyS] = forcedColor;
}
if (forcedColors[stringifyS]) {
return forcedColors[stringifyS];
}
if (seen[selectedScheme] === undefined) {
seen[selectedScheme] = {};
}
if (seen[selectedScheme][stringifyS] === undefined) {
seen[selectedScheme][stringifyS] = Object.keys(seen[selectedScheme]).length;
}
/* eslint consistent-return: 0 */
return selectedScheme[seen[selectedScheme][stringifyS] % selectedScheme.length];
};
}());
export const colorScalerFactory = function (colors, data, accessor, extents) {
// Returns a linear scaler our of an array of color
if (!Array.isArray(colors)) {
/* eslint no-param-reassign: 0 */
colors = spectrums[colors];
}
let ext = [0, 1];
if (extents) {
ext = extents;
}
if (data) {
ext = d3.extent(data, accessor);
}
const chunkSize = (ext[1] - ext[0]) / (colors.length - 1);
const points = colors.map((col, i) => ext[0] + (i * chunkSize));
return d3.scale.linear().domain(points).range(colors).clamp(true);
};
export function hexToRGB(hex, alpha = 255) {
if (!hex) {
return [0, 0, 0, alpha];
}
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return [r, g, b, alpha];
}

View File

@@ -1,11 +0,0 @@
export function getTextWidth(text, fontDetails = '12px Roboto') {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = fontDetails;
const metrics = context.measureText(text);
return metrics.width;
}
export default {
getTextWidth,
};

View File

@@ -1,40 +0,0 @@
import React from 'react';
import { Panel, Row, Col, FormControl } from 'react-bootstrap';
import DashboardTable from './DashboardTable';
export default class App extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
search: '',
};
this.onSearchChange = this.onSearchChange.bind(this);
}
onSearchChange(event) {
this.setState({ search: event.target.value });
}
render() {
return (
<div className="container welcome">
<Panel>
<Row>
<Col md={8}><h2>Dashboards</h2></Col>
<Col md={4}>
<FormControl
type="text"
bsSize="sm"
style={{ marginTop: '25px' }}
placeholder="Search"
value={this.state.search}
onChange={this.onSearchChange}
/>
</Col>
</Row>
<hr />
<DashboardTable search={this.state.search} />
</Panel>
</div>
);
}
}

View File

@@ -9,4 +9,3 @@ npm run lint
npm run test
npm run build
npm run cover
CODECLIMATE_REPO_TOKEN=ded6121d25d593a1c5aee9f26d85717b19df058f7408cef26910aa731aa7cc3f ./node_modules/.bin/codeclimate-test-reporter < ./coverage/lcov.info

View File

@@ -1,6 +1,6 @@
{
"name": "superset",
"version": "0.23.1",
"version": "0.28.0rc3",
"description": "Superset is a data exploration platform designed to be visual, intuitive, and interactive.",
"license": "Apache-2.0",
"directories": {
@@ -8,15 +8,15 @@
"test": "spec"
},
"scripts": {
"test": "mocha --require ignore-styles --compilers js:babel-core/register --require spec/helpers/browser.js --recursive spec/**/*_spec.*",
"cover": "babel-node node_modules/.bin/babel-istanbul cover _mocha -- --require ignore-styles spec/helpers/browser.js --recursive spec/**/*_spec.*",
"dev": "NODE_ENV=dev webpack --watch --colors --progress --debug --output-pathinfo --devtool inline-source-map",
"dev-fast": "NODE_ENV=dev webpack --watch --colors --progress --debug --output-pathinfo --devtool eval-cheap-source-map",
"prod": "NODE_ENV=production node --max_old_space_size=4096 ./node_modules/webpack/bin/webpack.js -p --colors --progress",
"build": "NODE_ENV=production webpack --colors --progress",
"test": "mocha --require ignore-styles --compilers js:babel-core/register --require spec/helpers/browser.js 'spec/**/*_spec.*'",
"test:one": "mocha --require ignore-styles --compilers js:babel-core/register --require spec/helpers/browser.js",
"cover": "babel-node node_modules/.bin/babel-istanbul cover _mocha -- --compilers babel-core/register --require spec/helpers/browser.js --require ignore-styles 'spec/**/*_spec.*'",
"dev": "webpack --mode=development --colors --progress --debug --watch",
"prod": "node --max_old_space_size=4096 webpack --mode=production --colors --progress",
"build": "webpack --mode=production --colors --progress",
"lint": "eslint --ignore-path=.eslintignore --ext .js,.jsx .",
"lint-fix": "eslint --fix --ignore-path=.eslintignore --ext .js,.jsx .",
"sync-backend": "babel-node --presets env javascripts/syncBackend.js"
"sync-backend": "babel-node --presets env src/syncBackend.js"
},
"repository": {
"type": "git",
@@ -38,27 +38,31 @@
"bugs": {
"url": "https://github.com/apache/incubator-superset/issues"
},
"engines": {
"node": ">= 6.11.5 <7.0.0 || >= 8.9.0"
},
"homepage": "http://superset.apache.org/",
"dependencies": {
"@data-ui/event-flow": "^0.0.8",
"@data-ui/sparkline": "^0.0.49",
"@data-ui/event-flow": "^0.0.54",
"@data-ui/sparkline": "^0.0.54",
"@data-ui/xy-chart": "^0.0.61",
"@vx/responsive": "0.0.172",
"babel-register": "^6.24.1",
"bootstrap": "^3.3.6",
"bootstrap-slider": "^10.0.0",
"brace": "^0.10.0",
"brfs": "^1.4.3",
"cal-heatmap": "3.6.2",
"brace": "^0.11.1",
"classnames": "^2.2.5",
"d3": "^3.5.17",
"d3-cloud": "^1.2.1",
"d3-hierarchy": "^1.1.5",
"d3-sankey": "^0.4.2",
"d3-svg-legend": "^1.x",
"d3-tip": "^0.6.7",
"d3-tip": "^0.9.1",
"datamaps": "^0.5.8",
"datatables.net-bs": "^1.10.15",
"deck.gl": "^5.0.1",
"deck.gl": "^5.1.4",
"distributions": "^1.0.0",
"dnd-core": "^2.6.0",
"dompurify": "^1.0.3",
"fastdom": "^1.0.6",
"geojson-extent": "^0.3.2",
@@ -67,42 +71,49 @@
"jed": "^1.1.1",
"jquery": "3.1.1",
"lodash.throttle": "^4.1.1",
"luma.gl": "^5.0.1",
"mapbox-gl": "^0.43.0",
"luma.gl": "^5.1.4",
"mapbox-gl": "^0.45.0",
"mathjs": "^3.20.2",
"moment": "^2.20.1",
"mousetrap": "^1.6.1",
"mustache": "^2.2.1",
"nvd3": "1.8.6",
"po2json": "^0.4.5",
"parse-iso-duration": "^1.0.0",
"prop-types": "^15.6.0",
"re-resizable": "^4.3.1",
"react": "^15.6.2",
"react-ace": "^5.0.1",
"react-ace": "^5.10.0",
"react-addons-css-transition-group": "^15.6.0",
"react-addons-shallow-compare": "^15.4.2",
"react-alert": "^2.3.0",
"react-bootstrap": "^0.31.5",
"react-bootstrap-slider": "2.0.1",
"react-bootstrap-table": "^4.0.2",
"react-bootstrap-datetimepicker": "0.0.22",
"react-bootstrap-dialog": "^0.10.0",
"react-bootstrap-slider": "2.1.5",
"react-bootstrap-table": "^4.3.1",
"react-color": "^2.13.8",
"react-datetime": "2.9.0",
"react-datetime": "2.14.0",
"react-dnd": "^2.5.4",
"react-dnd-html5-backend": "^2.5.4",
"react-dom": "^15.6.2",
"react-gravatar": "^2.6.1",
"react-grid-layout": "^0.16.0",
"react-map-gl": "^3.0.4",
"react-markdown": "^3.3.0",
"react-redux": "^5.0.2",
"react-resizable": "^1.3.3",
"react-select": "1.0.0-rc.10",
"react-search-input": "^0.11.3",
"react-select": "1.2.1",
"react-select-fast-filter-options": "^0.2.1",
"react-sortable-hoc": "^0.6.7",
"react-sortable-hoc": "^0.8.3",
"react-split-pane": "^0.1.66",
"react-syntax-highlighter": "^5.7.0",
"react-virtualized": "9.3.0",
"react-virtualized-select": "2.4.0",
"reactable": "^0.14.1",
"react-sticky": "^6.0.2",
"react-syntax-highlighter": "^7.0.4",
"react-virtualized": "9.19.1",
"react-virtualized-select": "^2.4.0",
"reactable": "1.0.2",
"redux": "^3.5.2",
"redux-localstorage": "^0.4.1",
"redux-thunk": "^2.1.0",
"redux-undo": "^1.0.0-beta9-9-7",
"shortid": "^2.2.6",
"sprintf-js": "^1.1.1",
"srcdoc-polyfill": "^1.0.0",
@@ -114,24 +125,27 @@
"devDependencies": {
"babel-cli": "^6.14.0",
"babel-core": "^6.10.4",
"babel-eslint": "^8.2.2",
"babel-istanbul": "^0.12.2",
"babel-loader": "^7.0.0",
"babel-loader": "^7.1.4",
"babel-plugin-css-modules-transform": "^1.1.0",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-polyfill": "^6.23.0",
"babel-preset-airbnb": "^2.1.1",
"chai": "^4.0.2",
"clean-webpack-plugin": "^0.1.16",
"codeclimate-test-reporter": "^0.5.0",
"clean-webpack-plugin": "^0.1.19",
"css-loader": "^0.28.0",
"enzyme": "^2.0.0",
"eslint": "^3.19.0",
"eslint": "^4.19.0",
"eslint-config-airbnb": "^15.0.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-prettier": "^2.6.0",
"eslint-plugin-react": "^7.0.1",
"exports-loader": "^0.6.3",
"extract-text-webpack-plugin": "3.0.0",
"file-loader": "^0.11.1",
"exports-loader": "^0.7.0",
"file-loader": "^1.1.11",
"github-changes": "^1.0.4",
"ignore-styles": "^5.0.1",
"imports-loader": "^0.7.1",
@@ -139,19 +153,23 @@
"jsdom": "9.12.0",
"json-loader": "^0.5.4",
"less": "^2.6.1",
"less-loader": "^4.0.3",
"less-loader": "^4.1.0",
"mini-css-extract-plugin": "^0.4.0",
"mocha": "^3.2.0",
"npm-check-updates": "^2.14.0",
"po2json": "^0.4.5",
"prettier": "^1.12.1",
"react-addons-test-utils": "^15.6.2",
"react-test-renderer": "^15.6.2",
"redux-mock-store": "^1.2.3",
"sinon": "^4.0.0",
"style-loader": "^0.18.2",
"sinon": "^4.5.0",
"style-loader": "^0.21.0",
"transform-loader": "^0.2.3",
"uglifyjs-webpack-plugin": "^1.1.0",
"url-loader": "^0.6.2",
"webpack": "^3.8.1",
"webpack-manifest-plugin": "1.3.2",
"webworkify-webpack": "2.1.0"
"url-loader": "^1.0.1",
"webpack": "^4.6.0",
"webpack-assets-manifest": "^3.0.1",
"webpack-cli": "^2.0.10",
"webpack-sources": "^1.1.0"
}
}

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