Compare commits

...

525 Commits

Author SHA1 Message Date
Gabriel Dutra
19343a0520 Clear QueryBasedParameterInput 2020-11-23 19:18:35 -03:00
Gabriel Dutra
c1ed8848f0 Merge branch 'master' into query-based-dropdown--parameters 2020-11-23 16:42:06 -03:00
Gabriel Dutra
b40070d7f5 Use LabeledValues for parameterized queries 2020-11-23 16:40:18 -03:00
Rafael Wendel
fa2b57a209 Remove unwanted props from Select component (#5277)
* Explicitly selected props so as to avoid errors from non-wanted props

* Simplified approach

* Ran prettier 😬

* Fixed minor issues
2020-11-22 13:07:56 -03:00
Jiajie Zhong
132fed64b3 Correct cleanup_query_results comment (#5276)
Correct comment from QUERY_RESULTS_MAX_AGE
to QUERY_RESULTS_CLEANUP_MAX_AGE
2020-11-20 23:11:13 +02:00
Gabriel Dutra
bd9ce68f68 Don't filter out values when param has search 2020-11-20 15:14:17 -03:00
Gabriel Dutra
0c0b62ae1a Remove searchTerm from structure 2020-11-20 15:13:47 -03:00
Gabriel Dutra
08bcdf77d0 Mock query instead of query_has_parameters 2020-11-12 09:11:54 -03:00
Gabriel Dutra
aa2064b1ab Fix other dropdown_values usages to use query obj 2020-11-11 13:58:01 -03:00
Gabriel Dutra
d0a787cab1 Make NoResultFound invalid parameters 2020-11-10 22:10:47 -03:00
Gabriel Dutra
a741341938 Oops 2020-11-10 20:46:51 -03:00
Gabriel Dutra
53385fa24b Merge branch 'master' into query-based-dropdown--parameters 2020-11-10 15:19:43 -03:00
Gabriel Dutra
fa7ecca485 Frontend updates from internal fork (#5259)
* DynamicComponent for QuerySourceAlerts

* General Settings updates

* Dynamic Date[Range] updates

* EmptyState updates

* Query and SchemaBrowser updates

* Adjust page headers and add disablePublish

* Policy updates

* Separate Home FavoritesList component

* Update FormatQuery

* Autolimit frontend fixes

* Misc updates

* Keep registering of QuerySourceDropdown

* Undo changes in DynamicComponent

* Change sql-formatter package.json syntax

* Allow opening help trigger in new tab

* Don't run npm commands as root in Dockerfile

* Cypress: Remove extra execute query
2020-11-10 14:59:15 +02:00
deecay
8f484706b1 Enable Boxplot to be horizontal (#5262) 2020-11-08 23:17:08 +02:00
Josh Bohde
e2e8714155 Enable graceful shutdown of rq workers (#5214)
* Enable graceful shutdown of rq workers

* Use `exec` in the `worker` command of the entrypoint to propagate
  the `TERM` signal
* Allow rq processes managed by supervisor to exit without restart on
  expected status codes
* Allow supervisorctl to contact the running supervisor
* Add a `shutdown_worker` command that will send `TERM` to all running
  worker processes and then sleep. This allows orchestration systems
  to initiate a graceful shutdown before sending `SIGTERM` to
  supervisord

* Use Heroku worker as the BaseWorker

This implements a graceful shutdown on SIGTERM, which simplifies
external shutdown procedures.

* Fix imports based upon review

* Remove supervisorctl config
2020-11-05 11:49:45 +02:00
Jerry
c6bf8a1c55 bugfix: fix #5254 (#5255)
Co-authored-by: Jerry <jerry.yuan@webweye.com>
2020-11-04 20:56:41 +02:00
Rafael Wendel
12f71925c2 Multiselect dropdown slowness (fix) (#5221)
* created util to estimate reasonable width for dropdown

* removed unused import

* improved calculation of item percentile

* added getItemOfPercentileLength to relevant spots

* added getItemOfPercentileLength to relevant spots

* Added missing import

* created custom select element

* added check for property path

* removed uses of percentile util

* gave up on getting element reference

* finished testing Select component

* removed unused imports

* removed older uses of Option component

* added canvas calculation

* removed minWidth from Select

* improved calculation

* added fallbacks

* added estimated offset

* removed leftovers 😅

* replaced to percentiles to max value

* switched to memo and renamed component

* proper useMemo syntax

* Update client/app/components/Select.tsx

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

* created custom restrictive types

* added quick const

* fixed style

* fixed generics

* added pos absolute to fix percy

* removed custom select from ParameterMappingInput

* applied prettier

* Revert "added pos absolute to fix percy"

This reverts commit 4daf1d4bef.

* Pin Percy version to 0.24.3

* Update client/app/components/ParameterMappingInput.jsx

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

* renamed Select.jsx to SelectWithVirtualScroll

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-11-03 21:50:39 +02:00
Omer Lachish
cae088f35b extend the refresh_queries timeout from 3 minutes to 10 minutes (#5253) 2020-11-02 22:36:57 +02:00
Rafael Wendel
a3c79f26b9 Fix for the typo button in ParameterMappingInput (#5244) 2020-10-29 17:24:13 -03:00
Jonathan Hult
c7c92a3192 Fix annotation bug causing queries not to run - ORA-00933 (#5179) 2020-10-28 10:03:26 +02:00
Rafael Wendel
55cf17aa47 added required to Form.Item and Input for better UI (#5231)
* added required to Form.Item and Input for better UI

* removed required from input

* Revert "removed required from input"

This reverts commit b56cd76fa1.

* Redo "removed required from input"

* removed typo

Co-authored-by: rafawendel2010@gmail.com <rafawendel>
2020-10-28 09:37:16 +02:00
Levko Kravets
8dd76a00c5 Fix dashboard background grid (#5238) 2020-10-26 21:46:38 +02:00
Christopher Grant
e242ac2b10 Static SAML configuration and assertion encryption (#5175)
* Change front-end and data model for SAML2 auth - static configuration

* Add changes to use inline metadata.

* add switch for static and dynamic SAML configurations

* Fixed config of backend static/dynamic to match UI

* add ability to encrypt/decrypt SAML assertions with pem and crt files. Upgraded to pysaml2 6.1.0 to mitigate signature mismatch during decryption

* remove print debug statement

* Use utility to find xmlsec binary for encryption, formatting saml_auth module

* format SAML Javascript, revert want_signed_response to pre-PR value

* pysaml2's entityid should point to the sp, not the idp

* add logging for entityid for validation

* use mustache_render instead of string formatting. put all static logic into static branch

* move mustache template for inline saml metadata to the global level

* Incorporate SAML type with Enabled setting

* Update client/app/pages/settings/components/AuthSettings/SAMLSettings.jsx

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

Co-authored-by: Chad Chen <chad.chen@databricks.com>
Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-10-25 12:06:45 -03:00
Gabriel Dutra
66463aedd4 Fix Home EmptyState help link (#5217) 2020-10-16 11:53:21 -03:00
Rafael Wendel
8a6524c1ba Add horizontal bar chart (#5154)
* added bar chart boilerplate

* added x/y manipulation

* replaced x/y management to inner series preparer

* added tests

* moved axis inversion to all charts series

* removed line and area

* inverted labels ui

* removed normalizer check, simplified inverted axes check

* finished working hbar

* minor review

* added conditional title to YAxis

* generalized horizontal chart for line charts, resetted state on globalSeriesType change

* fixed updates

* fixed updates to layout

* fixed minor issues

* removed right Y axis when axes inverted

* ran prettier

* fixed updater function conflict and misuse of getOptions

* renamed inverted to swapped

* created mappingtypes for swapped columns

* removed unused import

* minor polishing

* improved series behaviour in h-bar

* minor fix

* added basic filter to ChartTypeSelect

* final setup of filtered chart types

* Update viz-lib/src/components/visualizations/editor/createTabbedEditor.jsx

* added proptypes and renamed ChartTypeSelect props

* Add missing import

* fixed import, moved result array to global scope

* merged import

* clearer naming in ChartTypeSelect

* better lodash map syntax

* fixed global modification

* moved result inside useMemo

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
Co-authored-by: Levko Kravets <levko.ne@gmail.com>
2020-10-15 21:34:38 +03:00
Gabriel Dutra
9097feb100 Frontend updates from internal fork (#5209) 2020-10-15 14:25:22 -03:00
Gabriel Dutra
db4e97fa6f Remove build args from Cypress start script (#5203) 2020-10-09 12:23:14 -03:00
Levko Kravets
0d4615a482 Extra actions on Queries and Dashboards pages (#5201)
* Extra actions for Query View and Query Source pages

* Convert Queries List page to functional component

* Convert Dashboards List page to functional component

* Extra actions for Query List page

* Extra actions for Dashboard List page

* Extra actions for Dashboard page

* Pass some extra data to Dashboard.HeaderExtra component

* CR1
2020-10-09 12:12:56 +03:00
Alexander Rusanov
ff008a076b Updated Cypress to v5.3 and fixed e2e tests (#5199)
* Upgraded Cypress to v5.3 and fixed e2e tests

* Updated cypress image

* Fixed failing tests

* Updated NODE_VERSION in netlify

* Update client/cypress/integration/visualizations/choropleth_spec.js

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

* fixed test in choropleth

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-10-06 16:06:47 -03:00
Gabriel Dutra
8d548ecbac Share Embed Spec: Make sure query is executed (#5191) 2020-10-04 16:01:30 +03:00
Gabriel Dutra
2992c382d1 ScheduleDialog: Filter empty interval groups (#5196) 2020-10-03 05:54:05 +03:00
Gabriel Dutra
f4dcb2918a Move Cypress to dev dependencies (#3991)
* Test Cypress on package list

* Skip Puppeteer Chromium as well

* Put back missing npm install on netlify.toml

* Netlify: move env vars to build.environment

* Remove cypress:install script

* Update Cypress dockerfile

* Copy package-lock.json to Cypress dockerfile
2020-09-29 09:51:28 +03:00
Gabriel Dutra
c821cab4cb Generate Code Coverage report for Cypress (#5137) 2020-09-28 21:43:04 -03:00
Levko Kravets
4fb77867b0 Align Y axes at zero (#5053)
* Align Y axes as zero

* Fix typo (with @deecay)

* Add alignYAxesAtZero function

* Avoid 0 division

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-09-28 13:12:40 +03:00
Levko Kravets
a473611cb0 Some Choropleth improvements/refactoring (#5186)
* Directly map query results column to GeoJSON property

* Use cache for geoJson requests

* Don't handle bounds changes while loading geoJson data

* Choropleth: fix map "jumping" on load; don't save bounds if user didn't edit them; refine code a bit

* Improve cache

* Optimize Japan Perfectures map (remove irrelevant GeoJson properties)

* Improve getOptions for Choropleth; remove unused code

* Fix test

* Add US states map

* Convert USA map to Albers projection

* Allow to specify user-friendly field names for maps
2020-09-24 14:39:09 +03:00
Levko Kravets
210008c714 Ask user to log in when session expires (#5178)
* Ask user to log in when session expires

* Update implementation

* Update implementation

* Minor fix

* Update modal

* Do not intercept calls to api/session as Auth.requireSession() relies on it

* Refine code; adjust popup size and position
2020-09-23 16:30:08 +03:00
Omer Lachish
aa5d4f5f4e add 'cancelled' meta directive to all cancelled jobs (#5187) 2020-09-23 12:54:48 +03:00
Omer Lachish
6b811c5245 Refresh CSRF tokens (#5177)
* expire CSRF tokens after 6 hours

* use axios' built-in cookie to header copy mechanism

* add axios-auth-refresh

* retry CSRF-related 400 errors by refreshing the cookie

* export the auth refresh interceptor to support ejecting it if neccessary

* reject the original request if it's unrelated to CSRF
2020-09-21 23:21:14 +03:00
Levko Kravets
83726da48a Keep additional URL params when forking a query (#5184) 2020-09-21 12:54:55 +03:00
Levko Kravets
72dc157bbe Allow to clear selected tags on list pages (#5142)
* Convert TagsList to functional component

* Convert TagsList to typescript

* Allow to unselect all tags

* Add title to Tags block and explicit "clear filter" button

* Some tweaks
2020-09-17 14:01:15 +03:00
Lingkai Kong
1b8ff8e810 Add default limit (1000) to SQL queries (#5088)
* add default limit 1000

* Add frontend changes and connect to backend

* Fix query hash because of default limit

* fix CircleCI test

* adjust for comment
2020-09-14 14:18:31 +03:00
Omer Lachish
31ddd0fb79 prevent assigning queries to view_only data sources (#5152) 2020-09-10 15:43:25 +03:00
Levko Kravets
5cabf7a724 Keep selected filters when switching visualizations (#5146)
* getredash/redash#4944 Query pages: keep selected filters when switching visualizations

* Pass current filters to expanded widget modal
2020-09-10 13:42:53 +03:00
max-voronov
59b135ace7 Move CardsList to typescript (#5136)
* Refactor CardsList - pass a suffix for list item

Adding :id to an item to be used as a key suffix is redundant and the same
can be accomplished by using :index from the map function.

* Move CardsList to typescript

* Convert CardsList component to functional component

* CR1

* CR2
2020-09-05 20:08:01 +03:00
Gabriel Dutra
32b41e4112 Misc frontend changes from internal fork (#5143) 2020-09-04 08:00:30 -03:00
Gabriel Dutra
2e31b91054 Antd v4: Fix CreateUserDialog (#5139)
* Antd v4: Update CreateUserDialog

* Add Cypress test for user creation
2020-09-04 07:57:43 -03:00
Gabriel Dutra
205915e6db Add toggle to disable public URLs (#5140)
* Add toggle to disable public URLs

* Add Cypress tests
2020-09-01 08:49:30 -03:00
Levko Kravets
b7c245f925 Support multiple queries in a single query box (#5058)
* Support multiple queries in a single query box

* Implement statement splitting function and add tests for it

* Add a test for databricks-specific syntax

* Split statements before running query
2020-08-30 15:54:16 +03:00
Levko Kravets
681b2f1abd Introduce Link component (#5122)
* Introduce Link component

* Use Link component for external links as well

* Remove unused file (I hope it's really not needed)

* Use Link component in visualizations library

* Simplify Link component implementation

* CR1

* Trigger build

* CR2
2020-08-30 15:33:38 +03:00
Gabriel Dutra
a31196aef8 Upgrade Ant Design to v4 (#5068) 2020-08-25 14:24:15 -03:00
Arik Fraimovich
596e5bee3a Misc changes to codebase back ported from internal fork - part 2 (#5130)
* Auth: make login url configurable.

* More portable image url.

* durationHumanize: support for milliseconds.

* Sorter: support for custom sort.
2020-08-25 15:08:07 +03:00
Arik Fraimovich
84d516bfd1 Misc changes to codebase back ported from internal fork (#5129)
* Set corejs version in .babelrc so Jest doesn't complain.

* Rewrite services/routes in TypeScript.

* Add TypeScript definitions for DialogComponent.

* Make image paths more portable

* Add current route context and hook.

* Make EmptyState more flexible by being able to pass in getSteps function.

* Rewrite ItemsList in TypeScript.

* Introduce the possibility to add custom sorters for a column.

* Rearrange props to be friendly to TypeScript.

* Type definitions for NotificationApi.

* Use Databricks query editor components for databricks_internal type of query runner.

* URL Escape password in Alembic configuration.

* Compare types in migrations.
2020-08-25 14:11:38 +03:00
Gabriel Dutra
2cc3bd3d54 Add DynamicComponent to PermissionsControl flag (#5116) 2020-08-21 17:14:19 -03:00
Gabriel Dutra
ac652c20bf Fix create link on data sources page (#5121)
* Fix create link on data sources page

* Cypress: Add test that the source dialog opens
2020-08-21 16:47:42 -03:00
Gabriel Dutra
1bc6cd8f41 Keep widget loading when fetch request is replaced (#5118) 2020-08-20 19:00:57 -03:00
Levko Kravets
4c70b5ce8e Remove content width limit on all pages (#5091)
* Remove content width limit on all pages

* Update client/app/assets/less/inc/base.less

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

* Remove content limit; limit sidebar width

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-08-20 15:04:53 +03:00
Omer Lachish
de052ff02b Cypress touch-ups (#5109)
* allow non-sequential IDs for DataSources in Cypress tests

* refactor redash-api to a set of Cypress commands

* support mounting Redash endpoints in Cypress routes

* fix some parameter specs by waiting for schema to load

* extract baseUrl from cypress.json

* Restyled by prettier (#5110)

Co-authored-by: Restyled.io <commits@restyled.io>

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <commits@restyled.io>
2020-08-19 21:00:06 +03:00
Gabriel Dutra
a596d6558c Use Skeleton as ItemsList loading state (#5079) 2020-08-19 09:36:11 -03:00
Gabriel Dutra
fc71acdc09 Make DataSourceListComponent a dynamic component (#5113) 2020-08-19 08:59:53 -03:00
Gabriel Dutra
b326d36ae8 Update Organization Settings (#5114)
* Update Organization Settings

* Cypress: Update tab naming
2020-08-19 13:09:28 +03:00
Omer Lachish
378cc57d42 CSRF Exempts (#5108)
* if present, always convert CSRF cookies to headers

* exempt auth blueprints from CSRF protection

* respect CSRF exempts
2020-08-17 22:39:46 +03:00
peterlee
83c6a6bcd2 Make table visualization header fixed (#5103)
* add lock table header

* Move styling to a new class

* Update renderer.less

* Move class to table and fix top border

* Update renderer.less

* Update viz-lib/src/visualizations/table/renderer.less

Thanks, this change is good to me.

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-08-17 09:26:34 -03:00
Omer Lachish
5afd0554d0 Add support for CSRF tokens (#5055)
* add flask-wtf

* add CSRF tokens to all static forms

* add CSRF tokens to all axios requests

* disable CSRF validation in unit tests

* support CSRF-protected requests in *most* cypress tests

* don't enfroce CSRF checks by default

* avoid CSRF enforcement in unit tests

* remove redundant spread

* some camel casing hiccups

* always yield the CSRF cookie, but avoid enforcing it if CSRF toggle is off

* Restyled by prettier (#5056)

Co-authored-by: Restyled.io <commits@restyled.io>

* set a CSRF header only if cookie is present

* enforce CSRF in CI

* install lodash directly for Cypress

* install request-cookies directly for Cypress. We should probably start loading package.json deps

* enable CSRF support when logout and login happen within the same spec

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <commits@restyled.io>
2020-08-09 15:47:00 +03:00
Levko Kravets
eb603f63f0 Bar chart with second y axis overlaps data series (#4150) 2020-08-05 20:28:03 +03:00
Arik Fraimovich
6c00f7c4e3 Add: periodic job to remove ghost locks. (#5087) 2020-08-05 17:48:19 +03:00
koooge
f56f4c4899 fix: Compose version due to --build-arg (#5083)
Signed-off-by: koooge <koooooge@gmail.com>
2020-08-05 12:41:25 +03:00
Tobias Macey
d3b639a68a Exposing setting for overriding template directory (#4324)
When using some of the customized login flows such as `REMOTE_USER` the deployed site breaks due to not finding template files. This change updated the app default to use the existing Flask templates directory rather than the compiled static assets directory which only contains an index.html file.
2020-08-04 12:05:43 +03:00
Gabriel Dutra
3332b656ac Make sure Policy is loaded for user session (#5081) 2020-07-31 01:39:30 -03:00
Gabriel Dutra
24c95379ca Introduce caching to the Databricks Schema Browser (#5038)
* Add refresh button in the bottom

* Add caching

* Drop allSettled

* Simplify refresh button

* Update error to return 500

* Load tables before loading columns

* Don't mutate schema

* Reset db name and schemas when changing data source

* Load both tables and columns

* Return error with code 200

* Code review updates

* Add expiration time to the cache Keys

* Back with RQ
2020-07-30 15:16:14 +03:00
Levko Kravets
93b4be672f Queries list: move "My Queries" above "Archived" (#5072) 2020-07-28 19:53:22 +03:00
Gabriel Dutra
f3a47a9658 Move page size select to the Paginator component (#5064) 2020-07-27 16:52:09 -03:00
Omer Lachish
7804dfd68e loosen up some proptypes and backend casting to allow different primary key types (#5066) 2020-07-27 17:01:59 +03:00
Ben Amor
2dacd08bea Add override mechanism for webpack config (#5057) 2020-07-27 14:52:02 +03:00
Gabriel Dutra
fd76a2ecfb Add Column Type to Databricks schema browser (#5052)
* Add Column Type to Databricks schema browser

* Map schema columns to be an object

* Format pg with Black

* Add data_type for Postgres
2020-07-23 12:52:09 +03:00
Omer Lachish
7f98d7b694 Load extensions on db init (#5062)
* Only try to create tables and stamp DB if not tables exist already.

* load extensions when creating the database
2020-07-23 11:05:20 +03:00
Levko Kravets
a1255b4144 Fix wrong Y-axis range for stacked bar chart (#5029)
* getredash/redash#5026 Fix wrong Y-axis range for stacked bar chart

* Update tests

* Use Plotly's built-in algorinthm to compute Y-axis range

* Update tests

* Revert previous solution (yRange-related code)

* Revert other unrelated changes

* Revert other unrelated changes

* Move chart rendering to own file and ensure that rendering steps will occur in necessary order

* Reduce amount of plot updates by mergin separate updates into a sigle cumulative update

* Give better names for several functions
2020-07-17 11:28:15 +03:00
dependabot[bot]
6c349ea70a Bump lodash from 4.17.15 to 4.17.19 in /viz-lib (#5051)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-16 22:41:16 -03:00
Omer Lachish
95c28c47ad Eager load outdated queries (#5049)
* eager load outdated queries

* explicitly use .all() instead of list()
2020-07-16 23:29:47 +03:00
simonschneider-db
48924de700 Add TypeScript support (#5027)
* TASK Add typescript dependencies to package.json

* TASK Add typescript to build process and npm scripts and TASK Move example components to typescript and add an example definition file.

* TASK Move back to ts-loader instead of babel typescript preset

* FIX Remove unnecessary changes

* FIX Explicitly mention tsconfig file in webpack.config.js to avoid `error while parsing tsconfig.json, The 'files' list in config file 'tsconfig.json' is empty`
See (https://github.com/TypeStrong/ts-loader/issues/405#issuecomment-330108362)

* FIX Move tsconfig to client subdirectory to make it accessible in docker container (only webpack.config.js is copied over from root folder in Dockerfile)

* TASK Move from ts-loader to babel to reduce compatibility issues between ES6/7 and typescript compilation.

* TASK Add types for classnames, hoist-non-react-statics and lodash. Fix default export of DashboardList and run prettier on eslintrc

* Run npm install

* Trigger tests

* Run npm install 2

* Trigger tests
2020-07-16 23:05:44 +03:00
Jannis Leidel
41a691328a Fix bundle-extensions script to work on recent importlib-resources. (#5050)
Also adds a test case for running the script.
2020-07-16 23:05:22 +03:00
Omer Lachish
cb97364771 Dashboard URL does not show new name when dashboard name is updated (#1009)
* on dashboard api calls - take the id from the beginning of the slug, unless there is no number in it - in that case, take the entire slug as id

* add dashboard id when showing links to dashboards

* change path to include new name when renaming dashboards

* move slug generation to backend

* redirect to new name after changing (this time with a proper promise)

* oh right, we already have a slug function

* add spec that makes sure that renamed dashboards are redirected to the
url which contains their new name

* use id-slug in all Cypress specs

* move dashboards from /dashboard/:slug to /dashboards/:id-:name_as_slug

* Update dashboard url as its name changes

* Update separator to be "/"

* Update missing dashboard urls

* Update api not to depend on int id

* Use '-' instead of '/' as separator and update Dashboard.get calls

* slug -> name_as_slug

* Keep slug urls on cypress

* Update route path

* Use legacy attr for GET

* Use getter for urlForDashboard

* Update dashboard url when loaded by slug

* Update Dashboard routes to use id instead of slug

* Update Dashboard handler tests

* Update Cypress tests

* Fix create new dashboard spec

* Use axios { params }

* Drop Ternary operator

* Send updated slug directly in 'slug' attr

* Update multiple urls Dashboard test name

* Update route names

Co-authored-by: Levko Kravets <levko.ne@gmail.com>

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
Co-authored-by: Levko Kravets <levko.ne@gmail.com>
2020-07-16 23:03:59 +03:00
Gabriel Dutra
d12691dc2a Databricks Schema Browser: Allow eventlet worker instead of RQ (#5045)
* Add loading button in UI

* Handle databricks schema requests without RQ

* Don't use gevent worker

* Revert "Don't use gevent worker"

This reverts commit 9704c70a94.

* Use eventlet

* Use first column instead of 'namespace' one

* Revert "Add loading button in UI"

This reverts commit c0e4dfb966.

* Remove databricks tasks

* Update eventlet

* Add libevent

* Display logs on failure

* Revert "Add libevent"

This reverts commit a00d067cb7.

* Test updating gunicorn

* Don't set eventlet as the default for Redash

Co-authored-by: Arik Fraimovich <arik@arikfr.com>

* Remove fetchDataFromJob usage

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-07-15 17:35:59 +03:00
Levko Kravets
6f9e79c641 getredash/redash#5031 Counter is too large on Query View/Source pages (#5044) 2020-07-14 21:56:01 +03:00
Gabriel Dutra
461f98bbfc Update Ace Editor version (#5041) 2020-07-14 10:02:33 -03:00
Levko Kravets
81e7c72d48 Allow to change order of legend items (#5021)
* Allow to change order of legend items

* Update tests
2020-07-13 19:08:51 +03:00
Gabriel Dutra
328f0f3f0c Visualizations Library: Enhance docs (#4946) 2020-07-12 12:36:03 -03:00
Omer Lachish
ecb9adf903 purge_failed_jobs can take up to several minutes, so better have a proper timeout (#5033) 2020-07-12 10:18:38 +03:00
Gabriel Dutra
87e09f676e Dynamic Form: Make default extra fields state a prop (#5039) 2020-07-09 12:39:25 -03:00
Gabriel Dutra
6fc5c803e0 Fix schema browser items height (#5024) 2020-07-08 11:55:10 -03:00
Gabriel Dutra
6c57aa448e Query Source: Add Shift+Enter shortcut for query execution (#5037) 2020-07-08 10:36:16 -03:00
Lei Ni
878b297601 Fix: sorting queries by schedule was resulting in a wrong order (#4954)
* fix schedule sorting issue

* style change

* Update to meet code style.

* move the schedule sort to backend

* mod comment

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-07-07 21:29:12 +03:00
Levko Kravets
9c0450c84e Explicitly sort routes to reduce a chance of conflicts (#5020)
* Explicitly sort routes to reduce (avoid at all?) a chance of conflicts

* Sort routes by params count
2020-07-03 21:11:39 +03:00
Levko Kravets
74f206614f Refactor: extract commonly used pattern into hook (#5022) 2020-07-03 10:44:51 +03:00
Gabriel Dutra
2f26cf791c Fix Databricks Schema Browser scrollbar (#5023) 2020-07-02 17:20:22 -03:00
Levko Kravets
c6be5758ad Y-axis autoscale fails when min or max is set (#4904)
* getredash/redash#4784 Y-axis autoscale fails when min or max is set

* Update tests

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-07-02 20:33:20 +03:00
Alex Kovar
8341592b05 Add plus between tags to clarify how they are used #4628 (#5017)
Co-authored-by: Levko Kravets <kravets-levko@users.noreply.github.com>

Co-authored-by: Levko Kravets <kravets-levko@users.noreply.github.com>
2020-07-02 18:44:38 +03:00
Gabriel Dutra
a7edbf1e8d Handle React exception when a function is provided (#5016) 2020-07-01 22:53:42 -03:00
Gabriel Dutra
217f41b586 Allow GET from non-admins on data source resource (#4992) 2020-07-01 10:10:24 -03:00
Gabriel Dutra
a8bd07e293 Databricks custom Schema Browser (#5010) 2020-07-01 10:09:18 -03:00
Omer Lachish
332c16b130 add a couple of missed custom key types hooks (#5014) 2020-07-01 12:39:46 +03:00
Vladislav Denisov
7940d36616 Python query runner fix (#4966)
* fixed print method

* fixed `.items()` error

* added extra builtins

* added guarded_unpack_sequence
2020-07-01 10:53:27 +03:00
Daniel Lang
68b70ed63b Fixed broken custom JS visualization settings (#5013) 2020-07-01 01:22:07 -03:00
Gabriel Dutra
e0297835df Add "Last 12 months" option to dynamic date ranges (#5004) 2020-06-30 09:56:00 -03:00
Omer Lachish
004bc7a2ac Custom primary/foreign key types (#5008)
* allow overriding the type of key used for primary/foreign keys of the different models

* rename key_types to singular key_type

* add some documentation for `database_key_definitions`
2020-06-30 15:08:28 +03:00
Gabriel Dutra
efcf22079f Allow private addresses when enforcing is disabled (#4983) 2020-06-30 10:54:49 +03:00
Levko Kravets
a83cb18cc5 Textbox: confirm close if text was changed (#5009)
* Textbox: confirm close if text was changed

* Update texting (with @gabrieldutra)

* Update texting

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-06-29 19:29:56 +03:00
Levko Kravets
1ecdf7b853 Too large visualization cause filters block to collapse (#5007) 2020-06-29 15:20:08 +03:00
Omer Lachish
90024ebc92 Delete locks for cancelled queries (#5006)
* delete locks for cancelled queries

* test that query cancellations do not prevent reenqueues
2020-06-29 13:09:01 +03:00
Gabriel Dutra
a37b7babbf Remove pace-progress (#4990) 2020-06-28 15:27:48 -03:00
Mike Nason
8f4ac958b1 Fix org option in users create_root cli command (#5003)
Thanks @nason 👍
2020-06-25 22:02:46 +03:00
Omer Lachish
637d9837f4 Avoid purging operational queues (#4973)
* avoid purging operational queues

* schema queues actually run queries, so they should be purged
2020-06-25 15:35:50 +03:00
Levko Kravets
bdd3c3e735 Dynamically register frontend routes (#4998)
* Allow to override frontend routes

* Configure app before initializing ApplicationArea

* Refine code
2020-06-25 13:38:23 +03:00
Levko Kravets
6fc35510d3 Allow unregistering settings tabs (#5000) 2020-06-25 12:54:46 +03:00
Levko Kravets
6f842ef94a Refactor User Profile page and add extension points to it (#4996)
* Move components specific to UserProfile page to corresponding folder

* Split UserProfile page into components

* Rename components, refine code a bit

* Add some extension points

* Fix margin
2020-06-25 12:03:19 +03:00
Levko Kravets
a563900f0a Refactor Organization Settings and add extension points to it (#4995)
* Split OrganizationSettings page into components

* Update change handling: use objects instead of string keys, move some logic to more appropriate place

* Convert OrganizationSettings page to functional component and refine code a bit

* Add some extension points

* Improve onChange handler

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-06-24 12:36:45 +03:00
Gabriel Dutra
ee3930c64d Catch QueryResultError on widget load (#4991) 2020-06-23 19:48:14 -03:00
Levko Kravets
10bff8b3b1 Some permissions fixes (#4994)
* Don't show New ... buttons on list pages if user doesn't have corresponding permissions

* Hide Create menu item if no create actions available
2020-06-23 22:56:24 +03:00
Jim Sparkman
a8510d1ad5 Fix CLI command for "status" (#4989)
* Fix CLI command for "status"

CLI command "status" can fail due to incorrect connection information to RQ.

This change matches the behavior from line 65 and solves the connection error.

* Move connection up to CLI entrypoint
2020-06-23 14:40:36 +03:00
Levko Kravets
3a543a4ab2 ErrorMessage is not centered (#4981)
* ErrorMessage is not centered

* Adjust ErrorMessage size on large screens

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-06-18 15:35:51 +03:00
Levko Kravets
2b1ba1ee33 Add New Dashboard/Query/Alert buttons to corresponding list pages (#4976) 2020-06-18 15:23:48 +03:00
Levko Kravets
4a54ad9d06 Add/Edit Tags dialog does not set focus on tags input (#4979)
* Refactor: convert EditTagsDialog to functional component; properly cleanup on destruction

* Pass focus to select when EditTagsDialog opens
2020-06-18 15:05:07 +03:00
Levko Kravets
676f560830 Navbar: show correct settings link for non-admin users (#4978)
* Non-admin users have an access to some settings, so need to show correct menu item in navbar

* Refine settings test

* Add some tests
2020-06-18 14:49:08 +03:00
Levko Kravets
98a5154345 Fix headless mode (didn't work with vertical navbar) (#4977)
* Fix headless mode (didn't work with vertical navbar)

* Fix header margins on public dashboard page

* Fix test
2020-06-17 11:10:12 +03:00
Gabriel Dutra
4c324ddc80 Custom Query components per Data Source type (#4948) 2020-06-15 16:13:10 -03:00
Gabriel Dutra
05c2233782 Don't reuse getErrorMessage (#4968) 2020-06-15 07:45:02 -03:00
Levko Kravets
0ac24e38a1 Vertical navbar (#4859)
* Vertical navbar

* Update vertical menu look and add create menu.

* Make query editor work with vertical nav.

* Dark mode

* Fix create menu & make sidebar fixed.

* Update Alert pages layout

* Update System status pages

* Update Queries and Dashboards list pages

* Update Query Source and Query View pages

* Use dark theme for mobile navbar

* Update Dashboard page: fix Add widget/textbox panel positioning

* Dashboard page: fix layout issues when container changes its size (fixes known issues: navbar expand/collapse, scrollbar appears/hides)

* Fix dashboard page sticky header (there was a 15px space above it)

* Fix embeds

* Extract desktop navbar component; move mobile navbar and its styles to ApplicationLayout folder

* Remove old app header

* Fix tests

* Restore version info block

* Make Percy capture entire page

* Make vertical navbar expand/collapse animation smoother (as it's currently impossible to disable it :-( )

* Fix misc UI issues (show Create label on expanded menu; fix some CSS; don't select items on click)

* Allow to override navbars with DynamicComponent

* Fix misc UI issues: expand/collapse button animation, menu items styles, menu expand/collapse animation

* Hide submenu arrow; show username when menu is expanded

* Refine CSS and make it more isolated; adjust colors

* Update tests

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-06-15 10:01:49 +03:00
Arik Fraimovich
d036df0ca1 V9 changelog (in master) (#4967)
* V9 Changelog: Initial Draft from Jesse

* V9 Changelog: Add later updates

* Adjust title spacing

* Apply Jesse's suggestions

Co-authored-by: Jesse <jesse@whitehouse.dev>

* provide an explanation on how to switch from Celery to RQ when upgrading to v9

* Update CHANGELOG.md

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

* Add contributor names

* Update version.

* Update CHANGELOG

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
Co-authored-by: Jesse <jesse@whitehouse.dev>
Co-authored-by: Omer Lachish <omer@rauchy.net>
2020-06-11 12:33:36 +03:00
Gabriel Dutra
56df870f39 Plotly Charts: use .legend to determine legends size (#4935)
* Plotly Charts: use .bg to determine legends size

* Test: remove hack for legend below plotly

* Revert "Test: remove hack for legend below plotly"

This reverts commit d8efb0c032.

* Use .legend to calculate bounds

* Also update plots without legend
2020-06-11 12:30:55 +03:00
Arik Fraimovich
05540164e1 Small updates to Dockerfile (#4964) 2020-06-11 12:28:59 +03:00
Gabriel Dutra
bdb62365b1 Fix Sankey issue to render 1 and 5 stages (#4965)
* Sankey: Make sure last stage has "Exit"

* Sankey: Use 2 as min stage width size to render

* Use null instead of "Exit"

* Add comment about corresponding exit node

* Add multiple stages on Cypress test
2020-06-11 12:28:45 +03:00
Gabriel Dutra
6a12168f40 Make sure page updates when 'routes' changes (#4962) 2020-06-09 15:43:23 -03:00
Gabriel Dutra
ac0b494953 Fix Destination not returning custom error message (#4959) 2020-06-09 11:14:29 -03:00
Gabriel Dutra
77e8d70a64 Make sure queries have options and parameters (#4952) 2020-06-09 11:13:42 -03:00
Rob Hudson
8597b727a7 Update requirements_bundles versions and comment (#4939) 2020-06-09 13:38:29 +02:00
Omer Lachish
e233611840 Fix wrong Sentry exception messages on invalid parameters (#4945)
* don't join underlying exception message with commas when invalid parameter errors happen

* Revert "don't join underlying exception message with commas when invalid parameter errors happen"

This reverts commit 71a21b7ce6.

* when a problem occurs during refresh_queries, report it as a RefreshQueriesError
2020-06-07 13:05:31 +03:00
Gabriel Dutra
dd6098d405 MongoDB: Only set readPreference when it has one (#4947)
* MongoDB: Only set readPreference when it has one

* Use .get for readPreference
2020-06-07 12:39:43 +03:00
Omer Lachish
d38d3b6b4d support comma-separated queue lists for backward compatability (spaces are still supported) (#4937) 2020-06-03 15:13:52 +03:00
Gabriel Dutra
100c7be5e0 Return cached data source schema when available (#4934) 2020-06-02 11:26:53 +03:00
chulucninh09
733bc1c109 fix strftime format notation for second and millisecond (#4922) 2020-05-31 22:23:42 +03:00
Saravanan Selvamohan
19cc7f1be8 Added correct usage of the article (#4911)
Add an article - the level
Correct article usage - a schema browser
Consider adding hyphen - ready-made
Removed comma - environment
2020-05-31 22:22:01 +03:00
Arik Fraimovich
43e5c2aa11 Fix: auto hide Plotly Modebar (#4930)
* Only set value for displayModeBar if we want to hide it

* Update viz-lib/src/visualizations/chart/Renderer/PlotlyChart.jsx
2020-05-31 21:18:52 +03:00
Gabriel Dutra
376b317e2e Update requests usages not to allow redirects (#4924)
* Update requests usages not to allow redirects

* Remove type from super()

Co-authored-by: Jannis Leidel <jannis@leidel.info>

Co-authored-by: Jannis Leidel <jannis@leidel.info>
2020-05-31 12:49:39 +03:00
Levko Kravets
d550427485 Fork button disabled on View Query page for non-admin users (#4927) 2020-05-29 11:41:07 +03:00
Ievgen Aleinikov
d1044c1963 Athena: set query cost (#4077) 2020-05-27 13:16:46 +03:00
Gabriel Dutra
46e18b0c6f Use memoized query result data (#4920) 2020-05-26 11:30:31 -03:00
Levko Kravets
38dd3ff248 Fix flaky Map (Markers) tests (#4915)
* Fix flaky Map (Markers) tests

* Fix flaky Choropleth tests
2020-05-26 10:57:08 +03:00
Gabriel Dutra
6bac19c1e4 Use Antd Descriptions on Details visualization (#4914)
* Use Antd Descriptions for Details visualization

* Update styling

* Add some spacing to pagination
2020-05-26 09:52:03 +03:00
Gabriel Dutra
ce6bc2d64a Update antd to v3.26.17 (#4913)
* Update antd to v3.26.17

* Remove custom bg color for danger button

* Update ScheduleDialog snapshot
2020-05-24 22:28:39 +03:00
Gabriel Dutra
27c4992003 Use lambda on options for destinations factory (#4912) 2020-05-24 22:22:01 +03:00
Gabriel Dutra
13e454de86 Update Query Page shortcuts for MacOS (#4910)
* Add Ctrl+Enter to run queries (for Mac)

* Check altKey and show as "Option" key when for Mac
2020-05-24 11:19:50 +03:00
Levko Kravets
f4c9d7db1a getredash/redash#4692 When resizing chart to a certain size it errors out (#4907) 2020-05-24 11:17:25 +03:00
Gabriel Dutra
0d11d7bec2 Change visualizations build to be on postinstall instead of preinstall (#4909) 2020-05-22 11:07:52 -03:00
Arik Fraimovich
ec68e8bba3 Fix: table viz crashing when search is enabled (#4899)
* Fix: table viz crashing when search is enabled

* Replace that weird hack with more controlled code

* Don't clear search input, apply search when data changes

Co-authored-by: Levko Kravets <levko.ne@gmail.com>
2020-05-21 11:13:36 +03:00
chulucninh09
831512e52d Fix: front-end error when parse python float nan (#4903)
* float nan or inf will be serialized as null instead of NaN

* Re-implement float nan serialization fix for consistency
2020-05-21 11:12:19 +03:00
Patrick Yang
dfc873fb8b Add additional statsd metrics for worker/scheduler (#4884)
* Add additional statsd metrics for worker/scheduler
2020-05-20 14:35:55 -07:00
koooge
b117485571 chore: Skip dev install in frontend testing (#4897)
Signed-off-by: koooge <koooooge@gmail.com>
2020-05-20 13:14:28 +03:00
Gianni Moschini
3661d6cbc5 Remove heroku bin/pre_compile file (#4900) 2020-05-20 13:02:39 +03:00
Jannis Leidel
a2217cc4ec Set the schema item title attribute correctly. (#4892)
Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-05-15 15:04:00 -03:00
Gabriel Dutra
a7ea94f69a Pin @percy/agent version and update Cypress (#4896) 2020-05-15 14:22:43 -03:00
Gabriel Dutra
8010781f0d Add private address check to BaseHTTPQueryRunner (#4885)
Co-authored-by: Arik Fraimovich <arik@arikfr.com>

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-14 09:56:22 +03:00
Gabriel Dutra
7c8874b8ee Fix HelpTrigger in header not working (#4887) 2020-05-12 12:56:04 -03:00
Arik Fraimovich
8907a86e33 Make frontend build in Docker image optional (#4879)
* Add build arg to Dockerfile to control if we should build frontend assets

* Move more env settings into the shared one.

* Use build arg in docker-compose to skip frontend build.

* CirlceCI: Skip building frontend assets in backend tests

* Create dummy template files

* Expand file names manually.

* Add build arg to skip dev dependencies.

* Update Dockerfile

* Reverse logic of skip_dev_deps to what it should be.
2020-05-12 16:46:53 +03:00
Gabriel Dutra
22f0030864 Add release to html webpack config (#4883)
Co-authored-by: Arik Fraimovich <arik@arikfr.com>

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-12 10:55:48 +03:00
Gabriel Dutra
baf16d2501 Oracle: Encoding fix (#4882)
* Oracle: Encoding fix

Co-authored-by: Arik Fraimovich <arik@arikfr.com>

* Update redash/query_runner/oracle.py

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-12 10:54:32 +03:00
Gabriel Dutra
0446080d3f Yandex Metrica: rename .host to .url. (#4880)
Co-authored-by: Arik Fraimovich <arik@arikfr.com>

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-12 10:42:07 +03:00
Arik Fraimovich
a8a2964cb0 Make the Databricks driver URL and environment variable (#4878)
* Make the Databricks driver URL and environment variable

* Replace ENV with ARG
2020-05-11 13:24:11 +03:00
Omer Lachish
9562718a6a Run queries through ad-hoc SSH tunnels (#4797)
* run queries through adhoc SSH tunnels

* reduce indent by losing try/else clause

* document host/port getters and setters

* handle forceful schema refreshes in RQ and poll for their results using the /jobs endpoint

* set schema refresh timeout to 5 minutes

* Restyled by prettier (#4847)

Co-authored-by: Restyled.io <commits@restyled.io>

* send schema refresh errors as part of API response

* Use correct get_schema call.

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-11 13:22:40 +03:00
Takuya Arita
e470347d7f Refactor docker-compose.yml for development (#4544)
* Update description for the new setup repository

* Refactor docker-compose.yml for development

* Use Docker Compose file v2
2020-05-11 13:01:32 +03:00
Gabriel Dutra
76aeab02eb Postgres: Add support for uploading SSL certs (#4871)
Co-authored-by: Arik Fraimovich <arik@arikfr.com>

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-08 09:42:00 +03:00
Gabriel Dutra
9568c74fd0 Sentry's Performance tracing (#4872)
* Upgrade sentry-sdk

Co-authored-by: Arik Fraimovich <arik@arikfr.com>

* Move traces sample rate to configuration

Co-authored-by: Arik Fraimovich <arik@arikfr.com>

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-08 09:40:20 +03:00
Gabriel Dutra
57287b2c0b Fix: there is no host field. (#4873)
Co-authored-by: Arik Fraimovich <arik@arikfr.com>

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-05-08 09:39:22 +03:00
Gabriel Dutra
6d857588a1 Log data source id on errors (#4874)
Co-authored-by: Omer Lachish <omer@rauchy.net>

Co-authored-by: Omer Lachish <omer@rauchy.net>
2020-05-08 08:59:06 +03:00
Levko Kravets
dc49585320 Add option to explicitly set chart legend position (#4865)
* Add option to explicitly set chart legend position

* Revert some chanes in order to fix tests

* Leave only "auto" and "below the plot" legend placement options

* Move Show legend checkbox to select; fix spelling
2020-05-07 17:21:31 +03:00
Gabriel Dutra
fc246aafc4 Separate visualizations into their own package (#4837)
* Add visualizations project settings

* Move visualizations to redash-visualizations

* Delete shared components

* Remove antd from deps

* Remove p-r-5 from table utils

* Remove visualization deps from package.json

* Rename package and change its version

* Test preinstall script

* Update Dockerfile build for frontend

* Test adding dockerignore

* Update jest tests

* Add step for jest tests

* Include viz-lib on dev commands

* User prettier v1 for now

* Delete unused libs on the app

* Add readme draft (to be finished)

* Add getOptions to Editor

* Add required libraries and finish basic example

* Bump version
2020-05-06 10:49:15 +03:00
Gabriel Dutra
4f8d2caed4 Cypress: Add tests for Filters (#4757) 2020-05-05 01:12:01 -03:00
Levko Kravets
27eab28405 Search in navbar works only for first search term (#4857)
* Queries list page: react on search term change (from navbar)

* Items List components: update search input value when changed "outside"

* Code style
2020-05-04 15:05:49 +03:00
Reynold Xin
8a9a2e7199 Minor tweak to README (#4862) 2020-05-04 10:23:02 +03:00
Reynold Xin
8d29e80013 A new intro paragraph to explain what Redash is (#4861)
* A new intro paragraph to explain what Redash is

We have been using Redash at Databricks and really love it. I took the time to work with Arik to create a better, more up-to-date description of the project.

* Add data sources
2020-05-03 23:43:11 +03:00
Gabriel Dutra
0e3d25c40c Fix visualizations with filters not showing selected values (#4854) 2020-05-03 12:37:23 -03:00
Arik Fraimovich
fdc4205774 Add blob: to allowed img-src rules in CSP (#4860)
This is needed for Plotly download PNG feature to work.
2020-05-03 12:32:17 +03:00
Arik Fraimovich
873c87b4b3 Fix: showing current settings tab broken in MULTI_ORG. (#4855)
* Fix: showing current settings tab broken in MULTI_ORG.

* Revert "Fix: showing current settings tab broken in MULTI_ORG."

This reverts commit a88defd0b5.

* Add test for SettingsMenu#isActive

* Use stripBase to remove slug from url
2020-05-02 14:45:54 +03:00
Gabriel Dutra
ae9bbe25e5 Cypress: Assert results keep up on widget refresh (#4846) 2020-04-30 12:20:04 +03:00
koooge
e3fff396cb chore: Update node8 to 12 (#4845)
Signed-off-by: koooge <koooooge@gmail.com>
2020-04-30 12:19:06 +03:00
Gabriel Dutra
f37e3d5a10 Fix dashboard not showing results while refreshing (#4840) 2020-04-29 21:09:35 +03:00
Gabriel Dutra
45e1478be3 Specify restylers versions for restyled (#4842)
* Specify restylers versions for restyled

* Trigger file change for testing

* Revert "Trigger file change for testing"

This reverts commit d203e37700.
2020-04-29 15:44:57 +03:00
Jannis Leidel
2c90d920b3 Add ability to ship periodic RQ jobs as part of extensions again. (#4822)
This was dropped in aa17681af2.
2020-04-28 18:39:30 +02:00
Gabriel Dutra
bb767f3747 Remove Helper Classes from visualizations (#4788) 2020-04-25 15:51:21 -03:00
Gabriel Dutra
60bc1f8e35 Visualizations customizable settings (#4793) 2020-04-25 12:33:42 -03:00
koooge
de6d665c6e fix: Make sure boto installed (#4835)
Signed-off-by: koooge <koooooge@gmail.com>
2020-04-25 12:34:45 +03:00
Arik Fraimovich
60f92a2efc Add column description to table viz (#4831)
* Add column description to table viz

* Fix: misplaced super long titles tooltip.
2020-04-24 18:50:45 +03:00
Arik Fraimovich
ea8a075a2d ODBC Based Databricks Connector (#4814)
* ODBC Based Databricks connector.

* Install Databricks' ODBC driver in Docker image

* Add useragent string.

* Add Types enum to redash.query_runner to replace the seprate constants.

* Databricks connector:

1. Parse types.
2. Send additional connection options.
3. Correctly parse errors.

* Switch to TYPE constants to use code with Python 2.

* Add note about the Databricks driver terms and conditions.

* Show message about Databricks driver terms and conditions.

* Handle cases when the query doesn't return any results.

* Update redash/query_runner/databricks.py

Co-Authored-By: Jesse <jesse@whitehouse.dev>

* Use new Databricks logo

* Fix connection string options

Co-authored-by: Jesse <jesse@whitehouse.dev>
2020-04-24 18:04:44 +03:00
Arik Fraimovich
6ee9b43ef9 Show explicit user name instead of avatar in lists. (#4828) 2020-04-24 17:32:45 +03:00
Arik Fraimovich
cfc82156c2 Reduce number of queries used to load the dashboards list (#4816)
* Reduce number of queries used to load the dashboards list.

* Use DashboardSerializer everywhere.

* Call serialize
2020-04-21 10:07:48 +03:00
Omer Lachish
ab6dc51540 reset is_invitation_pending if someone tries to login through a reset passwrod link for the first time (#4817) 2020-04-20 20:39:08 +03:00
James T. Boylan
70186ab835 Dashboard Search bug fix (#4804)
* Move Dashboard off `subqueryload()` loader in all() method due to inconsistent results bug in SQLAlchemy when leveraging distinct within a subqueryload call through paginate.

* Added source reference to Presto Query Runner connection through the pyhive client to announce to presto that the query is coming from `redash` instead of `pyhive`.

* Removing source line from presto query runner to refactor based on feedback.
2020-04-19 21:46:25 +03:00
Matt N
e99c37a36a Don't immediately remove notifications from notification trays (#4773)
Let the notifications go into browser/OS notification trays so users can click on them from there if they miss the initial notification. Modern browsers generally use OS notifications so the user is in control of the notification at the OS level.
2020-04-14 14:27:03 +03:00
Cemre Mengu
de40f1a07b Fix comparison error when scale is None (#4638)
* Fix comparison error when scale is None

Prevents `'>' not supported between instances of 'NoneType' and 'int'` error when scale is `None`

* Update oracle.py

* Fix scale logic.

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-04-14 13:36:12 +03:00
Arik Fraimovich
2c1eb5c10d Disable Percy snapshot for Choropleth test (#4799)
* Disable Percy snapshot for Choropleth test

* Increase wait.

* Diasble Percy snapshot.

* Reduce wait time to original value.

* Restyled by prettier (#4800)

Co-authored-by: Restyled.io <commits@restyled.io>

* Update choropleth_spec.js

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <commits@restyled.io>
2020-04-14 13:34:35 +03:00
Daniel Lang
02cf895983 Added setting to hide Plotly mode bar (#4644) 2020-04-14 13:08:17 +03:00
Stefan Mees
940bd564d7 Datasource Exasol: support encryption setting (#4712)
* add pyexasol datasource, ensure that integer dont overflow in javascript

* support setting encryption for Exasol connections

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-04-14 12:38:01 +03:00
Jesse
9ba57a9491 Adds option to show 500 rows in the table visualization. Previous max (#4770)
was 250.
2020-04-14 12:36:27 +03:00
Omer Lachish
b80abd11fb use total_seconds to find stale jobs (#4777) 2020-04-14 11:49:17 +03:00
Levko Kravets
1d4ca5cf2e Pie Chart: set contrast colors for text in sectors (#4783) 2020-04-14 11:48:54 +03:00
Weng Kham
f7df6e0cdc Fix test connection on mongodb datasource (#4785)
Co-authored-by: Weng Kham Kan <wengkham.kan@icarasia.com>
2020-04-14 11:47:14 +03:00
Gabriel Dutra
3df1a86d66 Fix param added with empty query ignores options (#4736) 2020-04-14 11:41:52 +03:00
Gabriel Dutra
bad1294402 Dashboard Performance: Memoize widgets (#4734) 2020-04-14 11:04:39 +03:00
Gabriel Dutra
3d26afef16 Move the dropdown to the side in Edit Mode (#4758) 2020-04-14 10:37:06 +03:00
Logan Price
2d29240195 feature: add ability to make the restriction of api calls to private addresses optional (#4790)
* feature: add ability to make the restriction of api calls to private addresses optional

* chore: fix typo

* Update redash/settings/__init__.py

Co-authored-by: lprice92 <lprice92@iastate.edu>
Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-04-14 10:34:13 +03:00
Gabriel Dutra
c698359cb8 Remove "context" prop from visualizations (#4789) 2020-04-13 10:17:33 -03:00
Gabriel Dutra
2b3d9053e9 Fix Multi-Filters: "select all" makes table view unscrollable (#4782)
* Limit filters to 40% of query fixed layout space

* Add check for height to determine fixed layout

* Add maxTagCount of 5 to Filters

* Update maxTagCount settings to be similar to Parameters
2020-04-13 15:13:28 +03:00
Atharva Inamdar
45ea5171cb 4791 redshift schema bugfix (#4792)
* #4791 exclude pg_ tables from redshift table schema inspection

* restrictict only pg_temp
2020-04-12 13:56:06 +03:00
Omer Lachish
6a5445b726 sent stack trace to Sentry when refresh_queries fails to enqueue a certain query (#4780) 2020-04-08 16:34:36 +03:00
Levko Kravets
51b573230f Upgrade Plotly (#4752)
* Upgrade Plotly

* Fixes to Plotly wrapper

* Decrease plot margins

* Adjust plot margins
2020-04-06 13:35:39 +03:00
Levko Kravets
54b04eaff7 Pie chart ignores series labels (#4775) 2020-04-06 13:31:58 +03:00
Georgi Staykov
1e96faed3b Add db thread pool option to keep idle connections alive (#4741)
* Add db thread pool option to keep idle connections alive

* Add SQLALCHEMY_ENABLE_POOL_PRE_PING setting

* Change SQLALCHEMY_ENABLE_POOL_PRE_PING default value to false.

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-04-05 14:13:20 +03:00
Arik Fraimovich
90bfba57d4 Fix: extendedEnum breaks JSONSchema parsing (#4774)
(probably due to Python 3 migration)
2020-04-03 12:07:25 +03:00
lihan
7f2a0af841 Removing the PIP cache from the built image (#4766) 2020-04-03 12:06:55 +03:00
Arihant Surana
f9e3ac7534 feat: Add ssl options for Cassandra data source (#4665)
* feat: provide ssl options for Cassandra data source

* remove Log and prints

* Refactor to create module methods and unit tests

* Switch to using Enumerator and temp file

* Fix temporary file lifecycle for cert

* Align with changes on master

* Fix non certificate but ssl enabled usecase
2020-04-03 11:03:47 +03:00
Gabriel Dutra
4d266176d0 Fix parameter spec flaky test (#4771) 2020-04-02 16:01:22 -03:00
Levko Kravets
3373cfc1eb Sankey diagram should occupy all available area (not just the left part) (#4765)
* Code style

* Remove dead and duplcated code

* getredash/redash#4763 Sankey diagram should occupy full available area (not just the left part)
2020-03-31 23:10:27 +03:00
Gabriel Dutra
e3745f8ba3 Fix there's no publish button on mobile query page (#4760) 2020-03-30 18:16:36 -03:00
Arik Fraimovich
3f6699032f Add apt update step in build docker image job. 2020-03-24 16:11:49 +02:00
Gabriel Dutra
adf8b2e42b Cypress: Add/Edit query and dashboard tags spec (#4744) 2020-03-24 16:03:22 +02:00
Gabriel Dutra
8db1612689 Fix query based param with no results crashing page (#4707)
* Fix query based param with no results crashing page

* Add message for empty dropdown parameters

* Handle 500 no results case with empty result set

* Cypress: Make sure it shows the message

* Use .ant-select-selection to open dropdown
2020-03-24 14:48:14 +02:00
Gabriel Dutra
fabaf73b7b Move data source/destination deprecated handling to frontend (#4753)
* Move DS deprecated handling to frontend

* Add Cypress assertion for deprecated types
2020-03-24 10:09:03 +02:00
Ezekiel Templin
45914f941f Set POSTGRES_HOST_AUTH_METHOD environment variable (#4740)
Redash's docker-compose file will no longer bring up an environment from
a cold start due to recent upstream changes to the postgres image that
force the user to either set a password for the default superuser or
opt-in to allowing all connections without a password via environment
variable.

Upstream PR: https://github.com/docker-library/postgres/pull/658
Related Discussion: https://github.com/docker-library/postgres/issues/681
2020-03-18 14:52:23 +02:00
Gabriel Dutra
1e9b8f1126 Fix no button to add query tags (#4737) 2020-03-17 22:11:33 +02:00
Levko Kravets
52911b7be3 Cohort appearance settings (#4597)
* Cohort: add settings for tooltips, value formats and placeholder

* Cohort: add settings for colors

* Cohort: change all settings tabs to use horizontal inputs

* Cohort: show color labels in editor
2020-03-17 13:42:45 +02:00
Levko Kravets
a10a3f1731 getredash/redash#4728 DOMPurify by default removes 'target' attribute (#4729) 2020-03-17 13:30:55 +02:00
Gabriel Dutra
33131c1354 Trigger CI lint failure on warnings and fix failing frontend unit tests (#4735)
* Trigger lint error on warnings on CI

* Test removing pip3 command from frontend unit

* Test eslint warning

* Revert "Test eslint warning"

This reverts commit 89d407345a.

* Revert "Test removing pip3 command from frontend unit"

This reverts commit 424c900200.

* Run apt update before installing pip3
2020-03-16 13:27:21 +02:00
Gabriel Dutra
f6750428cf Dashboard Performance: HtmlContent improvements (#4726)
* Dashboard Performance: Memoize HtmlContent

* Only render HtmlContent if there is a description
2020-03-15 15:12:50 +02:00
Gabriel Dutra
f4b69d4495 Cypress: Separate start command and update to v4.1.0 (#4690) 2020-03-11 16:14:33 -03:00
Levko Kravets
db71ff399c Refactor dialog wrapper component (#4594)
* Dialog wrapper: stop using promises to handle results - replace with callbacks

* Dialog wrapper: handle async operation on close
2020-03-10 22:22:42 +02:00
Levko Kravets
e552effd96 Remove route.resolve feature (#4607)
* Stop using route.resolve feature (pages should load all the data themselves)

* Remove route.resolve feature

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-03-10 13:09:26 +02:00
Satyam Krishna
75cc6b3f53 Fix : Alembic migration for scheduled query from older to newer version (#4709) 2020-03-08 17:41:21 +02:00
Gabriel Dutra
bf3095c794 Update Dashboard and Alert headers with the Query one (#4710) 2020-03-06 14:26:37 -03:00
Omer Lachish
ee6dcab362 Cancel BigQuery Queries (#4701)
* cancel BigQuery queries when user requests cancellation or when the job times out

* create a new bigquery client to flush exising requests
2020-03-04 22:45:20 +02:00
Gabriel Dutra
e0312fb717 Mobile experience improvements (#4694)
* Allow touch action on dashboard grid

* Deactivate touch when resizing widgets

* Disable touch interactions on Plotly

* Update Plotly and use dragmode: false

* Remove autoFocus from ItemsList search

* Fix spacing for queries and dashboard favorites

* Make sure admin pages don't go over 100% width
2020-03-04 12:55:51 +02:00
Omer Lachish
791a0b3ec7 allow comparison with strings containing numbers as alert values (#4705) 2020-03-04 12:40:23 +02:00
Anton Yuzhaninov
e03e58c5c7 Fix: show size of actually used Redash database (#4706)
'postgres' is a default database name in the Docker image, but if an
external database server is used, than Redash database can have
a different name (specified in REDASH_DATABASE_URL).
2020-03-03 21:21:56 +02:00
Arik Fraimovich
78201c6108 Dynamic Form: boolean fields related fixes (#4586)
* Fix: when default value is false make sure it's still stringified.

* Fix: when extra field is of type boolean make sure it's different from default value to decide if it's open.

* Use isNil to check the default value

* Restyled by prettier (#4704)

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
2020-03-03 12:55:54 +02:00
Arik Fraimovich
d687befa59 Query page: update empty state text (#4699) 2020-03-03 10:53:45 +02:00
Gabriel Dutra
9635d00476 Fix error for query snippets with empty description (#4693) 2020-03-01 15:05:44 -03:00
Jesse
418590003e Solves redashlabs/product#47 (#4669) 2020-03-01 14:19:00 +02:00
Levko Kravets
3650f0c45b Table visualization: Show which columns are being used for search (#4680)
* Table visualization: Show which columns are being used for search

* Fix accidental bug
2020-03-01 14:15:49 +02:00
erels
668403c126 Fixed Clickhouse column name encoding problem (#4682) 2020-03-01 14:11:49 +02:00
Arik Fraimovich
4b94a5c88f Snowflake: use different method of showing columns if no schema specified in db name (#4696)
* Snowflake: use different method of showing columns if no schema specified in db name

* Update redash/query_runner/snowflake.py

Co-Authored-By: Omer Lachish <omer@rauchy.net>

* Update redash/query_runner/snowflake.py

Co-authored-by: Omer Lachish <omer@rauchy.net>
2020-03-01 13:55:28 +02:00
Omer Lachish
a9cb87d4b3 refresh_queries shouldn't break because of a single query having a bad schedule object (#4163)
* move filtering of invalid schedules to the query

* simplify retrieved_at assignment and wrap in a try/except block to avoid one query blowing up the rest

* refactor refresh_queries to use simpler functions with a single responsibility and add try/except blocks to avoid one query blowing up the rest

* avoid blowing up when job locks point to expired Job objects. Enqueue them again instead

* there's no need to check for the existence of interval - all schedules have intervals

* disable faulty schedules

* reduce FP style in refresh_queries

* report refresh_queries errors to Sentry (if it is configured)

* avoid using exists+fetch and use exceptions instead
2020-03-01 11:02:46 +02:00
Omer Lachish
b0f1cdd194 remove rq_healthcheck entrypoint and deprecate celery_healthcheck (#4574) 2020-02-27 17:55:04 +02:00
juanvasquezreyes
5d533a3277 Oracle: update DSN construction to support special characters in user/password. (#4659)
* Update oracle.py

The reason I propose this change is to fix an issue when oracle password has an @
example of connection string: user/p@ssword@host

* Update oracle.py

Fixing init after comments

* Remove empty constructor.

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-02-27 17:50:46 +02:00
Gabriel Dutra
5fa5cd958b Change visualization editor scroll to internal divs (#4689) 2020-02-26 23:09:53 +02:00
Levko Kravets
c5f14e5538 Use main react-grid-layout package instead of fork (#4687) 2020-02-26 21:20:30 +02:00
Levko Kravets
7043951f00 Use npm ci instead of npm install in CI scripts (#4688) 2020-02-26 19:23:32 +02:00
Omer Lachish
9790b0731d Perform cleanup on job timeouts (#4681)
* move repeated query cancellation error messages to the job serializer

* oerform cleanup on JobTimeoutException and DRY query cancellation exception blocks

* import JobTimeoutException directly from rq

* fix syntax error introduced by mistake

* add missing import
2020-02-26 13:24:57 +02:00
Levko Kravets
3102e2df94 Fix: Chart with a horizontal legend sometimes doesn't render properly (#4683) 2020-02-25 13:07:17 +02:00
Gabriel Dutra
f396c96457 Merge branch 'master' into query-based-dropdown--parameters 2020-02-25 07:49:36 -03:00
Omer Lachish
35250d64b9 Job timeout doesn't kill the mysql query (#4629)
* forward timeout SIGALRMs to MySQL threads in order to kill any running proccesses

* no need to attach to SIGALRM as RQ already does that
2020-02-25 00:16:19 +02:00
Gabriel Dutra
cdfa102125 Query View page design adjustments (#4670)
* Realign Data Source and Refresh Schedule

* Adjust execution status height

* Rewrite Query Page Header flexibility

* Remove margin from QuerySource parameters

* Cypress: Visit visualization instead of click in tab

* Fix wrong css class name in dashboard-grid
2020-02-24 21:05:58 +02:00
Gabriel Dutra
8bfcbf21e3 Remove redundant import 2020-02-24 11:44:28 -03:00
Gabriel Dutra
8a1640c4e7 Separate InputPopover component 2020-02-24 11:44:18 -03:00
Gabriel Dutra
209ee16261 Fix verification email url on home page (#4647) 2020-02-24 10:15:35 -03:00
Arik Fraimovich
f1a2f8cb88 Enable ODBC and MS SQL ODBC support (#4676)
Closes #4356.
2020-02-23 11:57:39 +02:00
Arik Fraimovich
dd8e23040a Remove core-js and polyfill include as we don't use Phantom anymore (#4583) 2020-02-23 11:15:53 +02:00
Gabriel Dutra
a37e7f93dc Add is_safe test for queries with params 2020-02-22 15:47:29 -03:00
Gabriel Dutra
cc34e781d3 Small updates
- Change searchTerm separator
- Add cy.wait
2020-02-22 15:23:43 -03:00
Gabriel Dutra
6aa0ea715e Invert tooltip messages order 2020-02-22 14:08:19 -03:00
Gabriel Dutra
6c27619671 Make Parameter Mapping required in UI 2020-02-21 23:00:26 -03:00
Gabriel Dutra
6eeb3b3eb2 Separate UI components 2020-02-21 15:49:23 -03:00
Gabriel Dutra
d40edb81c2 Fix backend tests 2020-02-21 14:18:59 -03:00
Gabriel Dutra
f128b4b85f Only allow search for Text Parameters 2020-02-21 13:36:06 -03:00
Gabriel Dutra
264fb5798d Merge branch 'master' into query-based-dropdown--parameters 2020-02-21 13:31:49 -03:00
Gabriel Dutra
90023ac435 Make sure Table updates correctly 2020-02-21 11:03:37 -03:00
Gabriel Dutra
df755fbc17 Add try except for NoResultFound 2020-02-21 09:40:52 -03:00
Gabriel Dutra
e555642844 Add is_safe check for parameterized query based 2020-02-21 09:27:12 -03:00
Gabriel Dutra
bdd7b146ae Change stored mapping attributes 2020-02-20 21:59:19 -03:00
Gabriel Dutra
b7478defec Don't validade query params with params 2020-02-20 19:29:43 -03:00
Gabriel Dutra
bb0d7830c9 Fixes + temp remove validation for Query param 2020-02-20 18:49:29 -03:00
Gabriel Dutra
d2cc2d20b6 Query Editor: Remove overflow visible from visualization (#4668) 2020-02-20 18:16:26 -03:00
Levko Kravets
7f8b103aea getredash/redash#4666 The download button on the dashboard will redirect users to an invalid page (#4667) 2020-02-20 21:16:16 +02:00
Gabriel Dutra
9eaa44da4a Query View redesign (#4536)
Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-02-19 17:47:34 -03:00
Gabriel Dutra
2833bb539f Fix Add Widget always shows recent queries list (#4658) 2020-02-18 18:01:26 -03:00
Gabriel Dutra
137aa22dd4 Parameter Mapping UI (2/2) 2020-02-18 17:55:27 -03:00
Levko Kravets
7ff5af1bf5 getredash/redash#4655 Closing the Help Drawer redirects you the homepage (#4657) 2020-02-18 21:23:23 +02:00
Omer Lachish
7124bc91d7 Avoid timing out when no timeout is set (#4653)
* soft limits should not exceed if they are set to run infinitely

* use a variable to explain magic number
2020-02-18 15:29:33 +02:00
Gabriel Dutra
9cf396599a Parameter Mapping UI (1/2) 2020-02-17 23:32:10 -03:00
Gabriel Dutra
b70f0fa921 Iterate over backend verification 2020-02-16 13:39:05 -03:00
Omer Lachish
abbfd598d7 support relative time in cloudwatch queries (#4649) 2020-02-16 12:23:25 +02:00
Gabriel Dutra
5e3613d6cb Start experiements with a 'search' parameter 2020-02-13 16:29:50 -03:00
Gabriel Dutra
545da898ee Fix dashboard editing permissions not working (#4613)
* Use dashboard.can_edit instead of checking owner

* Add owner or admin check to Manage Permissions

* Remove unnecessary useMemo
2020-02-13 11:50:45 +02:00
Omer Lachish
ddb0ef15c1 Set default query execution time limit to unlimited (#4626)
* default query execution time limit to 1 hour

* use -1 (run infinitely)  as a default limit
2020-02-11 11:23:02 +02:00
Jannis Leidel
9646156965 Handle stale jobs more carefully before purging them. (#4615) 2020-02-11 11:14:26 +02:00
Jannis Leidel
5c7cb1af3d Update cassandra-driver to 3.21.0. (#4636)
This provides binary wheel files and reduces Docker build times drastically.
2020-02-10 21:48:43 +02:00
Arik Fraimovich
2bd8771188 Fix: no need to encode strings anymore (#4627)
* It's 2020, we got Python 3, no need to encode strings anymore

* Remove encode calls from other places

* use alert.name directly
2020-02-10 20:34:42 +02:00
Arik Fraimovich
86f8f32ab4 Snowflake: switch to simpler query for fetching columns (#4634)
Because we already call USE DATABASE before running SHOW COLUMNS adding IN DATABASE is redundant, but causes an error if the user specifies a schema along with database name.
2020-02-10 20:34:23 +02:00
Gabriel Dutra
fdccaabbe9 Check for LDAP Login in Organization Settings (#4359)
* Check for LDAP Login in Organization Settings

* Restyled by prettier (#4570)

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
2020-02-10 20:13:56 +02:00
Levko Kravets
2f5920d5e4 getredash/redash#4601 Chart editor: enable search in columns selects (#4602) 2020-02-09 17:38:48 +02:00
Omer Lachish
e97510b2ee Clickhouse: control whether to verify SSL certificate (#4631) 2020-02-09 16:03:43 +02:00
Omer Lachish
80cfa3c557 set correct values for ProxyFix (#4630) 2020-02-09 15:20:16 +02:00
mickeey2525
9b71b569e2 Fix treasuredata endpoint (#4582)
* fix treasuredata endpoint

* make endpoint as a required

* fix unneccessart required parameter
2020-02-09 13:52:44 +02:00
Arik Fraimovich
f2159472da Fix: encode/decode bytestring for base64. (#4624)
* Fix: encode/decode bytestring for base64.

* Apply b64encode fix to HiveHttp
2020-02-09 13:41:41 +02:00
Omer Lachish
c961c33e49 If the error message happens to be empty, it will break serailization. (#4622) 2020-02-09 13:17:43 +02:00
Omer Lachish
5afc94c562 sync_user_details doens't really need a custom ttl (#4625) 2020-02-09 12:57:16 +02:00
Jesse
cee1a07320 Sort schema columns alphabetically (#4595)
* Adds logic to sort column names returned by the query runner. If `sorted`
raises an Exception it returns the column names unaltered from the query
runner.

* Moves table name sorting from model code into schema handler.

* Moves token sorting into the model code.

* Replaces single-quotes with double-quotes for consistency.

* Applies black formatting to changes.

* Moves schema sort into separate method. Adds test.

* Fixes output schema variable name. Without this the sorted cache is never returned!

   ____  ____  ____  _____
  / __ \/ __ \/ __ \/ ___/
 / /_/ / /_/ / /_/ (__  )
 \____/\____/ .___/____/
           /_/

* Adds test case guaranteeing that the model actually _uses_ the schema sorter.

Related to a31f90178c
2020-02-09 12:40:47 +02:00
Eduardo Garcia
42b1eadeb2 Update copyright year to 2020 in LICENSE (#4616) 2020-02-09 12:39:22 +02:00
Omer Lachish
7edac9ca89 keep adhoc job results longer (determined by settings.JOB_EXPIRY_TIME) (#4559) 2020-02-09 12:28:58 +02:00
David Hernández
69893f0304 Force specific version of Werkzeug to prevent the breaking changes of the new release. (#4618) 2020-02-09 09:23:48 +02:00
Jannis Leidel
b089f5f0ef Use correct logger when enqueuing a query execution. (#4614) 2020-02-06 15:16:21 +01:00
Omer Lachish
7a34a76817 RQ: Missing currently executing queries view (#4558)
* add meta information to executing queries

* add a table for running queries

* add pagination to queues table

* sort the queues table

* add pagination to all tables
2020-02-03 23:51:20 +02:00
Levko Kravets
2de3895986 Query editor: fix shortcuts (#4598) 2020-01-29 21:26:05 +02:00
Levko Kravets
713fd2d0fb Change visualizations import to be static (#4592)
* getredash/redash#4565 Change visualizations import to be static

* Move visualizations-related components to own folder
2020-01-28 12:48:38 +02:00
Levko Kravets
19c6d331b6 Refine routes definitions (#4579)
* Refine routes definitions

* Replace HoC wrappers with functions to create route definition

* Some updates for code consistency

* ItemsList component: remove currentRoute dependency

* Prepare route parametes in wrapper functions
2020-01-26 14:53:40 +02:00
Omer Lachish
a36b10173c Fix empty values sent in dynamic form (#3886)
* remove legacy session identifier support

* remove redundant test

* redirect to login to support any invalid session identifiers

* be more specific with caught errors

* reject empty values in DynamicForm

* don't submit form values if they are empty (unless they are
intentionally set to empty string)

* set empty values to null to clear out data source option in the model

* check explicitly for null
2020-01-23 21:21:49 +02:00
Eran Sandler
7d11fae9ea Added support for running MongoDB queries on secondary in replicaset mode (#1424)
* - Added support to specify read preference when query a replicaset database (for example, secondaryPreferred - to try and read data from secondary before primary).
- Removed old code that used MongoClientReplicaSet as it is now just a reference to MongoClient
- Fixed a documentation type :-)

* Moving to PyMongo 3.3.1 which also supports MongoDB 3.2

* Changed the readPreference config to use an enum

* Pass readPreference to MongoClient

* primaryPreferred is now the default
2020-01-23 21:14:37 +02:00
Levko Kravets
35e41385dc Fixes several bugs on dashboard page (see description) (#4571)
* Move each hook to own file; move hooks and components to own folders

* Update URL and timer only when refresh rate changes

* Skip dashboard refresh if previous refresh is still running

* Fix test
2020-01-23 17:03:37 +02:00
Levko Kravets
cdefa847c0 Restore query execute notifications (missed during React migration) (#4577) 2020-01-23 16:21:51 +02:00
Levko Kravets
a90b8c7443 getredash/redash#173 Don't allow to fork query while previous fork is still in progress (#4578) 2020-01-23 16:08:59 +02:00
Levko Kravets
1ba3a23457 Bug: when using global dashboard filters, widgets continuously update their local filters (#4575) 2020-01-23 16:07:28 +02:00
Levko Kravets
8a5e0ea3f4 Refine Timer and TimeAgo components (get rid of force update) (#4580) 2020-01-23 16:06:38 +02:00
Levko Kravets
cbc56264ea React migration cleanup (#4572)
* Revisit ANGULAR_REMOVE_ME things

* Remove styles related to 3rd-party Angular and jQuery libraries

* Remove some more unused styles

* Revisit error handling (app-wide)

* Remove unused file

* CR1
2020-01-22 17:15:25 +02:00
Levko Kravets
c92bb63f8b Fix Map visualization: L.layerGroup cannot compute its bounds (#4573) 2020-01-22 10:11:29 +02:00
Levko Kravets
ff0dbd5f01 Save new query before adding new visualization (#4569) 2020-01-21 13:06:26 +02:00
Leo Palmer Sunmo
80bfd405fd Force saml auth scheme (#3614)
* Add SAML scheme override env var

* Make it pretty, please the linter

* Import settings properly
2020-01-21 11:45:21 +02:00
taminif
945f53fea3 delete variable (#3813)
* delete variable

* delete duplicate code

* add empty line

* delete empty line
2020-01-21 11:29:56 +02:00
Steve Buckingham
56b51be64a Add redshift role use option (#4532)
* Add redshift role use option

* Update requirements for SSL socket wrap issue fixes

* Split Redshift class into User and IAM logins

* Update incorrect register

* Change type names

* Correct class name to inherit

* Render IAM redshift image and field order correct

* Update redash/query_runner/pg.py

Co-Authored-By: Arik Fraimovich <arik@arikfr.com>

* Update redash/query_runner/pg.py

Co-Authored-By: Arik Fraimovich <arik@arikfr.com>

* Remove need for specified urllib - specify pyopenssl is enough

* Pyopenssl back down to 19.0.0

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-01-21 11:18:33 +02:00
Levko Kravets
a682265e13 Migrate router and <app-view> to React (#4525)
* Migrate router and <app-view> to React: skeleton

* Update layout on route change

* Start moving page routes from angular to react

* Move page routes to react except of public dashboard and visualization embed)

* Move public dashboard and visualization embed routes to React

* Replace $route/$routeParams usages

* Some cleanup

* Replace AngularJS $location service with implementation based on history library

* Minor fix to how ApplicationView handles route change

* Explicitly use global layout for each page instead of handling related stuff in ApplicationArea component

* Error handling

* Remove AngularJS and related dependencies

* Move Parameter factory method to a separate file

* Fix CSS (replace custom components with classes)

* Fix: keep other url parts when updating location partially; refine code

* Fix tests

* Make router work in multi-org mode (respect <base> tag)

* Optimzation: don't resolve route if path didn't change

* Fix search input in header; error handling improvement (handle more errors in pages; global error handler for unhandled errors; dialog dismiss 'unhandled rejection' errors)

* Fix page keys; fix navigateTo calls (third parameter not available)

* Use relative links

* Router: ignore location REPLACE events, resolve only on PUSH/POP

* Fix tests

* Remove unused jQuery reference

* Show error from backend when creating Destination

* Remove route.resolve where not necessary (used constant values)

* New Query page: keep state on saving, reload when creating another new query

* Use currentRoute.key instead of hard-coded keys for page components

* Tidy up Router

* Tidy up location service

* Fix tests

* Don't add parameters changes to browser's history

* Fix test (improved fix)

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
2020-01-20 20:56:37 +02:00
Arik Fraimovich
a891160b4d Upgrade snowflake-connector-python (#4567)
* Upgrade snowflake-connector-python

* Downgrade requests
2020-01-20 19:50:57 +02:00
Gabriel Dutra
086798bbb7 Fix Cypress issues after React version of Query Pages (#4545)
* Update Pivot rows assertion

* Allow replacing Query results with Apply Changes
2020-01-20 14:26:22 +02:00
Levko Kravets
ebcec85c0c Tags filter doesn't work because of wrong query params format (#4563)
* getredash/redash#4557 Tags filter doesn't work because of wrong query params format

* Fix tests
2020-01-20 12:49:17 +02:00
Gabriel Dutra
2b5bfad054 Add padding to QueryExecutionStatus text (#4553) 2020-01-16 21:18:06 +02:00
Gabriel Dutra
479b277b91 Add loading state to Query save button (#4551)
* Add loading state to Query save button

* Hide dirty indication and icon when saving
2020-01-16 14:21:38 +02:00
Arik Fraimovich
94ac11c787 webpack: remove children from output (#4540) 2020-01-14 14:05:37 +02:00
Jannis Leidel
a7ef3ad72a Get rid of six and fix str/unicode types regression that became active on Python 3. (#4533)
This was introduced in d38ca803c5.
2020-01-14 12:51:36 +02:00
Ari Ekmekji
afe8c95f4d Load collections in all workspaces (#4541) 2020-01-14 12:48:04 +02:00
Omer Lachish
fe06f7f63e Google Analytics runner - iterate over keys the Python 3 way (#4538)
* iterate over key names instead of dict_keys values

* use dict comprehension instead of manipulating existing dict
2020-01-13 14:41:30 +02:00
Omer Lachish
5e01211852 adjust imports to match influxdb 5.2.3 (#4531) 2020-01-13 10:43:29 +02:00
Gabriel Dutra
375ffd3250 Migrate services and replace $http with axios (#4497) 2020-01-12 22:25:26 -03:00
Omer Lachish
674f057c59 fix typo in azure kusto runner (#4537) 2020-01-12 22:45:32 +02:00
Omer Lachish
aa17681af2 Nuke Celery (#4521)
* enforce hard limits on non-responsive work horses by workers

* move differences from Worker to helper methods to help make the specialization clearer

* move HardLimitingWorker to redash/tasks

* move schedule.py to /tasks

* explain the motivation for HardLimitingWorker

* pleasing CodeClimate

* pleasing CodeClimate

* port query execution to RQ

* get rid of argsrepr

* avoid star imports

* allow queries to be cancelled in RQ

* return QueryExecutionErrors as job results

* fix TestTaskEnqueue and QueryExecutorTests

* remove Celery monitoring

* get rid of QueryTask and use RQ jobs directly (with a job serializer)

* Revert "remove Celery monitoring"

This reverts commit 37a74ea403.

* reduce occurences of the word 'task'

* use Worker, Queue and Job instead of spreading names that share behavior details

* remove locks for failed jobs as well

* did I not commit that colon? oh my

* push the redis connection to RQ's stack on every request to avoid verbose connection setting

* use a connection context for tests

* remove Celery monitoring

* 👋 Celery

* remove Celery from Cypress

* black it up

* some more black

* return all started/queued job ids (for future monitoring

* Restyled by prettier (#4522)

* remove celery.py

* remove some frontend residuals that reappeared after a merge

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
2020-01-12 22:36:48 +02:00
Takuya Arita
13c3531956 Update description for the new setup repository (#4535) 2020-01-12 15:22:10 +02:00
Gabriel Dutra
350716c525 Add maildev missing settings (#4527) 2020-01-10 09:29:33 +02:00
Gabriel Dutra
fe11b8cc35 Cypress: Add test for Settings Tabs (#4530) 2020-01-09 12:40:40 -03:00
Gabriel Dutra
465dbc03b7 Hide unavailable page links to non-admin users in settings and header (#4524)
* Filter unavailable menu items in SettingsWrapper

* Don't show Alert Destination in header to users
2020-01-08 10:59:59 +02:00
Gabriel Dutra
76f0dcb085 Replace angular-sanitize with DOMPurify (#4502)
* Switch angular-sanitize package with dompurify

* Replace $sanitize with DOMPurify.sanitize

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-01-08 10:56:11 +02:00
Gabriel Dutra
99c276fc9a Migrate Query pages to React (#4429)
* Migrate Query Source View page to React: skeleton

* Sync QueryView and QuerySource (#4430)

* Migrate schema browser to react (#4432)

* Restyle code with Prettier

* Migrate Query page to React: Save changes (#4452)

* Migrate query source to React: Set of updates (#4457)

* Migrate Query page to React: Visualization Tabs (#4453)

Co-Authored-By: Levko Kravets <levko.ne@gmail.com>

* Migrate Query Source page to React: Visualizations area (#4463)

* Migrate Query page to React: Delete visualization button (#4461)

* Migrate Query Source page to React: Visualization actions (#4467)

* Migrate Query pages to React: Execute query hook (#4470)

* Migrate Query Source page to React: Editor area (#4468)

* Migrate Query Source page to React: metadata, schedule and description blocks (#4476)

* Migrate Query page to React: Cancel query execution (#4496)

* Migrate Query Source page to React: refine code (#4499)

* Migrate Query Source page to React: alerts (#4504)

* Migrate Query Source page to React: unsaved changes alert (#4505)

* Migrate Query Source to React: resizable areas (v2) (#4503)

* Migrate Query page to React: Query View (#4455)

Co-authored-by: Levko Kravets <levko.ne@gmail.com>

* Switch React and Angular versions of pages (until Angular version removed)

* Migrate Query pages to React: fix permissions (#4506)

* Migrate Query Source page to React: don't reload when saving new query (#4507)

* Migrate Query pages to React: fix tests (#4509)

* Use skipParametersDirtyFlag in executeQuery

* Fix: cannot fork query from Query View page

* Optimize query editor: handle query text changes faster

* Revert "Optimize query editor: handle query text changes faster"

This reverts commit 2934e53be6.

* Reduce debounced time to 100

* Migrate Query pages to React: cleanup (#4512)

* Migrate Query pages to React: cleanup

* Further cleanup

* Remove unused dependencies

* Fix embed pages

* Attempt to fix flaky test

* Cleanup: explicitly register the last Angular component

* Move contents of /filters folder to /lib

* Remove unnecessary import

* Remove cy.wait from Parameters spec

Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>

Co-authored-by: Levko Kravets <levko.ne@gmail.com>
2020-01-06 20:51:45 +02:00
Levko Kravets
fc9e8fe2aa Add error boundary to catch errors in visualizations (#4518)
* Add error boundary to catch errors in visualizations

* Fix: Funnel crash when step column is date/time

* CR1

* CR2
2020-01-06 10:22:20 +02:00
Omer Lachish
260bfca767 Multiprocess RQ workers (using supervisor) (#4371)
* launch and monitor multiple workers using supervisor

* run supervisord in non-daemon mode

* redirect all output to stdout/stderr

* no need to log supervisord's output because it is redirected to stdout anyway

* updated and less brittle healthcheck

* add supervisor healthchecks

* remove redundant supervisor installation as it is installed by pip

* add a 5 minute check gate
2020-01-01 15:32:29 +02:00
Arik Fraimovich
f85490cf50 Fix: don't try to access message property of an exception (#4516)
(not supported in Python 3)
2019-12-31 12:45:29 +02:00
Gabriel Dutra
29582e3212 Run prettier on cypress folder (#4510)
* Run prettier on cypress folder

* Test Restyled

* Revert "Test Restyled"

This reverts commit 13d43968fe.
2019-12-30 19:40:56 +02:00
Omer Lachish
329e85987c Execute Queries in RQ (#4413)
* enforce hard limits on non-responsive work horses by workers

* move differences from Worker to helper methods to help make the specialization clearer

* move HardLimitingWorker to redash/tasks

* move schedule.py to /tasks

* explain the motivation for HardLimitingWorker

* pleasing CodeClimate

* pleasing CodeClimate

* port query execution to RQ

* get rid of argsrepr

* avoid star imports

* allow queries to be cancelled in RQ

* return QueryExecutionErrors as job results

* fix TestTaskEnqueue and QueryExecutorTests

* remove Celery monitoring

* get rid of QueryTask and use RQ jobs directly (with a job serializer)

* Revert "remove Celery monitoring"

This reverts commit 37a74ea403.

* reduce occurences of the word 'task'

* use Worker, Queue and Job instead of spreading names that share behavior details

* remove locks for failed jobs as well

* did I not commit that colon? oh my

* push the redis connection to RQ's stack on every request to avoid verbose connection setting

* use a connection context for tests

* black it up

* run RQ on all queues when running in Cypress
2019-12-30 14:11:01 +02:00
Arik Fraimovich
ff34dedf46 Fix: properly encode UTF-8 filenames in query results request (#4498)
* Fix: properly encode UTF-8 filenames in query results request

Ended up copying the implementation from Flask's send_file helper function, because send_file doesn't really fit our use case.

* Update tests/handlers/test_query_results.py

Co-Authored-By: Omer Lachish <omer@rauchy.net>

Co-authored-by: Omer Lachish <omer@rauchy.net>
2019-12-30 11:52:18 +02:00
Arik Fraimovich
d0fb377ed6 Viz Embed: Add option to hide timestamp (#4491) 2019-12-30 11:45:22 +02:00
Arik Fraimovich
30bc1e2ff6 Refine permissions usage in Redash to allow for guest users (#4492)
* Allow executing query with either view_query or execute_query permissions.

* Render AuthHeader according to permissions.

* Don't return dashboards where you only have access to textbox widget.

Closes #4099.
2019-12-30 10:07:20 +02:00
Gabriel Dutra
fd46194580 Update EditInPlace to use Antd components (#4493) 2019-12-26 12:53:33 -03:00
deecay
f5900a1929 Chart: Bubble size control by coefficient and sizemode (#3928) 2019-12-26 16:19:45 +02:00
Tsuyoshi Yoshizawa
c2b39db03e Support download as TSV File (#4445) 2019-12-26 16:16:48 +02:00
Omer Lachish
f420e02cee adjust imports to match simple-salesforce 0.74.3 (#4490) 2019-12-25 16:26:58 +02:00
Arik Fraimovich
0aa176e2e5 Don't update query's updated_at when updating schedule_failures counter (#4488) 2019-12-25 16:25:16 +02:00
Arik Fraimovich
97d523e348 Retain tags when forking a query (#4489) 2019-12-25 16:25:02 +02:00
Arik Fraimovich
88d21e9461 Add explicit handling of 404 errors in query result requests. (#4487) 2019-12-25 15:46:13 +02:00
Arik Fraimovich
40c1ef0f59 Fix: query results query runner fails to load cached results. (#4486) 2019-12-25 15:21:43 +02:00
Arik Fraimovich
10ba2ddbaa Snowflake: add missing date types (#4484)
Without those the values might be miscategorized in the UI.
2019-12-25 14:58:45 +02:00
Omer Lachish
e7eedd0556 fix all occurances of B306: BaseException.message has been deprecated as of Python 2.6 and is removed in Python 3. Use str(e) to access the user-readable message. Use e.args to access arguments passed to the exception. (#4482) 2019-12-25 10:13:39 +02:00
Omer Lachish
c3299ff0ad totalRows are returned as a string and should be a number (#4481) 2019-12-24 22:20:17 +02:00
Randy Zwitch
6b2f23f357 Update pymapd to 0.19.0 (#4424) 2019-12-24 15:34:42 +02:00
Arik Fraimovich
0819f80e72 Hive/Databricks: mark date types as TYPE_DATE. (#4419) 2019-12-24 10:39:56 +02:00
Gabriel Dutra
7223f60ddf Migrate VisualizationEmbed to React (#4364)
* Migrate VisualizationEmbed to React

* Angular cleanup

* Remove onClick event from TimeAgo

* Check Table exists before taking snapshot

* Apply Prettier
2019-12-24 10:21:48 +02:00
Gabriel Dutra
38b6b47594 Migrate Dashboard and Public Dashboard to React (#4228)
* Initial React Rendering with useDashboard

* Make sure widgets refresh + useCallback

* Rename collectFilters and add refreshRate

* Fix error updates not being rendered

* Only render widget bottom when queryResults exists

* Cleanup

* Add useCallback to refreshDashboard

* Make sure Promise.all have all promises done

* Start migrating Dashoard to React
- initial rendering
- some actions
- temporary updated less file

* Fullscreen handler added

* Separate refreshRateHandler hook

* Add a few tooltips

* Separate DashboardControl and normalize btn width

* Share Button

* Fix serach params not updating

* Enumerate More Options

* Toggle Publish options

* Archive Dashboard

* Parameters + Filters

* Prepare Manage Permissions

* Start to create edit mode

* Add Edit Mode functionalities

* Use previous state when updating dashboard

* Mobile adjustments

* PermissionsEditorDialog + Dashboard page title

* Update Dashboard spec

* Fix other specs

* Break dashboard.less

* Hide publish button on mobile

* Angular Cleaning

* Keep edit state when changing resolution

* Bug fix: Dashboard Level Filters not updating

* Remove prepareWidgetsForDashboard

* Revert "Remove prepareWidgetsForDashboard"

This reverts commit b434f03da1.

* Avoid saving layout changes out of editing mode

* Apply policy for enabled refresh rates

* Disable loadDashboard deps

* Restyled by prettier (#4459)

* Update title when dashboard name updates

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
2019-12-24 10:20:40 +02:00
Levko Kravets
49dcb7f689 Refactor QueryEditor component (#4464) 2019-12-20 15:35:43 +02:00
deecay
425e79fdd2 Fix prettier commandline option to be recursive (#4458) 2019-12-17 14:52:45 +02:00
Levko Kravets
bc52b78889 Third column not selectable for Bubble and Heatmap charts (#4449) 2019-12-16 13:00:17 +02:00
deecay
944adb95ba Map: add tooltip and popup templating (#4443) 2019-12-14 20:07:09 +02:00
Daniel Dubovski
8cb49158bf Adding application to Azure Kusto query runner (#4441)
This is to allow for better metrics collection and tracking on the service side.
More info can be found [here](https://docs.microsoft.com/en-us/azure/kusto/api/netfx/request-properties#the-application-x-ms-app-named-property)
2019-12-13 21:47:11 +02:00
Gabriel Dutra
ca098172e9 Fix Restyled config (#4438) 2019-12-11 23:06:17 -03:00
Omer Lachish
a3beac0b78 allow setting of custom sentry environments (#4437) 2019-12-11 23:00:06 +02:00
Arik Fraimovich
56d3be2248 Prettier all the Javascript code & GitHub Action (#4433)
* Prettier all the JS files

* Add GitHub Action to autoformat code pushed to master

* Fix eslint violation due to formatting.

* Remove GitHub actions for styling

* Add restyled.io config
2019-12-11 17:05:38 +02:00
Arik Fraimovich
81b14a58ef Remove Husky (#4435) 2019-12-11 14:49:57 +02:00
Arik Fraimovich
2dff8b9a00 Black support for the Python codebase (#4297)
* Apply black formatting

* Add auto formatting when committing to master

* Update CONTRIBUTING.md re. Black & Prettier
2019-12-11 13:54:29 +02:00
Arik Fraimovich
37a964c8d9 Remove codeclimate config (#4434) 2019-12-11 13:44:52 +02:00
Arik Fraimovich
1b9b3032ca Change eslint configuration and fix resulting issues (#4423)
* Remove app/service/query-string (unused) and its dependency.

* Fix usage of mixed operators.

* eslint --fix fixes for missing dependencies for react hooks

* Fix: useCallback dependency passed to $http's .catch.

* Satisfy react/no-direct-mutation-state.

* Fix no-mixed-operators violations.

* Move the decision of whether to render Custom chart one level up to make sure hooks are called in the same order.

* Fix: name was undefined. It wasn't detected before because there is such global.

* Simplify eslint config and switch to creat-react-app's eslint base.

* Add prettier config.

* Make sure eslint doesn't conflict with prettier

* A few updates post eslint (#4425)

* Prettier command in package.json
2019-12-11 12:00:46 +02:00
David Mudro
0385b6fb64 Fix counter vizualization (#4385)
* crude unit tests for counter visualisation utils

* improve type safety with default param values for getCounterData()

* fix count rows never shows zero

* remove default values for getCounterData() params
2019-12-10 13:38:22 +02:00
Arik Fraimovich
7c05a730dc Remove --max-old-space-size=4096 from npm build command (#4381)
* Remove --max-old-space-size=4096 from build

Looks like it's no longer needed.

* Update to node v12.

* Add build:old-node-version for those who have Node < 12.
2019-12-05 22:41:57 +02:00
Kenji Ichihashi
263305214e Update rds-combined-ca-bundle.pem(#4290) (#4304)
Can use rds-ca-2019 and etc
`$ curl https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem \
> redash/query_runner/files/rds-combined-ca-bundle.pem`
2019-12-05 11:29:42 +02:00
Jakdaw
3494e21cf4 Add user/pass authentication support for Druid (#4315)
* Add support for configuring a Username/Password for the connection to Druid

* Bump pydruid version for username/password support

* Deal with missing/empty configuration parameters
2019-12-05 09:27:59 +02:00
Gabriel Dutra
15e8b88996 Cypress: Make sure params are saved before reload (#4420) 2019-12-04 13:37:31 -03:00
Levko Kravets
ba36b4e671 Migrate AddToDashboard dialog to React (#4408) 2019-12-04 17:50:50 +02:00
Levko Kravets
94bd03dc42 Set of improvements and refinements to visualizations after React migration (#4382) 2019-12-04 16:23:29 +02:00
Levko Kravets
041d05d18b Chart series switch places when picking Y axis or color (#4412) 2019-12-04 16:00:01 +02:00
Gabriel Dutra
c14e7ab4ca Fix dragged parameter wrapping in some cases (#4415) 2019-12-03 12:48:11 -03:00
Monica Gangwar
4d6c30ef13 refreshing snowflake schema w/o waking cluster (#4285)
* refreshing snowflake schema w/o waking cluster

Have also added a new internal method to not select a
warehouse while executing query
Using 'show columns' to fetch database schema instead of
executing a select query in information schema
show columns does not require a warehouse to run

* modularising snowflake code to avoid repetitions

fixing internal function syntax and avoiding
code repetition

* removing user object in snowflake schema query
2019-12-02 10:48:30 +02:00
Arik Fraimovich
36ab8eae89 Update Snowflake connector version to address compatibility issue with Azure dependencies (#4407) 2019-11-27 18:44:08 +02:00
Stefan Mees
e82373ac1d add pyexasol datasource, ensure that integer dont overflow in javascript (#4378) 2019-11-27 18:43:58 +02:00
Arik Fraimovich
d3feba69b2 Downgrade Kombu version to 4.6.3 (#4406)
It was accidentally upgraded as part of the dependencies upgrade we did recently, but 4.6.5 has a bug...
2019-11-27 18:08:47 +02:00
Omer Lachish
80f3ec1c99 avoid logging job parameters (#4311) 2019-11-27 09:33:20 +02:00
Arik Fraimovich
c612bba19c Amazon CloudWatch query runners (#4372)
* CloudWatch Metrics query runner

* Add: query runner for CloudWatch Logs Insights

* Add logos

* Update Insights type

* Basic test connection

* Format files
2019-11-27 09:14:28 +02:00
Nicolas Le Manchet
f5a40827aa Remove builtins invalid in Python 3 from Python runner (#4375)
These few builtins were available in Python 2.7 but not anymore
in Python 3, making the runner fail to start.
2019-11-27 09:12:36 +02:00
Gabriel Dutra
5de291a98d Fix Map spec and Alert Page snapshot flakyness (#4403) 2019-11-26 19:08:18 -03:00
Levko Kravets
c70a48db9c Table visualization with column named "children" renders +/- buttons (#4394) 2019-11-26 15:47:19 +02:00
Omer Lachish
be56035bd6 don't try to purge jobs which have already been deleted (#4396) 2019-11-25 11:04:00 +02:00
Gabriel Dutra
7c97d8eafa Add autoscroll to ng-view (#4337) 2019-11-24 14:01:35 -03:00
Gabriel Dutra
0563ecf648 Migrate Home to React (#4379) 2019-11-24 13:59:56 -03:00
Levko Kravets
e72d7a8cca Table visualization: accept timestamp for date/time columns (#4389) 2019-11-24 11:50:52 +02:00
Levko Kravets
a7a933946b Hide deprecated visualizations from query editor (#4388)
* Hide deprecated visualizations from query editor

* Fix Map tests
2019-11-24 11:05:01 +02:00
uncletimmy3
7cfd362a7a fix typo at unsupportedRedirect.js (#4387) 2019-11-24 10:46:16 +02:00
Arik Fraimovich
4d1b359713 Remove unused npm dependencies (#4380)
* Remove ui-ace.

* Remove ui-sortable.

* Remove angular-base64-upload.

* Remove angular-messages.

* Remove jquery-ui.

* Update package-lock.json.
2019-11-21 12:18:33 +02:00
Levko Kravets
818649bbec Migrate Chart visualization to React Part 2: Editor (#4139) 2019-11-20 21:57:12 +02:00
Levko Kravets
c6a2725f0a Migrate Map visualization to React (#4278) 2019-11-20 17:36:59 +02:00
Gabriel Dutra
5cd6913e40 Fix Cypress and Percy flakyness issues (#4365) 2019-11-18 10:37:01 -03:00
Gabriel Dutra
0aebb37317 Remove Chrome Logger and update Cypress and Percy (#4354) 2019-11-14 15:23:00 -03:00
Levko Kravets
aa06b32e17 Add some tests for Choropleth visualization (#4358) 2019-11-14 19:08:51 +02:00
Levko Kravets
b44fa51829 Migrate Funnel visualization to React (#4267)
* Migrate Funnel visualization to React: Editor

* Migrate Funnel visualization to React: Renderer

* Replace Auto sort options with Sort Column + Reverse Order

* Add option for items limit (instead of hard-coded value)

* Add number formatting options

* Replace d3.max with lodash.maxBy; fix bug in prepareData

* Add options for min/max percent values

* Debounce inputs

* Tests

* Refine Renderer: split components, use Ant Table for rendering, fix data handling

* Extract utility function to own file

* Fix tests

* Fix: sometimes after updating options, funnel shows "ghost" rows from previous dataset

* Sort by value column by default
2019-11-14 15:47:17 +02:00
Levko Kravets
1a95904ffd Migrate Choropleth visualization to React (#4313)
* Migrate Choropleth to React: skeleton

* Migrate Choropleth to React: Editor - skeleton

* Choropleth Editor: Bounds tab

* Choropleth Editor: Colors tab

* Choropleth Editor: Format tab

* Choropleth Editor: General tab

* Some refinements

* Migrate Choropleth to React: Renderer

* Refine code

* CR1
2019-11-14 15:42:15 +02:00
Omer Lachish
ef56e4e920 use to set the hash instead of directly manipulating it (#4351)
* use  to set the hash instead of directly manipulating it

* Update Jobs.jsx
2019-11-13 15:36:04 +02:00
shinsuke-nara
d5a3f0de57 CLI command to reencrypt data source options (#4190)
* Script to reencrypt data source options.

* Implement reencrypt sub command under database command.
2019-11-13 15:27:20 +02:00
Arik Fraimovich
cf274d96c8 Fix: number based alerts evaluation isn't working (#4295)
* Fix: correctly evaluate numeric thresholds

* Missing import

* More missing imports

* Alert evaluation: support for booleans
2019-11-13 15:11:21 +02:00
Levko Kravets
c00410768c Migrate Cohort visualization to React (#4270)
* Migrate Cohort to React: Editor

* Extract prepareData and getOptions to own files

* Refine CohortRenderer Angular component (js, less, prepareData) for easier migration

* Migrate Cohort to React: Renderer

* Migrate Cornelius to React: styles

* Migrate Cohort to React: Cornelius library

* Cornelius: add licence info; remove unused style

* Cornelius: use numeral to format numbers; revisit styles

* Cornelius: use moment to format date labels

* Cornelius: use chroma for cell backgrounds; update options; update proptypes; minor fixes

* Tidy up

* Tests
2019-11-13 14:39:08 +02:00
Jakdaw
dda5a9d58f Fix the DB migration so that the correct key is used for encrypting DS credentials. (#4344)
Without this upgrades from at least v5 (and earlier) won't work.
2019-11-11 21:49:05 +02:00
Omer Lachish
a0a32be3dd Admin status page's current tab does not preserve (#4299)
* handle a console warning about passing in string page options

* preserve selected tab in the location hash
2019-11-11 12:04:32 +02:00
Omer Lachish
e0e94d79ac Restarting rq-scheduler reschedules all periodics (#4302)
* add some logging to scheduler

* schedule jobs only if they are not already scheduled

* jobs scheduled with an interval over 24 hours were not repeated

* schedule version_check using standard scheduling

* clean up old jobs that are not part of the definition anymore

* add some tests

* add one more test to verify that reschedules are not done when not neccesary

* no need to check for func existence - all jobs have a func to run
2019-11-11 09:54:41 +02:00
Omer Lachish
f19d24287e auto-refresh data RQ jobs admin page (#4298) 2019-11-11 09:42:05 +02:00
Gabriel Dutra
80878abf7b Migrate Settings Screen to React (#4323)
* Migrate settings-screen to React

* Use black instead of blue color for active item

* Revert "Use black instead of blue color for active item"

This reverts commit 0e4ececa6a.

* Add selectable=false to the Menu
2019-11-10 09:07:40 +02:00
Gabriel Dutra
6716bb390c Update TagsList and Sidebar to use Ant components (#4338) 2019-11-07 13:41:15 -03:00
Omer Lachish
a33d11de3a RQ: periodically clear failed jobs (#4306)
* add some logging to scheduler

* clean failed RQ job data from Redis

* move stale job purging to tasks/general.py

* provide better documentation on why we don't reject keys in FailedJobRegistry at the moment

* pleasing the CodeClimate overlords

* simplified clenaup by deleting both job data and registry entry

* use FailedJobRegistry as source of truth for purging

* remove redundant key deletion

* Update redash/settings/__init__.py

Co-Authored-By: Arik Fraimovich <arik@arikfr.com>
2019-11-07 17:00:53 +02:00
Omer Lachish
6f791a092b Adjust RQ job priorities (#4301)
* prioritize periodic jobs

* declare default queues in inside worker()

* separate send_email to its own queue
2019-11-06 13:36:27 +02:00
Kyle Krueger
cce6546a62 Feature/last x days parameter (#4333)
* Add last 14, 30, 60, and 90 days to DRP.js

Date Range Parameter (DRP)

* Add last 14, 30, 60, and 60 day params to DRP.jsx

DateRangeParameters (DRP)
2019-11-05 16:15:11 +02:00
Ran Byron
5fd78fdb23 New feature - Alert muting (#4276)
* New feature - Alert muting

* pep8 fix

* Fixed backend api update

* whoops semicolon

* Implemented mute
2019-11-02 14:54:26 +02:00
Gabriel Dutra
74dbb8acf3 Skip favorites dropdown loading state on init (#4318) 2019-10-31 13:28:28 -03:00
Omer Lachish
36638be1dd optimize work horse initialization by configuration mappers on the worker process (#4314) 2019-10-30 09:53:06 +02:00
Gabriel Dutra
82f488d231 Migrate PermissionsEditor to React (#4266)
Co-Authored-By: Arik Fraimovich <arik@arikfr.com>
2019-10-29 12:42:31 -03:00
Arik Fraimovich
7b3943052e Move the setup scripts to their own home (#4310) 2019-10-28 21:11:21 +02:00
Arik Fraimovich
96a95b7090 Add V8 to the CHANGELOG. 2019-10-28 13:27:34 +02:00
Omer Lachish
accf0f7ac5 show more workers per page. also allow page size selection (#4300) 2019-10-28 09:51:57 +02:00
Arik Fraimovich
88ae639ee4 CircleCI workflow improvements (#4296)
* CircleCI workflow improvements

- Don't automatically build the Docker image.
- Make the Python lint step requirement for the follow up steps. When it fails it usually means there is a code error which will prevent the next steps anyway.

* Fix YAML syntax error.

* Add separate build Docker image step for master branch
2019-10-27 22:27:34 +02:00
Omer Lachish
ba413c210e use rq_redis_connection instead of redis_connection (#4288) 2019-10-25 14:23:24 +03:00
Levko Kravets
7157244eec Migrate Table visualization to React Part 2: Editor (#4175)
* Migrate table editor to React: skeleton, Grid tab

* Columns tab

* Cleanup

* Columns tab: DnD column sorting

* Columns types should be JSX

* New Columns tab UI/X

* Use Sortable component on Columns tab

* Tests: Grid Settings

* Tests: Columns Settings

* Tests: Editors for Text, Number, Boolean and Date/Time columns

* Tests: Editors for Image and Link columns

* Minor UI fix

* Trigger build

* Debounce inputs
2019-10-24 12:46:46 +03:00
Gabriel Dutra
9f7844640a Introduce inheritance to the Parameter structure (#4049)
* Start draft for new Parameter structure

* Add the rest of the methods

* EnumParameter

* QueryBasedDropdownParameter

* DateParameter

* DateRangeParameter

* Update Parameter usage on code

* Merge dynamicValue into normalizedValue

* Add updateLocals and omit unwanted props

* Allow null NumberParameter and omit parentQueryId

* Rename parameter getValue to getExecutionValue

* Update $$value to normalizedValue + omit on save

* Add a few comments

* Remove ngModel property from Parameter

* Use value directly in DateRangeParameter

* Use simpler separator for DateRange url param

* Add backward compatibility

* Use normalizeValue null value for isEmpty

* Start creating jest tests

* Add more tests

* Normalize null value for multi mode in Enum

* Use saved value for param isEmpty
2019-10-24 12:42:30 +03:00
Nicolas Le Manchet
246eca1121 Migrate the application to Python 3 (#4251)
* Make core app compatible with Python 3

No backward compatibility with Python 2.7 is kept.
This commit mostly contains changes made with 2to3 and manual
tweaking when necessary.

* Use Python 3.7 as base docker image

Since it is not possible to change redash/base:debian to Python 3
without breaking future relases, its Dockerfile is temporarly
copied here.

* Upgrade some requirements to newest versions

Some of the older versions were not compatible with Python 3.

* Migrate tests to Python 3

* Build frontend on Python 3

* Make the HMAC sign function compatible with Python 3

In Python 3, HMAC only works with bytes so the strings and the
float used in the sign function need to be encoded.
Hopefully this is still backward compatible with already generated
signatures.

* Use assertCountEqual instead of assertItemsEqual

The latter is not available in Python 3.
See https://bugs.python.org/issue17866

* Remove redundant encoding header for Python 3 modules

* Remove redundant string encoding in CLI

* Rename list() functions in CLI

These functions shadow the builtin list function which is
problematic since 2to3 adds a fair amount of calls to the builtin
list when it finds dict.keys() and dict.values().

Only the Python function is renamed, from the perspective of the
CLI nothing changes.

* Replace usage of Exception.message in CLI

`message` is not available anymore, instead use the string
representation of the exception.

* Adapt test handlers to Python 3

* Fix test that relied on dict ordering

* Make sure test results are always uploaded (#4215)

* Support encoding memoryview to JSON

psycopg2 returns `buffer` objects in Python 2.7 and `memoryview`
in Python 3. See #3156

* Fix test relying on object address ordering

* Decode bytes returned from Redis

* Stop using e.message for most exceptions

Exception.message is not available in Python 3 anymore, except
for some exceptions defined by third-party libraries.

* Fix writing XLSX files in Python 3

The buffer for the file should be made of bytes and the actual
content written to it strings.

Note: I do not know why the diff is so large as it's only a two
lines change. Probably a white space or file encoding issue.

* Fix test by comparing strings to strings

* Fix another exception message unavailable in Python 3

* Fix export to CSV in Python 3

The UnicodeWriter is not used anymore. In Python 3, the interface
provided by the CSV module only deals with strings, in and out.
The encoding of the output is left to the user, in our case
it is given to Flask via `make_response`.

* (Python 3) Use Redis' decode_responses=True option (#4232)

* Fix test_outdated_queries_works_scheduled_queries_tracker (use utcnow)

* Make sure Redis connection uses decoded_responses option

* Remove unused imports.

* Use Redis' decode_responses option

* Remove cases of explicit Redis decoding

* Rename helper function and make sure it doesn't apply twice.

* Don't add decode_responses to Celery Redis connection URL

* Fix displaying error while connecting to SQLite

The exception message is always a string in Python 3, so no
need to try to decode things.

* Fix another missing exception message

* Handle JSON encoding for datasources returning bytes

SimpleJSON assumes the bytes it receives contain text data, so it
tries to UTF-8 encode them. It is sometimes not true, for instance
the SQLite datasource returns bytes for BLOB types, which typically
do not contain text but truly binary data.

This commit disables SimpleJSON auto encoding of bytes to str and
instead uses the same method as for memoryviews: generating a
hex representation of the data.

* Fix Python 3 compatibility with RQ

* Revert some changes 2to3 tends to do (#4261)

- Revert some changes 2to3 tends to do when it errs on the side of caution regarding dict view objects.

- Also fixed some naming issues with one character variables in list comprehensions.

- Fix Flask warning.

* Upgrade dependencies

* Remove useless `iter` added by 2to3

* Fix get_next_path tests (#4280)

* Removed setting SERVER_NAME in tests setup to avoid a warning.

* Change get_next_path to not return empty string in case of a domain only value.

* Fix redirect tests:

Since version 0.15 of Werkzeug it uses full path for fixing the location header instead of the root path.

* Remove explicit dependency for Werkzeug

* Switched pytz and certifi to unbinded versions.

* Switch to new library for getting country from IP

`python-geoip-geolite2` is not compatible with Python 3, instead
use `maxminddb-geolite2` which is very similar as it includes
the geolite2 database in the package .

* Python 3 RQ modifications (#4281)

* show current worker job (alongside with minor cosmetic column tweaks)

* avoid loading entire job data for queued jobs

* track general RQ queues (default, periodic and schemas)

* get all active RQ queues

* call get_celery_queues in another place

* merge dicts the Python 3 way

* extend the result_ttl of refresh_queries to 600 seconds to allow it to continue running periodically even after longer executions

* Remove legacy Python flake8 tests
2019-10-24 12:42:13 +03:00
Arik Fraimovich
7ffb97232e Pin Cypress version (#4284) 2019-10-24 12:22:56 +03:00
Omer Lachish
8b9fa53efe extend the result_ttl of refresh_queries to 600 seconds to allow it to continue running periodically even after longer executions (#4283) 2019-10-24 11:56:07 +03:00
Omer Lachish
43b35b6fb4 Monitor general RQ queues (default, periodic and schemas) (#4256)
* track general RQ queues (default, periodic and schemas)

* get all active RQ queues

* call get_celery_queues in another place
2019-10-23 12:31:32 +03:00
Omer Lachish
f0f85ece42 avoid loading entire job data for queued jobs (#4257) 2019-10-23 11:43:31 +03:00
Omer Lachish
612833404b show current worker job (alongside with minor cosmetic column tweaks) (#4262) 2019-10-23 11:20:15 +03:00
Ran Byron
5d58503623 Minor alert bug fixes (#4274) 2019-10-22 16:58:20 +03:00
Ran Byron
3dfad87266 Extracted alert menu button (#4273) 2019-10-22 13:00:16 +03:00
Levko Kravets
0659ef1079 Add "use-debounce" dependency (#4268) 2019-10-19 22:28:57 +03:00
Ran Byron
a2e21dd1c3 App Header React migration (#4245) 2019-10-19 14:25:58 +03:00
Levko Kravets
f165cad9ff Migrate Sunburst Renderer to React (#4259) 2019-10-17 19:16:05 +03:00
Levko Kravets
e0a2705c1a Restore <body> bottom padding (#4252) 2019-10-17 13:22:09 +03:00
Levko Kravets
0aca649cb5 Migrate Sankey renderer to React (#4255) 2019-10-17 13:19:29 +03:00
Stefan Maric
79b37e8843 Fix double-scrollbar when in fullscreen (#4243) 2019-10-16 23:46:44 +03:00
Ran Byron
72bb5d29a0 Fix: Alert page breaks when target query returns null result (#4250)
* Fix: Alert page breaks when target query returns null result

* Better handling of topValue value
2019-10-16 11:27:37 +03:00
Omer Lachish
5a5fdecdde Replace Celery with RQ (except for execute_query tasks) (#4093)
* add rq and an rq_worker service

* add rq_scheduler and an rq_scheduler service

* move beat schedule to periodic_jobs queue

* move version checks to RQ

* move query result cleanup to RQ

* use timedelta and DRY up a bit

* move custom tasks to RQ

* do actual schema refreshes in rq

* rename 'period_jobs' to 'periodic', as it obviously holds jobs

* move send_email to rq

* DRY up enqueues

* ditch  and use a partially applied  decorator

* move subscribe to rq

* move check_alerts_for_query to rq

* move record_event to rq

* make tests play nicely with rq

* 👋 beat

* rename rq_scheduler to plain scheduler, now that there's no Celery scheduler entrypoint

* add some color to rq-worker's output

* add logging context to rq jobs (while keeping execute_query context via get_task_logger for now)

* move schedule to its own module

* cancel previously scheduled periodic jobs. not sure this is a good idea.

* rename redash.scheduler to redash.schedule

* allow custom dynamic jobs to be added decleratively

* add basic monitoring to rq queues

* add worker monitoring

* pleasing the CodeClimate overlords

* adjust cypress docker-compose.yml to include rq changes

* DRY up Cypress docker-compose

* add rq dependencies to cypress docker-compose service

* an odd attempt at watching docker-compose logs when running with Cypress

* Revert "an odd attempt at watching docker-compose logs when running with Cypress"

This reverts commit 016bd1a93e.

* show docker-compose logs at Cypress shutdown

* Revert "DRY up Cypress docker-compose"

This reverts commit 43abac7084.

* minimal version for binding is 3.2

* remove unneccesary code reloads on cypress

* add a  command which errors if any of the workers running inside the current machine haven't been active in the last minute

* SCHEMAS_REFRESH_QUEUE is no longer a required setting

* split tasks/queries.py to execution.py and maintenance.py

* fix tests after query execution split

* pleasing the CodeClimate overlords

* rename worker to celery_worker and rq_worker to worker

* use /rq_status instead of /jobs

* show started jobs' time ago according to UTC

* replace all spaces in column names

* fix query tests after execution split

* exit with an int

* general lint

* add an entrypoint for rq_healthcheck

* fix indentation

* delete all existing periodic jobs before scheduling them

* remove some unrequired requires

* move schedule example to redash.schedule

* add RQ integration to Sentry's setup

* pleasing the CodeClimate overlords

* remove replication settings from docker-compose - a proper way to scale using docker-compose would be the --scale CLI option, which will be described in the knowledge based

* revert to calling a function in dynamic settings to allow periodic jobs to be scheduled after app has been loaded

* don't need to depend on context when templating failure reports

* set the timeout_ttl to double the interval to avoid job results from expiring and having periodic jobs not reschedule

* whoops, bad merge

* describe custom jobs and don't actually schedule them

* fix merge
2019-10-15 23:59:22 +03:00
Omer Lachish
f6e1470a7c Avoid depending on app context when templating failure reports (#4231)
* don't need to depend on context when templating failure reports

* extract a render_template function with some docs

* CodeClimate has really outdone itself this time. Removed a whitespace character in order to fix 2 CodeClimate errors

* apparently whitespace doesn't count as a character
2019-10-15 23:08:28 +03:00
Arik Fraimovich
27cd76797e Make sure query results are consistent (#4246) 2019-10-15 21:48:44 +03:00
Amol Grover
29b113005c pagerduty.py: Change default summary text (#4239)
* pagerduty.py: Change default summary text

Change is made to use alert name in PagerDuty's alert
destination default summary text instead of
query id and name

* Update default description text & field description
2019-10-15 11:34:34 +03:00
Ran Byron
53d971bf87 Implemented new condition comparison options (#4240)
* Implemented new condition comparison options

* Fixed test

* Move backward compatibility code to service
2019-10-15 08:41:23 +03:00
Gabriel Dutra
a102e93e50 Fix dashboard parameter mapping issues (#4211) 2019-10-14 17:21:44 -03:00
Ran Byron
74beed80d2 Fixed hangouts chat icon (#4236) 2019-10-11 13:11:15 +03:00
Ran Byron
39f038f992 Fixed alert destination hrefs (#4235)
* Fixed alert destination hrefs

* Added query url
2019-10-11 13:10:47 +03:00
Gabriel Dutra
da2ed56281 Extend bolder markdown fix to widget description (#4229) 2019-10-10 09:53:58 -03:00
Arik Fraimovich
9d8812a598 Postgres: make sure table from the public schema doesn't get merged with table from other schemas (#4224)
* Postgres: make sure table from the public schema doesn't get merged with a table from another schema.

* PEP8 updates
2019-10-10 13:02:22 +03:00
Arik Fraimovich
204447a9f5 Add interface to abstract query result persistence (#4147)
* Add interface to implement custom persistence for QueryResult data

Co-authored-by: Omer Lachish <omer@rauchy.net>

* Deserialize query results data in the model

* Change order of mixins.

* Make DBPersistence.data setter in sycn with getter + tests
2019-10-10 10:39:55 +03:00
Arik Fraimovich
3b7efb8c1f Make sure that the default settings signal that no email server is configured (#4226)
* The sender email address has to be None for the test of "is email server
configured" to be correct. Moved the dev setting into docker-compose.yml.

* Move the REDASH_MAIL_SERVER setting into docker-compose.yml to revert the default value to its original value in case anyone was using it.

* Make worker dependant on email as it's the one that actually using it.
2019-10-07 22:23:22 +03:00
Ran Byron
69dc761c60 Alert page - migrate to React and redesign (#4153) 2019-10-07 19:15:06 +03:00
Ran Byron
2f42b8154c Fix: Misleading warning when trying to download results of unsaved query #4218 (#4219) 2019-10-06 16:00:24 +03:00
Arik Fraimovich
3f9d49dbd1 Remove debug code (#4216) 2019-10-06 11:57:05 +03:00
Justin Clift
0a5dca5d72 Adjust botocore dependency, so we don't need to update it as often (#4154) 2019-10-06 11:47:16 +03:00
Gabriel Dutra
8ea285dda9 Split setup in advanced and regular for data sources and destinations (#4160)
* DynamicForm support for advanced options

* Randomly select a few options to be advanced

* Merge conditions with the same logic

* Address some comments

* Update styling for the button

* Some style adjustments (#4162)

* Don't set default value to additional settings

* Rename advanced -> extra

* Show extra fields by default when they are filled

* Update hasFilledExtraField logic

* Add example field from destination as extra
2019-10-06 11:46:50 +03:00
Gabriel Dutra
569c325aa0 Support for dropdown of predefined options in data sources setup (#4161)
* Support for predefined options in data sources

* DynamicForm Select: title -> name

* Make it work with "enum" prop

* Make it work for "extendedEnum" prop

* Not JS

* Deep copy the configuration schema
2019-10-06 11:44:56 +03:00
Gabriel Dutra
d8a0af1a95 Fix query based dropdown not adding quote marks correctly (#4186)
* Handle non-array in multi-value QueryBasedParameter

* Use state value in QueryBasedParameterInput

* Normalize array in parameter structure

* Add Multi-selection test

* Remove unnecessary not null check
2019-10-06 11:35:47 +03:00
Ran Byron
648847df0b Fix: Multi-value Dropdown not available in Static Value edit dialog (#4213) 2019-10-05 17:52:50 +03:00
Arik Fraimovich
3f31bf3fc0 Fix: use correct variable name (#4210) 2019-10-03 13:00:21 +03:00
Rui Z
f6ad3d9d24 Vertica: prevent overwriting row data when duplicated column names exist (#4201)
* Vertica: prevent overwriting row data when duplicated column names exist

* remove enumeration
2019-10-02 12:20:51 +03:00
bennywij
e8ccdc23c7 Correct typo in log stmt. Add comment re PR 4201 (#4205) 2019-10-02 11:37:57 +03:00
Levko Kravets
a8af968d70 Sortable component (#4199) 2019-09-30 19:12:27 +03:00
Jesse
cb14459881 Fixes #3766. (#4189) 2019-09-27 11:00:50 +02:00
Gabriel Dutra
780fbceba5 Fix Pivot Visualization should not be saving data (#4174) 2019-09-25 11:36:39 -03:00
Omer Lachish
2c77c219c6 Add maildev to the dev stack (#4173)
* add maildev to the dev stack

* Update redash/settings/__init__.py

Co-Authored-By: Arik Fraimovich <arik@arikfr.com>
2019-09-25 10:50:34 +03:00
Gabriel Dutra
874e0d1ce3 Fix Execute Selected not working for dirty queries (#4176) 2019-09-24 10:59:40 -03:00
Gabriel Dutra
401d164622 Remove Widget dev console errors (#4177) 2019-09-24 07:39:03 -03:00
Arik Fraimovich
ff041b77cf Update Sentry-SDK (#4169) 2019-09-23 09:54:10 +03:00
Arik Fraimovich
b2d1636f8e Downgrade mysqlclient to 1.3.14 (#4165)
Closes #4164.
2019-09-22 14:56:09 +03:00
Arik Fraimovich
a3e8477410 List enabled Query Runner types during build (#4166)
* Add CLI command to list enabled query runner types
2019-09-22 14:55:21 +03:00
Omer Lachish
ed22b63f22 remove the annoying quoted title from EmptyState (#4168) 2019-09-22 14:33:19 +03:00
Arik Fraimovich
d636b29ba9 Update version (#4167) 2019-09-22 13:23:56 +03:00
Ran Byron
6173a2a619 Handle Create Dashboard with middle click (#4158) 2019-09-22 10:57:28 +03:00
Gabriel Dutra
fd435d2182 Migrate Pivot Table visualization to React (#4133)
* npm install react-pivottable

* Initiate Pivot Table Migration

* Update renderer with editor options

* Clean up

* Remove old pivottable from package.json

* Test Percy Snapshot with Pivot Table in a Dashboard

* Tmp: use cy.wait to make sure dashboard is loaded

* Clean up Percy snapshot test

* Small improvements
- cy.all with multiple args
- add controls to pivot valid options

* Watch for options in the Renderer
2019-09-22 10:46:03 +03:00
Gabriel Dutra
cb654b3f21 Migrate Widget component to React (#4020)
* Improve sizing for Number inputs

Co-Authored-By: Ran Byron <ranbena@gmail.com>

* Migrate WidgetDialog

* Start migrating Widget

* Update textbox to use HtmlContent

* QueryLink migration and some updates

* Add visualization rendering

* Render widget

* Add delete button

* Update AutoHeight

* Add widget bottom

* Add Drodpown button

* Split Widget component

* Update with #4056 and trigger netlify

* In progress: use composition

* Add header and footer

* Update widget actions positioning

* Re-render when refreshing from widget

* Add workaround to force DashboardGrid re-render

* VisualizationWidgetFooter component

* VisualizationWidget menu

* Separate RestrictedWidget

* Update tests

* Update margin for Parameters

* Remove widget files

* Revert "Improve sizing for Number inputs"

This reverts commit a02ce8f0aa.

* Some cleanup

* Move refresh logic to the Dashboard

* Add loadingWidgets logic to the public dashboard

* Add onLoadWidget

* Remove parameter from URL when empty

* Recreate widget array instead of loadingWidgets

* Add comment about re-rendering + whitespace missing

* CR changes

* Use plain html instead of string syntax

Co-Authored-By: Ran Byron <ranbena@gmail.com>
2019-09-20 22:08:42 +03:00
Arik Fraimovich
e8d40bbdac CHANGELOG for v8.0.0-beta.2 (#4145)
* Stop building tarballs.

* Update version reference.

* CHANGELOG for 8.0.0-beta.2
2019-09-18 11:23:32 +03:00
Levko Kravets
e5d52055d9 Widget filters overlapped by visualization (#4137)
* Fix: widget filters overlapped by visualization

* Fix tests

* Fix tests
2019-09-18 11:22:26 +03:00
Levko Kravets
c5e414e6ba Color picker component (#4136) 2019-09-16 13:01:48 +03:00
Gabriel Dutra
b9a40d1808 Query Snippets: Use onClick instead of link for 'Click here' option (#4144)
* Snippets: Don't change url when not needed

* Revert "Snippets: Don't change url when not needed"

This reverts commit 2f346f3bb4.

* Query Snippets: use onClick instead of link
2019-09-16 10:00:23 +03:00
Ran Byron
033dd0d15e Bug fix: Query view doesn't sync parameters when selecting and deleting (#4146) 2019-09-16 07:15:38 +03:00
Arik Fraimovich
95795d93c7 CHANGELOG for V8-beta. (#4057)
* CHANGELOG for V8-beta.

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md
2019-09-15 15:48:59 +03:00
Arik Fraimovich
75e48b0bd6 Allow users to share aggregated usage information with us (#4108)
* Initial commit of BeaconConsent component

* Add comment about being able to change setting

* Use <Text> correctly

* Final version of consent screen

* Show beacon consent message on homepage only if it wasn't enabled already.

* Add consent setting to organization settings screen.

* Add support for custom message in OrgSetting.save.

* Implmenet consent saving.

* If consent given, send extra data

* Add HelpTrigger

* Make CodeClimate happy

* Wrap everything with DynamicComponent
2019-09-15 15:18:48 +03:00
Levko Kravets
75883a1a02 Counter Editor: move components to own files (#4138) 2019-09-13 22:35:19 +03:00
Gabriel Dutra
75a5546741 Add jsconfig settings with '@' webpack alias (#4135) 2019-09-12 18:25:40 -03:00
Levko Kravets
54071e4b87 Migrate Chart visualization to React Part 1: Renderer (#4130)
* Migrate Chart visualization: Renderer

* Refine PlotlyChart component; move stylesheets to visualization's folder

* Migrate Custom JS Chart to React

* Cleanup
2019-09-12 10:23:43 +03:00
Arik Fraimovich
6458a1eb62 Remove duplicate messages method (#4131) 2019-09-11 11:56:40 +03:00
Levko Kravets
ecf160c9bc Alerts: Add more condition comparison options (#4134)
* getredash/redash#4132 Add more condition comparison options

* Add arguments to fallback lambda
2019-09-11 11:18:59 +03:00
Levko Kravets
2c98f0425d Allow the user to decide how to handle null values in charts (#4071)
* getredash/redash#2629 Refactor Chart visualization, add option for handling NULL values (keep/convert to 0.0)

* Handle null values in line/area stacking code; some cleanup

* Handle edge case: line/area stacking when last value of one of series is missing

* Mjnor update to line/area stacking code

* Fix line/area normalize to percents feature

* Unit tests

* Refine tests; add tests for prepareLayout function

* Tests for prepareData (heatmap) function

* Tests for prepareData (pie) function

* Tests for prepareData (bar, line, area) function

* Tests for prepareData (scatter, bubble) function

* Tests for prepareData (box) function

* Remove unused file
2019-09-09 13:00:26 +03:00
Ran Byron
8f01988c8c Decrease size of widget pagination (#4120)
* Added tests

* Perhaps this would trigger percy

* Decrease size of widget pagination

* Removed unused attr

* Updated tests
2019-09-09 10:57:26 +03:00
Arik Fraimovich
b8741f6cff Sync botocor eversions across requirements files. (#4128) 2019-09-09 10:44:05 +03:00
Levko Kravets
424751d9e9 Migrate Counter visualization to React (#4106)
* Migrate Counter to React: Renderer

* Migrate Counter to React: Editor

* Cleanup

* Review and fix rows indexing algorithm

* Counter not properly scaled in editor

* Fix wrong label for/input id pair

* Tests

* Tests

* Fix vendor prefixes

* Remove unnecessary useEffect dependencies

* Update tests

* Fix Percy snapshot names
2019-09-09 10:10:10 +03:00
Arik Fraimovich
e048a69392 Upgrade Sentry-SDK and enable additional integratoins (#4127)
* Update sentry-sdk version

* Add additional Sentry integrations
2019-09-09 10:00:09 +03:00
Ran Byron
2c1e846837 Widget table scroll-x visible (#4101)
* Table viz horizontal scroll made visible

* Added tests

* Fixed snapshot pre-condition

* Perhaps this would trigger percy
2019-09-09 09:50:03 +03:00
Justin Clift
4b9e26de5a Update botocore, to get pass pip warning (#4122) 2019-09-04 09:12:22 +03:00
sphenlee
17f50192e7 hive_ds: show a user friendly error message when possible (#4121) 2019-09-04 08:10:56 +03:00
Gabriel Dutra
dcdec0abb5 Use ng-src for data source icons (#4123) 2019-09-03 20:42:19 +03:00
Ran Byron
302c6dd02e Fix number param value normlization (#4116) 2019-09-02 16:29:56 +03:00
Arik Fraimovich
4c56900248 Move annotation logic into Query Runner (#4113)
* Code formatting

* Move annotation logic into query runner, so it can be overriden in the query runner.

* Add mixin to __all__

* Switch to flag instead of mixin

* Feature (Redshift): option to set query group for adhoc/scheduled queries  (#4114)

* Add scheduled status to query job metadata.

* Add: option to set query group for adhoc/scheduled Redshift queries

* Scheduled might not be set for already enqueued queries.
2019-09-02 16:01:05 +03:00
swfz
1f1f853297 Display data source icon in query editor (#4119) 2019-09-02 14:42:41 +03:00
Arik Fraimovich
43f63b1b57 Add ability to use Ant's Table loading property when using ItemsTable (#4117) 2019-09-02 14:38:28 +03:00
Gabriel Dutra
5ae80835b1 Fix Dropdown parameter options appearing behind Dialog (#4109) 2019-09-01 21:55:37 -03:00
Arik Fraimovich
df3da82afd Fix: allow users with view only acces to use the queries in Query Results (#4112)
* Fix: allow users with view only acces to access the queries

* Add tests

* Update error message

* Update error message. Take 2
2019-09-01 22:17:53 +03:00
Ran Byron
98e33b7780 Fix widget bottom element alignment (#4110) 2019-09-01 16:59:11 +03:00
Omer Lachish
8a3f6f90eb Update badge in README.md to link to CircleCI (#4104)
* Update README.md

* Update README.md

* Update README.md

Co-Authored-By: Ran Byron <ranbena@gmail.com>

* Update README.md
2019-09-01 10:50:14 +03:00
shinsuke-nara
cab011def9 Migrate with SQL statements. (#4105) 2019-08-30 14:08:22 +03:00
Omer Lachish
31c888ea8e Dashboard: when updating parameters, run only relevant queries (#3804)
* refresh only affected queries in dashboard when parameters are changed

* rename pendingParameters to updatedParameters

* select which widgets to update according to their mapping as a dashboard-level parameter

* use lodash's include
2019-08-30 07:03:51 +03:00
Sandeep Belagavi
443054428f [Qubole] - Adding support to process Quantum query types. (#4066)
* [Qubole] - Adding support to process Quantum query types.

Quantum is a serverless interactive service that offers
direct SQL access to user's data lake. Changes are made
to accept `quantum` query type from user which makes
`Cluster Label` as optional.

* -Making quantum as defult query.
-Dictionary safe access to connection parmeters

* keeping pep8 standards

* Maintainig pep8 std

* Use latest version of qds-sdk

* Use qds-sdk v1.13.0

* Use qds-sdk v1.12.0

* Use qds-sdk v1.13.0

* Updating SDK with verified version

* hive as default query type

* qds-sdk : Locking most recent release version

* qds-sdk : Locking recent release version

* falling back to original version of qds-sdk
2019-08-29 19:22:52 +03:00
Gleb Lesnikov
ef9a4d5eed [Data Sources] Add: Azure Data Explorer (Kusto) query runner (#4091)
* [Data Sources] Add: Azure Data Explorer (Kusto) query runner

* CodeClimate fixes

* Remove TODO

* Fixed configuration properties names for Azure Kusto

* Azure Kusto: get_schema in one query

* azure-kusto-data update to 0.0.32

* Add Kusto to the default query runners list
2019-08-26 10:17:49 +03:00
Arik Fraimovich
a2b68a3569 Make sure we always pass a list to _get_column_lists (#4095)
(some data sources might return None as the columns list)
2019-08-25 17:39:15 +03:00
Ran Byron
e7b707eb25 Removed redash-newstyle.less (#4017) 2019-08-22 08:06:54 +03:00
Arik Fraimovich
1786273344 Fix: MySQL connections without SSL are failing (#4090)
* Move connection logic into a single method & make sure not to pass ssl value if not used.

* Remove wildcard import and format file.
2019-08-21 14:31:17 +03:00
Christian Clauss
d38ca803c5 Add more flake8 tests and fail build if any test fails (#4055)
* Add more flake8 tests and fail build if any test fails

Run all flake8 E9xx + F63x + F7xx + F82x tests.

* long = long in Python 2
2019-08-18 11:27:44 +03:00
Gabriel Dutra
a1f11cb8d9 Migrate Parameters component to React (#4006)
* Start Parameters Migration

* Add dirtyCount

* Use workaround with setState

* Apply Changes

* Add EditSettingsDialog

* Add Cmd/Ctrl + Enter behavior

* Remove isApplying

* Delete Angular version of parameters

* Update tests

* Remove angular stuff

* Update jest

* Drag placeholder

* Update events

* Use old button styling and move css

* Reviewing code

* Add parameter rearrange test

* Add Parameter Settings title change test

* Update Parameter Settings button styling

* Move parameter url logic back to Parameters

* Disable url update when query is new

* Styling changes (#4019)

* Ran's title width styling

* Update drag test

* Improve sizing for Number inputs

Co-Authored-By: Ran Byron <ranbena@gmail.com>

* Fix issue with dragged parameter wrapping

Co-Authored-By: Ran Byron <ranbena@gmail.com>

* Don't reevaluate dirtyParamCount

* Allow multiple values :)

* Fix parameter alignments

* Fix Select width on search

* Update client/app/components/Parameters.less

Co-Authored-By: Ran Byron <ranbena@gmail.com>

* Humanize param.name

* Make sure angular updates Execute disabled status
2019-08-18 11:27:20 +03:00
1176 changed files with 93748 additions and 43353 deletions

View File

@@ -1,12 +1,12 @@
FROM cypress/browsers:chrome67 FROM cypress/browsers:node14.0.0-chrome84
ENV APP /usr/src/app ENV APP /usr/src/app
WORKDIR $APP WORKDIR $APP
COPY package.json $APP/package.json COPY package.json package-lock.json $APP/
RUN npm run cypress:install > /dev/null COPY viz-lib $APP/viz-lib
RUN npm ci > /dev/null
COPY client/cypress $APP/client/cypress COPY . $APP
COPY cypress.json $APP/cypress.json
RUN ./node_modules/.bin/cypress verify RUN ./node_modules/.bin/cypress verify

View File

@@ -1,18 +1,25 @@
version: 2.0 version: 2.0
flake8-steps: &steps build-docker-image-job: &build-docker-image-job
- checkout docker:
- run: sudo pip install flake8 - image: circleci/node:12
- run: ./bin/flake8_tests.sh steps:
- setup_remote_docker
- checkout
- run: sudo apt update
- run: sudo apt install python3-pip
- run: sudo pip3 install -r requirements_bundles.txt
- run: .circleci/update_version
- run: npm run bundle
- run: .circleci/docker_build
jobs: jobs:
python-flake8-tests: backend-lint:
docker: docker:
- image: circleci/python:3.7.0 - image: circleci/python:3.7.0
steps: *steps steps:
legacy-python-flake8-tests: - checkout
docker: - run: sudo pip install flake8
- image: circleci/python:2.7.15 - run: ./bin/flake8_tests.sh
steps: *steps
backend-unit-tests: backend-unit-tests:
environment: environment:
COMPOSE_FILE: .circleci/docker-compose.circle.yml COMPOSE_FILE: .circleci/docker-compose.circle.yml
@@ -26,12 +33,15 @@ jobs:
name: Build Docker Images name: Build Docker Images
command: | command: |
set -x set -x
docker-compose build --build-arg skip_ds_deps=true docker-compose build --build-arg skip_ds_deps=true --build-arg skip_frontend_build=true
docker-compose up -d docker-compose up -d
sleep 10 sleep 10
- run: - run:
name: Create Test Database name: Create Test Database
command: docker-compose run --rm postgres psql -h postgres -U postgres -c "create database tests;" command: docker-compose run --rm postgres psql -h postgres -U postgres -c "create database tests;"
- run:
name: List Enabled Query Runners
command: docker-compose run --rm redash manage ds list_types
- run: - run:
name: Run Tests name: Run Tests
command: docker-compose run --name tests redash tests --junitxml=junit.xml --cov-report xml --cov=redash --cov-config .coveragerc tests/ command: docker-compose run --name tests redash tests --junitxml=junit.xml --cov-report xml --cov=redash --cov-config .coveragerc tests/
@@ -41,30 +51,43 @@ jobs:
mkdir -p /tmp/test-results/unit-tests mkdir -p /tmp/test-results/unit-tests
docker cp tests:/app/coverage.xml ./coverage.xml docker cp tests:/app/coverage.xml ./coverage.xml
docker cp tests:/app/junit.xml /tmp/test-results/unit-tests/results.xml docker cp tests:/app/junit.xml /tmp/test-results/unit-tests/results.xml
when: always
- store_test_results: - store_test_results:
path: /tmp/test-results path: /tmp/test-results
- store_artifacts: - store_artifacts:
path: coverage.xml path: coverage.xml
frontend-lint: frontend-lint:
environment:
CYPRESS_INSTALL_BINARY: 0
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
docker: docker:
- image: circleci/node:8 - image: circleci/node:12
steps: steps:
- checkout - checkout
- run: mkdir -p /tmp/test-results/eslint - run: mkdir -p /tmp/test-results/eslint
- run: npm install - run: npm ci
- run: npm run lint:ci - run: npm run lint:ci
- store_test_results: - store_test_results:
path: /tmp/test-results path: /tmp/test-results
frontend-unit-tests: frontend-unit-tests:
environment:
CYPRESS_INSTALL_BINARY: 0
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
docker: docker:
- image: circleci/node:8 - image: circleci/node:12
steps: steps:
- checkout - checkout
- run: sudo apt install python-pip - run: sudo apt update
- run: sudo pip install -r requirements_bundles.txt - run: sudo apt install python3-pip
- run: npm install - run: sudo pip3 install -r requirements_bundles.txt
- run: npm ci
- run: npm run bundle - run: npm run bundle
- run: npm test - run:
name: Run App Tests
command: npm test
- run:
name: Run Visualizations Tests
command: (cd viz-lib && npm test)
- run: npm run lint - run: npm run lint
frontend-e2e-tests: frontend-e2e-tests:
environment: environment:
@@ -73,64 +96,64 @@ jobs:
PERCY_TOKEN_ENCODED: ZGRiY2ZmZDQ0OTdjMzM5ZWE0ZGQzNTZiOWNkMDRjOTk4Zjg0ZjMxMWRmMDZiM2RjOTYxNDZhOGExMjI4ZDE3MA== PERCY_TOKEN_ENCODED: ZGRiY2ZmZDQ0OTdjMzM5ZWE0ZGQzNTZiOWNkMDRjOTk4Zjg0ZjMxMWRmMDZiM2RjOTYxNDZhOGExMjI4ZDE3MA==
CYPRESS_PROJECT_ID_ENCODED: OTI0Y2th CYPRESS_PROJECT_ID_ENCODED: OTI0Y2th
CYPRESS_RECORD_KEY_ENCODED: YzA1OTIxMTUtYTA1Yy00NzQ2LWEyMDMtZmZjMDgwZGI2ODgx CYPRESS_RECORD_KEY_ENCODED: YzA1OTIxMTUtYTA1Yy00NzQ2LWEyMDMtZmZjMDgwZGI2ODgx
CYPRESS_INSTALL_BINARY: 0
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
docker: docker:
- image: circleci/node:8 - image: circleci/node:12
steps: steps:
- setup_remote_docker - setup_remote_docker
- checkout - checkout
- run:
name: Enable Code Coverage report for master branch
command: |
if [ "$CIRCLE_BRANCH" = "master" ]; then
echo 'export CODE_COVERAGE=true' >> $BASH_ENV
source $BASH_ENV
fi
- run: - run:
name: Install npm dependencies name: Install npm dependencies
command: | command: |
npm install npm ci
- run: - run:
name: Setup Redash server name: Setup Redash server
command: | command: |
npm run cypress start npm run cypress build
npm run cypress start -- --skip-db-seed
docker-compose run cypress npm run cypress db-seed docker-compose run cypress npm run cypress db-seed
- run: - run:
name: Execute Cypress tests name: Execute Cypress tests
command: npm run cypress run-ci command: npm run cypress run-ci
build-tarball: - run:
docker: name: "Failure: output container logs to console"
- image: circleci/node:8 command: |
steps: docker-compose logs
- checkout when: on_fail
- run: sudo apt install python-pip - run:
- run: sudo pip install -r requirements_bundles.txt name: Copy Code Coverage results
- run: npm install command: |
- run: .circleci/update_version docker cp cypress:/usr/src/app/coverage ./coverage || true
- run: npm run bundle when: always
- run: npm run build
- run: rm -rf ./node_modules/
- run: .circleci/pack
- store_artifacts: - store_artifacts:
path: /tmp/artifacts/ path: coverage
build-docker-image: build-docker-image: *build-docker-image-job
docker: build-preview-docker-image: *build-docker-image-job
- image: circleci/node:8
steps:
- setup_remote_docker
- checkout
- run: sudo apt install python-pip
- run: sudo pip install -r requirements_bundles.txt
- run: .circleci/update_version
- run: npm run bundle
- run: .circleci/docker_build
workflows: workflows:
version: 2 version: 2
build: build:
jobs: jobs:
- python-flake8-tests - backend-lint
- legacy-python-flake8-tests - backend-unit-tests:
- backend-unit-tests requires:
- backend-lint
- frontend-lint - frontend-lint
- frontend-unit-tests: - frontend-unit-tests:
requires: requires:
- backend-lint
- frontend-lint - frontend-lint
- frontend-e2e-tests: - frontend-e2e-tests:
requires: requires:
- frontend-lint - frontend-lint
- build-tarball: - build-preview-docker-image:
requires: requires:
- backend-unit-tests - backend-unit-tests
- frontend-unit-tests - frontend-unit-tests
@@ -139,15 +162,16 @@ workflows:
branches: branches:
only: only:
- master - master
- hold:
type: approval
requires:
- backend-unit-tests
- frontend-unit-tests
- frontend-e2e-tests
filters:
branches:
only:
- /release\/.*/ - /release\/.*/
- build-docker-image: - build-docker-image:
requires: requires:
- backend-unit-tests - hold
- frontend-unit-tests
- frontend-e2e-tests
filters:
branches:
only:
- master
- preview-image
- /release\/.*/

View File

@@ -1,4 +1,4 @@
version: '3' version: '2.2'
services: services:
redash: redash:
build: ../ build: ../

View File

@@ -1,45 +1,62 @@
version: '3' version: "2.2"
x-redash-service: &redash-service
build:
context: ../
args:
skip_dev_deps: "true"
skip_ds_deps: "true"
code_coverage: ${CODE_COVERAGE}
x-redash-environment: &redash-environment
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
REDASH_RATELIMIT_ENABLED: "false"
REDASH_ENFORCE_CSRF: "true"
services: services:
server: server:
build: ../ <<: *redash-service
command: dev_server command: server
depends_on: depends_on:
- postgres - postgres
- redis - redis
ports: ports:
- "5000:5000" - "5000:5000"
environment: environment:
<<: *redash-environment
PYTHONUNBUFFERED: 0 PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO" scheduler:
REDASH_REDIS_URL: "redis://redis:6379/0" <<: *redash-service
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
REDASH_RATELIMIT_ENABLED: "false"
worker:
build: ../
command: scheduler command: scheduler
depends_on: depends_on:
- server - server
environment: environment:
<<: *redash-environment
worker:
<<: *redash-service
command: worker
depends_on:
- server
environment:
<<: *redash-environment
PYTHONUNBUFFERED: 0 PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
QUEUES: "queries,scheduled_queries,celery,schemas"
WORKERS_COUNT: 2
cypress: cypress:
ipc: host
build: build:
context: ../ context: ../
dockerfile: .circleci/Dockerfile.cypress dockerfile: .circleci/Dockerfile.cypress
depends_on: depends_on:
- server - server
- worker - worker
- scheduler
environment: environment:
CYPRESS_baseUrl: "http://server:5000" CYPRESS_baseUrl: "http://server:5000"
CYPRESS_coverage: ${CODE_COVERAGE}
PERCY_TOKEN: ${PERCY_TOKEN} PERCY_TOKEN: ${PERCY_TOKEN}
PERCY_BRANCH: ${CIRCLE_BRANCH} PERCY_BRANCH: ${CIRCLE_BRANCH}
PERCY_COMMIT: ${CIRCLE_SHA1} PERCY_COMMIT: ${CIRCLE_SHA1}
PERCY_PULL_REQUEST: ${CIRCLE_PR_NUMBER} PERCY_PULL_REQUEST: ${CIRCLE_PR_NUMBER}
COMMIT_INFO_BRANCH: ${CIRCLE_BRANCH} COMMIT_INFO_BRANCH: ${CIRCLE_BRANCH}
COMMIT_INFO_MESSAGE: ${COMMIT_INFO_MESSAGE}
COMMIT_INFO_AUTHOR: ${CIRCLE_USERNAME} COMMIT_INFO_AUTHOR: ${CIRCLE_USERNAME}
COMMIT_INFO_SHA: ${CIRCLE_SHA1} COMMIT_INFO_SHA: ${CIRCLE_SHA1}
COMMIT_INFO_REMOTE: ${CIRCLE_REPOSITORY_URL} COMMIT_INFO_REMOTE: ${CIRCLE_REPOSITORY_URL}

View File

@@ -6,11 +6,11 @@ docker login -u $DOCKER_USER -p $DOCKER_PASS
if [ $CIRCLE_BRANCH = master ] || [ $CIRCLE_BRANCH = preview-image ] if [ $CIRCLE_BRANCH = master ] || [ $CIRCLE_BRANCH = preview-image ]
then then
docker build -t redash/redash:preview -t redash/preview:$VERSION_TAG . docker build --build-arg skip_dev_deps=true -t redash/redash:preview -t redash/preview:$VERSION_TAG .
docker push redash/redash:preview docker push redash/redash:preview
docker push redash/preview:$VERSION_TAG docker push redash/preview:$VERSION_TAG
else else
docker build -t redash/redash:$VERSION_TAG . docker build --build-arg skip_dev_deps=true -t redash/redash:$VERSION_TAG .
docker push redash/redash:$VERSION_TAG docker push redash/redash:$VERSION_TAG
fi fi

View File

@@ -1,32 +0,0 @@
version: "2"
checks:
complex-logic:
enabled: false
file-lines:
enabled: false
method-complexity:
enabled: false
method-count:
enabled: false
method-lines:
config:
threshold: 100
nested-control-flow:
enabled: false
identical-code:
enabled: false
similar-code:
enabled: false
plugins:
pep8:
enabled: true
eslint:
enabled: false
exclude_patterns:
- "tests/**/*.py"
- "migrations/**/*.py"
- "setup/**/*"
- "bin/**/*"
- "**/node_modules/"
- "client/dist/"
- "**/*.pyc"

View File

@@ -1,6 +1,7 @@
client/.tmp/ client/.tmp/
client/dist/ client/dist/
node_modules/ node_modules/
viz-lib/node_modules/
.tmp/ .tmp/
.venv/ .venv/
venv/ venv/

3
.gitignore vendored
View File

@@ -5,11 +5,12 @@ venv/
.coveralls.yml .coveralls.yml
.idea .idea
*.pyc *.pyc
.nyc_output
coverage
.coverage .coverage
coverage.xml coverage.xml
client/dist client/dist
.DS_Store .DS_Store
celerybeat-schedule*
.#* .#*
\#*# \#*#
*~ *~

63
.restyled.yaml Normal file
View File

@@ -0,0 +1,63 @@
enabled: true
auto: false
# Open Restyle PRs?
pull_requests: true
# Leave comments on the original PR linking to the Restyle PR?
comments: true
# Set commit statuses on the original PR?
statuses:
# Red status in the case of differences found
differences: true
# Green status in the case of no differences found
no_differences: true
# Red status if we encounter errors restyling
error: true
# Request review on the Restyle PR?
#
# Possible values:
#
# author: From the author of the original PR
# owner: From the owner of the repository
# none: Don't
#
# One value will apply to both origin and forked PRs, but you can also specify
# separate values.
#
# request_review:
# origin: author
# forked: owner
#
request_review: author
# Add labels to any created Restyle PRs
#
# These can be used to tell other automation to avoid our PRs.
#
labels: ["Skip CI"]
# Labels to ignore
#
# PRs with any of these labels will be ignored by Restyled.
#
# ignore_labels:
# - restyled-ignore
# Restylers to run, and how
restylers:
- name: black
image: restyled/restyler-black:v19.10b0
include:
- redash
- tests
- migrations/versions
- name: prettier
image: restyled/restyler-prettier:v1.19.1-2
include:
- client/app/**/*.js
- client/app/**/*.jsx
- client/cypress/**/*.js

View File

@@ -1,5 +1,265 @@
# Change Log # Change Log
## v9.0.0-beta - 2020-06-11
This release was long time in the making and has several major changes:
- Our backend code was updated to support Python 3 and we no longer support Python 2. If you're using our Docker images, this should be a transparent change for you.
- We replaced Celery with RQ for background jobs processing. This will require some setup updates -- see instructions below.
- The frontend code is now 100% React and we removed all the Angular dependencies.
This release was made possible by contributions from over 50 people: @ari-e, @ariarijp, @arihantsurana, @arikfr, @atharvai, @cemremengu, @chulucninh09, @citrin, @daniellangnet, @DavidHernandez, @deecay, @dmudro, @erans, @erels, @ezkl, @gabrieldutra, @gstaykov, @ialeinikov, @ikenji, @Jakdaw, @jezdez, @juanvasquezreyes, @koooge, @kravets-levko, @kykrueger, @leibowitz, @leosunmo, @lihan, @loganprice, @mickeey2525, @mnoorenberghe, @monicagangwar, @NicolasLM, @p-yang, @Ralnoc, @ranbena, @randyzwitch, @rauchy, @rxin, @saravananselvamohan, @satyamkrishna, @shinsuke-nara, @stefan-mees, @stevebuckingham, @susodapop, @taminif, @thewarpaint, @tsuyoshizawa, @uncletimmy3, @wengkham.
### Upgrading
Typically, if you are running your own instance of Redash and wish to upgrade, you would simply modify the Docker tag in your `docker-compose.yml` file. Since RQ has replaced Celery in this version, there are a couple extra modifications that need to be done in your `docker-compose.yml`:
1. Under `services/scheduler/environment`, omit `QUEUES` and `WORKERS_COUNT` (and omit `environment` altogether if it is empty).
2. Under `services`, add a new service for general RQ jobs:
```yaml
worker:
<<: *redash-service
command: worker
environment:
QUEUES: "periodic emails default"
WORKERS_COUNT: 1
```
Following that, force a recreation of your containers with `docker-compose up --force-recreate --build` and you should be good to go.
### UX
- Redesigned Query Results page:
- Completely new layout is easier to read for non-technical Redash users.
- Empty query results are clearly displayed. User is now prompted to edit or execute the query.
- Mobile Experience Improvements:
- UI element spacing has been redesigned for clarity
- Admin pages now honor max-width. Tables scroll independent of the top menu.
- Large legends no longer shrink the visualization on small screens.
- Fix: it was sometimes impossible to scroll pages with dashboards because the visualizations captured every touch event.
- Fix: Visualizations on small screens would not always show horizontal scroll bars.
- Dashboards can now be un-archived using the API.
- Dashboard UI performance was improved.
- List pages were changed to show a user's name instead of avatar.
- Search-enabled tables now show a prompt for which columns will be searched.
- In the visualization editor, the settings pane now scrolls independent of the visualization preview.
- Tokens in the schema viewer now sort alphabetically.
- Links to settings panes that require Admin privileges are now hidden from non-Admins.
- The Admin page now remembers which tab you were viewing after a page reload.
### Visualizations
- Feature: Allow bubble size control with either coefficient or sizemode.
- Feature: Table visualization now treats Unix timestamps in query results as timestamps.
- Feature: It's now possible to provide a description to each Table column, appearing in UI as a tooltip.
- Feature: Added tooltip and popover templating to the map with markers visualization.
- Feature: Added an organization setting to hide the Plotly mode bar on all visualizations.
- Feature: Cohort visualization now has appearance settings.
- Feature: Add option to explicitly set Chart legend position.
- Change: Deprecated visualizations are now hidden.
- Change: Table settings editor now extends vertically instead of horizontally.
- Change: The maximum table pagination is now 500.
- Change: Pie chart labels maintain contrast against lighter slices.
- Fix: Chart series switched places when picking Y axis.
- Fix: Third column was not selectable for Bubble and Heatmap charts.
- Fix: On the counter visualizations, the “count rows” option showed an empty string instead of 0.
- Fix: Table visualization with column named "children" rendered +/- buttons.
- Fix: Sankey visualization now correctly occupies all available area even with fewer stages.
- Fix: Pie chart ignores series labels.
### Data Sources
- New Data Sources: Amazon Cloudwatch, Amazon CloudWatch Logs Insights, Azure Kusto, Exasol.
- Athena:
- Added the option to specify a base cost in settings, displaying a price for each query when executed.
- BigQuery:
- Fix: large jobs continued running after the user clicked “Cancel” query execution.
- Cassandra:
- Updated driver to 3.21.0 which dramatically reduces Docker build times.
- SSL options are now available.
- Clickhouse:
- You can now choose whether to verify the SSL certificate.
- Databricks:
- Databricks now use an ODBC-based connector.
- Fix: Date column was coerced to DateTime in the front-end.
- Druid:
- Added username and password authentication option.
- Microsoft SQL Server
- Added support for ODBC connections via pyodbc. There are now two MSSQL data source types. One using TDS. The other is using ODBC.
- MongoDB:
- Added support for running queries on secondary in replicaset mode.
- Fix: Connection test always succeeded.
- Oracle:
- Fix: Connection would fail if username or password contained special characters.
- Fix: Comparisons would fail if scale was None.
- RDS:
- Updated rds-combined-ca-bundle.pem to the latest CA.
- Redshift:
- Added the ability to use IAM Roles and Users.
- Fix: Redshift was unable to have its schema refreshed.
- Rockset:
- Fix: Allow Redash to load collections in all workspaces.
- Snowflake:
- You can now refresh the snowflake schema without waking the cluster.
- Added support for all of Snowflakes datetime types. Otherwise certain timestamps would only appear as strings in the front-end.
- TreasureData:
- Fix: API calls would fail when setting a non-default region.
### Alerts
- Feature: Added ability to mute alerts without deleting them.
- Fix: numerical comparisons failed if value from query was a string.
### Parameters
- Added Last x Days options for date range parameters.
- Fix: Parameters added in empty queries were always added as text parameters
### Bug Fixes
- Fix: Alembic migration schema was preventing v4 users from upgrading. In v5 we started encrypting data source credentials in the database.
- Fix: System admin dashboard would not show correct database size if non-default name was used.
- Fix: refresh_queries job would break if any query had a bad schedule object.
- Fix: Orgs with LDAP enabled couldnt disable password login.
- Fix: SSL mode was sometimes sent as an empty string to the database instead of omitted entirely.
- Fix: When creating new Map visualization with clustering disabled, map would crash on save.
- Fix: It was possible on the New Query page to click “Save” multiple times, causing multiple new query records to be created.
- Fix: Visualization render errors on a dashboard would crash the entire page.
- Fix: A scheduled execution failure would modify the querys “updated_at” timestamp.
- Fix: Parameter UI would wrap awkwardly during some drag operations.
- Fix: In dashboard edit mode, users couldnt modify widgets.
- Fix: Frontend error when parsing a NaN float.
### Other
- Added TSV as a download format (in addition to CSV and Excel).
- Added maildev settings (helps with automated settings).
- Refine permissions usage in Redash to allow for guest users
- The query results API now explicitly handles 404 errors.
- Forked queries now retain the tags of the original query.
- We now allow setting custom Sentry environments.
- Started using Black linter for our Python source code
- Added CLI command to re-encrypt data source details with new secret key.
- Favorites list is now loaded on menu click instead of on page load.
- Administrators can now allow connections to private IP addresses.
## v8.0.0 - 2019-10-27
There were no changes in this release since `v8.0.0-beta.2`. This is just to mark a stable release.
## v8.0.0-beta.2 - 2019-09-16
This is an update to the previous beta release, which includes:
- Add options for users to share anonymous usage information with us (see [docs](https://redash.io/help/open-source/admin-guide/usage-data) for details).
- Visualizations:
- Allow the user to decide how to handle null values in charts.
- Upgrade Sentry-SDK to latest version.
- Make horizontal table scroll visible in dashboard widgets without scrolling.
- Data Sources:
- Add support for Azure Data Explorer (Kusto).
- MySQL: fix connections without SSL configuration failing.
- Amazon Redshift: option to set query group for adhoc/scheduled queries.
- Hive: make error message more friendly.
- Qubole: add support to run Quantum queries.
- Display data source icon in query editor.
- Fix: allow users with view only acces to use the queries in Query Results
- Dashboard: when updating parameters refersh only widgets that use those parameters.
This release had contributions from 12 people: @arikfr, @cclauss, @gabrieldutra, @justinclift, @kravets-levko, @ranbena, @rauchy, @sandeepV2, @shinsuke-nara, @spacentropy, @sphenlee, @swfz.
## v8.0.0-beta - 2019-08-18
After months of being heads down with hard work, it's finally time to wrap up the V8 release 🤩 This release includes many long awaited improvements to parameters, UX improvements, further React migration and other changes, fixes and improvements.
While this version is already running on the hosted platform to make sure it's stable, we're excited to put this in the hands of our Open Source users.
Starting from this release we will no longer build a tarball distribution of the codebase and recommend everyone to switch over to using our Docker images. We're planning on dropping Python 2 support towards its EOL this year and switching over to the Docker image will make this transition much simpler.
This release was made possible by contributions from over 40 people: @aidarbek, @AntonZarutsky, @ariarijp, @arikfr, @combineads, @deecay, @fmy, @gabrieldutra, @guwenqing, @guyco33, @ialeinikov, @Jakdaw, @jezdez, @justinclift, @k-tomoyasu, @katty0324, @koooge, @kravets-levko, @ktmud, @KumanoTanaka, @kyoshidajp, @nason, @oldPadavan, @openjck, @osule, @otsaloma, @ranbena, @rauchy, @rueian, @sekiyama58, @shinsuke-nara, @taminif, @The-Alchemist, @vv-p, @washort, @wudi-ayuan, @ygrishaev, @yoavbls, @yoshiken, @yusukegoto and the support of over 500 organizations who subscribed to our hosted version and by that sponsor the team's work.
### Parameters
- Parameter UI improvements:
- Support for multi-select in dropdown (and query dropdown) parameters.
- Support for dynamic values in date and date-range parameters.
- Search dropdown parameter values.
- New UX for applying parameter changes in queries and dashboards.
- Allow using Safe Parameters in visualization embeds and public dashboards. Safe Parameters are any parameter type except for the a text parameter (dropdowns are safe).
### Data Sources
- New Data Sources: Couchbase, Phoenix and Dgraph.
- New JSON data source (and deprecated old URL data source).
- Snowflake: update connector to latest version.
- PostgreSQL: show only accessible tables in schema.
- BigQuery:
- Correctly handle NaN values.
- Treat repeated fields as rrays.
- [BigQuery] Fix: in some queries there is no mode field
- DynamoDB:
- Support for Unicode in queries.
- Safe loading of schema.
- Rockset: better handling of query errors.
- Google Sheets:
- Support for Team Drive.
- Friendlier error message in case of an API error and more reliable test connection.
- MySQL:
- Support for calling Stored Procedures and better handling of query cancellation.
- Switch to using `mysqlclient` (a maintained fork of `Python-MySQL`).
- MongoDB: Support serializing Decimal128 values.
- Presto: support for passwords in connection settings.
- Amazon Athena: allow to specify custom work group.
- Query Results: querying a column with a dictionary or array fails
- Clickhouse: make sure we don't show password in error messages.
- Enable Cassandra support by default.
### Visualizations
- Charts:
- Fix: legend overlapping chart on small screens.
- Fix: Pie chart not rendering when series doesn't exist in options.
- Pie Chart: add option to set direction of slices.
- WordCloud: rewritten to support new options (provide frequency in query, limits), scale when resizing, handle long words and more.
- Pivot Table: support hiding totals.
- Counters: apply formatting to target value.
- Maps:
- Ability to customize marker icon and color.
- Customization options for Choropleth maps.
- New Visualization: Details View.
### **UX**
- Replace blank screen with a loading indicator when the application is doing its first load.
- Multiple improvements to dashboards editing: auto-save, grid markings and better refresh indicator.
- Admin can now edit user's groups from the user page.
- Add keyboard shortcut (Ctrl/Cmd+Shift+F) to trigger query formatting.
### API
- Query Result API response minimized to only required fields when called with a non user API key.
- Prefer API key over cookies in authentication.
- User can now regenerate Query API Key.
### Other Changes
- Sends CSP headers to prevent various kinds of security attacks via the browser. Might break unusual usages and embeds of Redash.
- New Failed Scheduled Queries email report (can be enabled from organization settings screen).
- Deprecated HipChat Alert Destination.
- Add options to hide different parts of a Visualization embed UI (parameters, title, link to query).
- Support multi-byte search for query names and descriptions (needs to be enabled in Organization settings screen).
- CSV query results download: correctly serialize booleans and date values.
- Dashboard filters now collect values from all widgets with the same filter.
- Support for custom message and description in alert notifications (currently disabled behind a feature flag until we improve the alert UX).
### Bug Fixes
- Fix: adding widget to dashboard from a query page is broken.
- Fix: default time format option was wrong.
- Fix: when too many errors of a scheduled queries occur it causes an OverflowError.
- Fix: when forking a query maintain the same visualizations order.
## v7.0.0 - 2019-03-17 ## v7.0.0 - 2019-03-17
We're trying a new format for the CHANGELOG in this release. Focusing on the bigger changes, but for whoever interested, you can see all the changes [here](https://github.com/getredash/redash/compare/v6.0.0...master). We're trying a new format for the CHANGELOG in this release. Focusing on the bigger changes, but for whoever interested, you can see all the changes [here](https://github.com/getredash/redash/compare/v6.0.0...master).

View File

@@ -46,8 +46,8 @@ When creating a new bug report, please make sure to:
If you would like to suggest an enhancement or ask for a new feature: If you would like to suggest an enhancement or ask for a new feature:
- Please check [the roadmap](https://trello.com/b/b2LUHU7A/redash-roadmap) for existing Trello card for what you want to suggest/ask. If there is, feel free to upvote it to signal interest or add your comments. - Please check [the forum](https://discuss.redash.io/c/feature-requests/5) for existing threads about what you want to suggest/ask. If there is, feel free to upvote it to signal interest or add your comments.
- If there is no existing card, open a thread in [the forum](https://discuss.redash.io/c/feature-requests) to start a discussion about what you want to suggest. Try to provide as much details and context as possible and include information about *the problem you want to solve* rather only *your proposed solution*. - If there is no open thread, you're welcome to start one to have a discussion about what you want to suggest. Try to provide as much details and context as possible and include information about *the problem you want to solve* rather only *your proposed solution*.
### Pull Requests ### Pull Requests
@@ -55,9 +55,9 @@ If you would like to suggest an enhancement or ask for a new feature:
- Include screenshots and animated GIFs in your pull request whenever possible. - Include screenshots and animated GIFs in your pull request whenever possible.
- Please add [documentation](#documentation) for new features or changes in functionality along with the code. - Please add [documentation](#documentation) for new features or changes in functionality along with the code.
- Please follow existing code style: - Please follow existing code style:
- Python: we use PEP8 for Python. - Python: we use [Black](https://github.com/psf/black) to auto format the code.
- Javascript: we use Airbnb's style guides for [JavaScript](https://github.com/airbnb/javascript#naming-conventions) and [React](https://github.com/airbnb/javascript/blob/master/react) (currently we don't follow Airbnb's convention for naming files, but we're gradually fixing this). To make it automatic and easy, we recommend using [Prettier](https://github.com/prettier/prettier). - Javascript: we use [Prettier](https://github.com/prettier/prettier) to auto-format the code.
### Documentation ### Documentation
The project's documentation can be found at [https://redash.io/help/](https://redash.io/help/). The [documentation sources](https://github.com/getredash/website/tree/master/src/pages/kb) are hosted on GitHub. To contribute edits / new pages, you can use GitHub's interface. Click the "Edit on GitHub" link on the documentation page to quickly open the edit interface. The project's documentation can be found at [https://redash.io/help/](https://redash.io/help/). The [documentation sources](https://github.com/getredash/website/tree/master/src/pages/kb) are hosted on GitHub. To contribute edits / new pages, you can use GitHub's interface. Click the "Edit on GitHub" link on the documentation page to quickly open the edit interface.
@@ -66,9 +66,9 @@ The project's documentation can be found at [https://redash.io/help/](https://re
### Release Method ### Release Method
We publish a stable release every ~2 months, although the goal is to get to a stable release every month. You can see the change log on [GitHub releases page](https://github.com/getredash/redash/releases). We publish a stable release every ~3-4 months, although the goal is to get to a stable release every month.
Every build of the master branch updates the latest *RC release*. These releases are usually stable, but might contain regressions and therefore recommended for "advanced users" only. Every build of the master branch updates the *redash/redash:preview* Docker Image. These releases are usually stable, but might contain regressions and therefore recommended for "advanced users" only.
When we release a new stable release, we also update the *latest* Docker image tag, the EC2 AMIs and GCE images. When we release a new stable release, we also update the *latest* Docker image tag, the EC2 AMIs and GCE images.

View File

@@ -1,22 +1,88 @@
FROM node:10 as frontend-builder FROM node:12 as frontend-builder
# Controls whether to build the frontend assets
ARG skip_frontend_build
ENV CYPRESS_INSTALL_BINARY=0
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
RUN useradd -m -d /frontend redash
USER redash
WORKDIR /frontend WORKDIR /frontend
COPY package.json package-lock.json /frontend/ COPY --chown=redash package.json package-lock.json /frontend/
RUN npm install COPY --chown=redash viz-lib /frontend/viz-lib
COPY client /frontend/client # Controls whether to instrument code for coverage information
COPY webpack.config.js /frontend/ ARG code_coverage
RUN npm run build ENV BABEL_ENV=${code_coverage:+test}
FROM redash/base:debian RUN if [ "x$skip_frontend_build" = "x" ] ; then npm ci --unsafe-perm; fi
COPY --chown=redash client /frontend/client
COPY --chown=redash webpack.config.js /frontend/
RUN if [ "x$skip_frontend_build" = "x" ] ; then npm run build; else mkdir -p /frontend/client/dist && touch /frontend/client/dist/multi_org.html && touch /frontend/client/dist/index.html; fi
FROM python:3.7-slim
EXPOSE 5000
# Controls whether to install extra dependencies needed for all data sources. # Controls whether to install extra dependencies needed for all data sources.
ARG skip_ds_deps ARG skip_ds_deps
# Controls whether to install dev dependencies.
ARG skip_dev_deps
RUN useradd --create-home redash
# Ubuntu packages
RUN apt-get update && \
apt-get install -y \
curl \
gnupg \
build-essential \
pwgen \
libffi-dev \
sudo \
git-core \
wget \
# Postgres client
libpq-dev \
# ODBC support:
g++ unixodbc-dev \
# for SAML
xmlsec1 \
# Additional packages required for data sources:
libssl-dev \
default-libmysqlclient-dev \
freetds-dev \
libsasl2-dev \
unzip \
libsasl2-modules-gssapi-mit && \
# MSSQL ODBC Driver:
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \
curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list && \
apt-get update && \
ACCEPT_EULA=Y apt-get install -y msodbcsql17 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ARG databricks_odbc_driver_url=https://databricks.com/wp-content/uploads/2.6.10.1010-2/SimbaSparkODBC-2.6.10.1010-2-Debian-64bit.zip
ADD $databricks_odbc_driver_url /tmp/simba_odbc.zip
RUN unzip /tmp/simba_odbc.zip -d /tmp/ \
&& dpkg -i /tmp/SimbaSparkODBC-*/*.deb \
&& echo "[Simba]\nDriver = /opt/simba/spark/lib/64/libsparkodbc_sb64.so" >> /etc/odbcinst.ini \
&& rm /tmp/simba_odbc.zip \
&& rm -rf /tmp/SimbaSparkODBC*
WORKDIR /app
# Disalbe PIP Cache and Version Check
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV PIP_NO_CACHE_DIR=1
# We first copy only the requirements file, to avoid rebuilding on every file # We first copy only the requirements file, to avoid rebuilding on every file
# change. # change.
COPY requirements.txt requirements_bundles.txt requirements_dev.txt requirements_all_ds.txt ./ COPY requirements.txt requirements_bundles.txt requirements_dev.txt requirements_all_ds.txt ./
RUN pip install -r requirements.txt -r requirements_dev.txt RUN if [ "x$skip_dev_deps" = "x" ] ; then pip install -r requirements.txt -r requirements_dev.txt; else pip install -r requirements.txt; fi
RUN if [ "x$skip_ds_deps" = "x" ] ; then pip install -r requirements_all_ds.txt ; else echo "Skipping pip install -r requirements_all_ds.txt" ; fi RUN if [ "x$skip_ds_deps" = "x" ] ; then pip install -r requirements_all_ds.txt ; else echo "Skipping pip install -r requirements_all_ds.txt" ; fi
COPY . /app COPY . /app

View File

@@ -1,4 +1,4 @@
Copyright (c) 2013-2019, Arik Fraimovich. Copyright (c) 2013-2020, Arik Fraimovich.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,

View File

@@ -35,7 +35,7 @@ backend-unit-tests: up test_db
docker-compose run --rm --name tests server tests docker-compose run --rm --name tests server tests
frontend-unit-tests: bundle frontend-unit-tests: bundle
npm install CYPRESS_INSTALL_BINARY=0 PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 npm ci
npm run bundle npm run bundle
npm test npm test

View File

@@ -4,30 +4,79 @@
[![Documentation](https://img.shields.io/badge/docs-redash.io/help-brightgreen.svg)](https://redash.io/help/) [![Documentation](https://img.shields.io/badge/docs-redash.io/help-brightgreen.svg)](https://redash.io/help/)
[![Datree](https://s3.amazonaws.com/catalog.static.datree.io/datree-badge-20px.svg)](https://datree.io/?src=badge) [![Datree](https://s3.amazonaws.com/catalog.static.datree.io/datree-badge-20px.svg)](https://datree.io/?src=badge)
![Build Status](https://circleci.com/gh/getredash/redash.png?circle-token=8a695aa5ec2cbfa89b48c275aea298318016f040) [![Build Status](https://circleci.com/gh/getredash/redash.png?style=shield&circle-token=8a695aa5ec2cbfa89b48c275aea298318016f040)](https://circleci.com/gh/getredash/redash/tree/master)
**_Redash_** is our take on freeing the data within our company in a way that will better fit our culture and usage patterns. Redash is designed to enable anyone, regardless of the level of technical sophistication, to harness the power of data big and small. SQL users leverage Redash to explore, query, visualize, and share data from any data sources. Their work in turn enables anybody in their organization to use the data. Every day, millions of users at thousands of organizations around the world use Redash to develop insights and make data-driven decisions.
Prior to **_Redash_**, we tried to use traditional BI suites and discovered a set of bloated, technically challenged and slow tools/flows. What we were looking for was a more hacker'ish way to look at data, so we built one. Redash features:
**_Redash_** was built to allow fast and easy access to billions of records, that we process and collect using Amazon Redshift ("petabyte scale data warehouse" that "speaks" PostgreSQL). 1. **Browser-based**: Everything in your browser, with a shareable URL.
Today **_Redash_** has support for querying multiple databases, including: Redshift, Google BigQuery, PostgreSQL, MySQL, Graphite, Presto, Google Spreadsheets, Cloudera Impala, Hive and custom scripts. 2. **Ease-of-use**: Become immediately productive with data without the need to master complex software.
3. **Query editor**: Quickly compose SQL and NoSQL queries with a schema browser and auto-complete.
**_Redash_** consists of two parts: 4. **Visualization and dashboards**: Create [beautiful visualizations](https://redash.io/help/user-guide/visualizations/visualization-types) with drag and drop, and combine them into a single dashboard.
5. **Sharing**: Collaborate easily by sharing visualizations and their associated queries, enabling peer review of reports and queries.
1. **Query Editor**: think of [JS Fiddle](https://jsfiddle.net) for SQL queries. It's your way to share data in the organization in an open way, by sharing both the dataset and the query that generated it. This way everyone can peer review not only the resulting dataset but also the process that generated it. Also it's possible to fork it and generate new datasets and reach new insights. 6. **Schedule refreshes**: Automatically update your charts and dashboards at regular intervals you define.
2. **Visualizations and Dashboards**: once you have a dataset, you can create different visualizations out of it, and then combine several visualizations into a single dashboard. Currently Redash supports charts, pivot table, cohorts and [more](https://redash.io/help/user-guide/visualizations/visualization-types). 7. **Alerts**: Define conditions and be alerted instantly when your data changes.
8. **REST API**: Everything that can be done in the UI is also available through REST API.
9. **Broad support for data sources**: Extensible data source API with native support for a long list of common databases and platforms.
<img src="https://raw.githubusercontent.com/getredash/website/8e820cd02c73a8ddf4f946a9d293c54fd3fb08b9/website/_assets/images/redash-anim.gif" width="80%"/> <img src="https://raw.githubusercontent.com/getredash/website/8e820cd02c73a8ddf4f946a9d293c54fd3fb08b9/website/_assets/images/redash-anim.gif" width="80%"/>
## Getting Started ## Getting Started
* [Setting up Redash instance](https://redash.io/help/open-source/setup) (includes links to ready made AWS/GCE images). * [Setting up Redash instance](https://redash.io/help/open-source/setup) (includes links to ready-made AWS/GCE images).
* [Documentation](https://redash.io/help/). * [Documentation](https://redash.io/help/).
## Supported Data Sources ## Supported Data Sources
Redash supports more than 35 [data sources](https://redash.io/help/data-sources/supported-data-sources). Redash supports more than 35 SQL and NoSQL [data sources](https://redash.io/help/data-sources/supported-data-sources). It can also be extended to support more. Below is a list of built-in sources:
- Amazon Athena
- Amazon DynamoDB
- Amazon Redshift
- Axibase Time Series Database
- Cassandra
- ClickHouse
- CockroachDB
- CSV
- Databricks (Apache Spark)
- DB2 by IBM
- Druid
- Elasticsearch
- Google Analytics
- Google BigQuery
- Google Spreadsheets
- Graphite
- Greenplum
- Hive
- Impala
- InfluxDB
- JIRA
- JSON
- Apache Kylin
- OmniSciDB (Formerly MapD)
- MemSQL
- Microsoft Azure Data Warehouse / Synapse
- Microsoft Azure SQL Database
- Microsoft SQL Server
- MongoDB
- MySQL
- Oracle
- PostgreSQL
- Presto
- Prometheus
- Python
- Qubole
- Rockset
- Salesforce
- ScyllaDB
- Shell Scripts
- Snowflake
- SQLite
- TreasureData
- Vertica
- Yandex AppMetrrica
- Yandex Metrica
## Getting Help ## Getting Help
@@ -37,7 +86,7 @@ Redash supports more than 35 [data sources](https://redash.io/help/data-sources/
## Reporting Bugs and Contributing Code ## Reporting Bugs and Contributing Code
* Want to report a bug or request a feature? Please open [an issue](https://github.com/getredash/redash/issues/new). * Want to report a bug or request a feature? Please open [an issue](https://github.com/getredash/redash/issues/new).
* Want to help us build **_Redash_**? Fork the project, edit in a [dev environment](https://redash.io/help-onpremise/dev/guide.html), and make a pull request. We need all the help we can get! * Want to help us build **_Redash_**? Fork the project, edit in a [dev environment](https://redash.io/help-onpremise/dev/guide.html) and make a pull request. We need all the help we can get!
## Security ## Security

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Copy bundle extension files to the client/app/extension directory""" """Copy bundle extension files to the client/app/extension directory"""
import logging import logging
import os import os
from pathlib2 import Path from pathlib import Path
from shutil import copy from shutil import copy
from collections import OrderedDict as odict from collections import OrderedDict as odict
from importlib_metadata import entry_points import importlib_metadata
from importlib_resources import contents, is_resource, path import importlib_resources
# Name of the subdirectory # Name of the subdirectory
BUNDLE_DIRECTORY = "bundle" BUNDLE_DIRECTORY = "bundle"
@@ -18,7 +17,7 @@ logger = logging.getLogger(__name__)
# Make a directory for extensions and set it as an environment variable # Make a directory for extensions and set it as an environment variable
# to be picked up by webpack. # to be picked up by webpack.
extensions_relative_path = Path('client', 'app', 'extensions') extensions_relative_path = Path("client", "app", "extensions")
extensions_directory = Path(__file__).parent.parent / extensions_relative_path extensions_directory = Path(__file__).parent.parent / extensions_relative_path
if not extensions_directory.exists(): if not extensions_directory.exists():
@@ -26,18 +25,6 @@ if not extensions_directory.exists():
os.environ["EXTENSIONS_DIRECTORY"] = str(extensions_relative_path) os.environ["EXTENSIONS_DIRECTORY"] = str(extensions_relative_path)
def resource_isdir(module, resource):
"""Whether a given resource is a directory in the given module
https://importlib-resources.readthedocs.io/en/latest/migration.html#pkg-resources-resource-isdir
"""
try:
return resource in contents(module) and not is_resource(module, resource)
except (ImportError, TypeError):
# module isn't a package, so can't have a subdirectory/-package
return False
def entry_point_module(entry_point): def entry_point_module(entry_point):
"""Returns the dotted module path for the given entry point""" """Returns the dotted module path for the given entry point"""
return entry_point.pattern.match(entry_point.value).group("module") return entry_point.pattern.match(entry_point.value).group("module")
@@ -78,26 +65,36 @@ def load_bundles():
""" """
bundles = odict() bundles = odict()
for entry_point in entry_points().get("redash.bundles", []): for entry_point in importlib_metadata.entry_points().get("redash.bundles", []):
logger.info('Loading Redash bundle "%s".', entry_point.name) logger.info('Loading Redash bundle "%s".', entry_point.name)
module = entry_point_module(entry_point) module = entry_point_module(entry_point)
# Try to get a list of bundle files # Try to get a list of bundle files
if not resource_isdir(module, BUNDLE_DIRECTORY): try:
bundle_dir = importlib_resources.files(module).joinpath(BUNDLE_DIRECTORY)
except (ImportError, TypeError):
# Module isn't a package, so can't have a subdirectory/-package
logger.error( logger.error(
'Redash bundle directory "%s" could not be found.', entry_point.name 'Redash bundle module "%s" could not be imported: "%s"',
entry_point.name,
module,
) )
continue continue
with path(module, BUNDLE_DIRECTORY) as bundle_dir: if not bundle_dir.is_dir():
bundles[entry_point.name] = list(bundle_dir.rglob("*")) logger.error(
'Redash bundle directory "%s" could not be found or is not a directory: "%s"',
entry_point.name,
bundle_dir,
)
continue
bundles[entry_point.name] = list(bundle_dir.rglob("*"))
return bundles return bundles
bundles = load_bundles().items() bundles = load_bundles().items()
if bundles: if bundles:
print('Number of extension bundles found: {}'.format(len(bundles))) print("Number of extension bundles found: {}".format(len(bundles)))
else: else:
print('No extension bundles found.') print("No extension bundles found.")
for bundle_name, paths in bundles: for bundle_name, paths in bundles:
# Shortcut in case not paths were found for the bundle # Shortcut in case not paths were found for the bundle

View File

@@ -1,33 +1,31 @@
#!/bin/bash #!/bin/bash
set -e set -e
worker() { scheduler() {
WORKERS_COUNT=${WORKERS_COUNT:-2} echo "Starting RQ scheduler..."
QUEUES=${QUEUES:-queries,scheduled_queries,celery,schemas}
WORKER_EXTRA_OPTIONS=${WORKER_EXTRA_OPTIONS:-}
echo "Starting $WORKERS_COUNT workers for queues: $QUEUES..." exec /app/manage.py rq scheduler
exec /usr/local/bin/celery worker --app=redash.worker -c$WORKERS_COUNT -Q$QUEUES -linfo --max-tasks-per-child=10 -Ofair $WORKER_EXTRA_OPTIONS
} }
scheduler() { dev_scheduler() {
WORKERS_COUNT=${WORKERS_COUNT:-1} echo "Starting dev RQ scheduler..."
QUEUES=${QUEUES:-celery}
SCHEDULE_DB=${SCHEDULE_DB:-celerybeat-schedule}
echo "Starting scheduler and $WORKERS_COUNT workers for queues: $QUEUES..." exec watchmedo auto-restart --directory=./redash/ --pattern=*.py --recursive -- ./manage.py rq scheduler
}
exec /usr/local/bin/celery worker --app=redash.worker --beat -s$SCHEDULE_DB -c$WORKERS_COUNT -Q$QUEUES -linfo --max-tasks-per-child=10 -Ofair worker() {
echo "Starting RQ worker..."
export WORKERS_COUNT=${WORKERS_COUNT:-2}
export QUEUES=${QUEUES:-}
exec supervisord -c worker.conf
} }
dev_worker() { dev_worker() {
WORKERS_COUNT=${WORKERS_COUNT:-2} echo "Starting dev RQ worker..."
QUEUES=${QUEUES:-queries,scheduled_queries,celery,schemas}
SCHEDULE_DB=${SCHEDULE_DB:-celerybeat-schedule}
echo "Starting dev scheduler and $WORKERS_COUNT workers for queues: $QUEUES..." exec watchmedo auto-restart --directory=./redash/ --pattern=*.py --recursive -- ./manage.py rq worker $QUEUES
exec watchmedo auto-restart --directory=./redash/ --pattern=*.py --recursive -- /usr/local/bin/celery worker --app=redash.worker --beat -s$SCHEDULE_DB -c$WORKERS_COUNT -Q$QUEUES -linfo --max-tasks-per-child=10 -Ofair
} }
server() { server() {
@@ -41,10 +39,6 @@ create_db() {
exec /app/manage.py database create_tables exec /app/manage.py database create_tables
} }
celery_healthcheck() {
exec /usr/local/bin/celery inspect ping --app=redash.worker -d celery@$HOSTNAME
}
help() { help() {
echo "Redash Docker." echo "Redash Docker."
echo "" echo ""
@@ -52,10 +46,10 @@ help() {
echo "" echo ""
echo "server -- start Redash server (with gunicorn)" echo "server -- start Redash server (with gunicorn)"
echo "worker -- start Celery worker" echo "worker -- start a single RQ worker"
echo "scheduler -- start Celery worker with a beat (scheduler) process" echo "dev_worker -- start a single RQ worker with code reloading"
echo "dev_worker -- start Celery worker with a beat (scheduler) process which picks up code changes and reloads" echo "scheduler -- start an rq-scheduler instance"
echo "celery_healthcheck -- runs a Celery healthcheck. Useful for Docker's HEALTHCHECK mechanism." echo "dev_scheduler -- start an rq-scheduler instance with code reloading"
echo "" echo ""
echo "shell -- open shell" echo "shell -- open shell"
echo "dev_server -- start Flask development server with debugger and auto reload" echo "dev_server -- start Flask development server with debugger and auto reload"
@@ -89,10 +83,18 @@ case "$1" in
shift shift
scheduler scheduler
;; ;;
dev_scheduler)
shift
dev_scheduler
;;
dev_worker) dev_worker)
shift shift
dev_worker dev_worker
;; ;;
celery_healthcheck)
shift
echo "DEPRECATED: Celery has been replaced with RQ and now performs healthchecks autonomously as part of the 'worker' entrypoint."
;;
dev_server) dev_server)
export FLASK_DEBUG=1 export FLASK_DEBUG=1
exec /app/manage.py runserver --debugger --reload -h 0.0.0.0 exec /app/manage.py runserver --debugger --reload -h 0.0.0.0
@@ -124,4 +126,3 @@ case "$1" in
exec "$@" exec "$@"
;; ;;
esac esac

View File

@@ -1,7 +1,9 @@
#!/bin/sh #!/bin/sh
set -o errexit # fail the build if any task fails
flake8 --version ; pip --version flake8 --version ; pip --version
# stop the build if there are Python syntax errors or undefined names # stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

View File

@@ -1,9 +1,10 @@
#!/bin/env python #!/bin/env python3
from __future__ import print_function
import sys import sys
import re import re
import subprocess import subprocess
def get_change_log(previous_sha): def get_change_log(previous_sha):
args = ['git', '--no-pager', 'log', '--merges', '--grep', 'Merge pull request', '--pretty=format:"%h|%s|%b|%p"', 'master...{}'.format(previous_sha)] args = ['git', '--no-pager', 'log', '--merges', '--grep', 'Merge pull request', '--pretty=format:"%h|%s|%b|%p"', 'master...{}'.format(previous_sha)]
log = subprocess.check_output(args) log = subprocess.check_output(args)
@@ -33,4 +34,4 @@ if __name__ == '__main__':
changes = get_change_log(previous_sha) changes = get_change_log(previous_sha)
for change in changes: for change in changes:
print(change) print(change)

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
# Heroku pre_compile script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
pushd $DIR/..
# heroku requires cffi to be in requirements.txt in order for libffi to be installed.
# https://github.com/heroku/heroku-buildpack-python/blob/master/bin/steps/cryptography
# to avoid making it a requirement for other build systems, we'll inject it now
# into the requirements.txt file
# Remove Heroku unsupported Python packages:
grep -v -E "^(pymssql|thrift|sasl|pyhive)" requirements_all_ds.txt >> requirements.txt
# make the heroku Procfile the active one
cp Procfile.heroku Procfile
popd

View File

@@ -1,4 +1,4 @@
from __future__ import print_function #!/usr/bin/env python3
import os import os
import sys import sys
import re import re

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import urllib import urllib
import argparse import argparse
import os import os
@@ -27,7 +27,7 @@ def run(cmd, cwd=None):
def confirm(question): def confirm(question):
reply = str(raw_input(question + ' (y/n): ')).lower().strip() reply = str(input(question + ' (y/n): ')).lower().strip()
if reply[0] == 'y': if reply[0] == 'y':
return True return True

View File

@@ -1,20 +1,29 @@
{ {
"presets": [ "presets": [
["@babel/preset-env", { [
"exclude": [ "@babel/preset-env",
"@babel/plugin-transform-async-to-generator", {
"@babel/plugin-transform-arrow-functions" "exclude": ["@babel/plugin-transform-async-to-generator", "@babel/plugin-transform-arrow-functions"],
], "corejs": "2",
"useBuiltIns": "usage" "useBuiltIns": "usage"
}], }
"@babel/preset-react" ],
"@babel/preset-react",
"@babel/preset-typescript"
], ],
"plugins": [ "plugins": [
"angularjs-annotate",
"@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-object-assign", "@babel/plugin-transform-object-assign",
["babel-plugin-transform-builtin-extend", { [
"globals": ["Error"] "babel-plugin-transform-builtin-extend",
}] {
] "globals": ["Error"]
}
]
],
"env": {
"test": {
"plugins": ["istanbul"]
}
}
} }

View File

@@ -1,3 +1,4 @@
build/*.js build/*.js
dist
config/*.js config/*.js
client/dist client/dist

View File

@@ -1,66 +1,57 @@
module.exports = { module.exports = {
root: true, root: true,
extends: ["airbnb", "plugin:compat/recommended"], parser: "@typescript-eslint/parser",
plugins: ["jest", "compat", "no-only-tests"], extends: [
"react-app",
"plugin:compat/recommended",
"prettier",
// Remove any typescript-eslint rules that would conflict with prettier
"prettier/@typescript-eslint",
],
plugins: ["jest", "compat", "no-only-tests", "@typescript-eslint"],
settings: { settings: {
"import/resolver": "webpack" "import/resolver": "webpack",
}, },
parser: "babel-eslint",
env: { env: {
browser: true, browser: true,
node: true node: true,
}, },
rules: { rules: {
// allow debugger during development // allow debugger during development
"no-debugger": process.env.NODE_ENV === "production" ? 2 : 0, "no-debugger": process.env.NODE_ENV === "production" ? 2 : 0,
"no-param-reassign": 0,
"no-mixed-operators": 0,
"no-underscore-dangle": 0,
"no-use-before-define": ["error", "nofunc"],
"prefer-destructuring": "off",
"prefer-template": "off",
"no-restricted-properties": "off",
"no-restricted-globals": "off",
"no-multi-assign": "off",
"no-lonely-if": "off",
"consistent-return": "off",
"no-control-regex": "off",
"no-multiple-empty-lines": "warn",
"no-only-tests/no-only-tests": "error",
"operator-linebreak": "off",
"react/destructuring-assignment": "off",
"react/jsx-filename-extension": "off",
"react/jsx-one-expression-per-line": "off",
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/jsx-wrap-multilines": "warn",
"react/no-access-state-in-setstate": "warn",
"react/prefer-stateless-function": "warn",
"react/forbid-prop-types": "warn",
"react/prop-types": "warn",
"jsx-a11y/anchor-is-valid": "off", "jsx-a11y/anchor-is-valid": "off",
"jsx-a11y/click-events-have-key-events": "off", "no-restricted-imports": [
"jsx-a11y/label-has-associated-control": [
"warn",
{
controlComponents: true
}
],
"jsx-a11y/label-has-for": "off",
"jsx-a11y/no-static-element-interactions": "off",
"max-len": [
"error", "error",
120,
2,
{ {
ignoreUrls: true, paths: [
ignoreComments: false, {
ignoreRegExpLiterals: true, name: "antd",
ignoreStrings: true, message: "Please use 'import XXX from antd/lib/XXX' import instead.",
ignoreTemplateLiterals: true },
} {
name: "antd/lib",
message: "Please use 'import XXX from antd/lib/XXX' import instead.",
},
],
},
], ],
"no-else-return": ["error", { allowElseIf: true }], },
"object-curly-newline": ["error", { consistent: true }] overrides: [
} {
// Only run typescript-eslint on TS files
files: ["*.ts", "*.tsx", ".*.ts", ".*.tsx"],
extends: ["plugin:@typescript-eslint/recommended"],
rules: {
// Do not require functions (especially react components) to have explicit returns
"@typescript-eslint/explicit-function-return-type": "off",
// Do not require to type every import from a JS file to speed up development
"@typescript-eslint/no-explicit-any": "off",
// Do not complain about useless contructors in declaration files
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": "error",
// Many API fields and generated types use camelcase
"@typescript-eslint/camelcase": "off",
},
},
],
}; };

View File

@@ -7,4 +7,4 @@ module.exports = {
rules: { rules: {
"jest/no-focused-tests": "off", "jest/no-focused-tests": "off",
}, },
}; };

View File

@@ -1,4 +1,4 @@
import { configure } from 'enzyme'; import { configure } from "enzyme";
import Adapter from 'enzyme-adapter-react-16'; import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() }); configure({ adapter: new Adapter() });

View File

@@ -1,5 +1,5 @@
import MockDate from 'mockdate'; import MockDate from "mockdate";
const date = new Date('2000-01-01T02:00:00.000'); const date = new Date("2000-01-01T02:00:00.000");
MockDate.set(date); MockDate.set(date);

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,13 @@
<svg width="274" height="199" viewBox="0 0 274 199" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.5" d="M57.9111 49.2668L202.769 30" stroke="#F2F2F2" stroke-width="59" stroke-linecap="round"/>
<path opacity="0.5" d="M39.2842 92.7371L244.24 64.886" stroke="#F2F2F2" stroke-width="59" stroke-linecap="round"/>
<path opacity="0.5" d="M30 136.299L232.813 107.734" stroke="#F2F2F2" stroke-width="59" stroke-linecap="round"/>
<path opacity="0.5" d="M86.4541 169.149L234.166 150.596" stroke="#F2F2F2" stroke-width="59" stroke-linecap="round"/>
<path d="M167.829 69.1349H96.458L117.605 51.9531H183.028L167.829 69.1349Z" fill="#C0D5FF"/>
<path d="M171.133 70.4566H92.4933V85.6559V143.149H171.133V70.4566Z" fill="#E8F4FF"/>
<path d="M190.298 48.6489L171.133 70.4566L186.993 94.9076L192.28 89.9514L206.818 73.7608L190.298 48.6489Z" fill="#E8F4FF"/>
<path d="M171.133 70.4566V143.149L192.28 118.037V89.9514L186.993 94.9076L171.133 70.4566Z" fill="#E8F4FF"/>
<path d="M92.4933 70.4566L81.9199 89.9514L92.4933 85.6559V70.4566Z" fill="#E8F4FF"/>
<path d="M92.4933 70.4566H171.133M92.4933 70.4566L118.927 48.6489H190.298M92.4933 70.4566L81.9199 89.9514L92.4933 85.6559M92.4933 70.4566V85.6559M171.133 70.4566V143.149M171.133 70.4566L190.298 48.6489M171.133 70.4566L186.993 94.9076L192.28 89.9514M171.133 143.149H92.4933V85.6559M171.133 143.149L192.28 118.037V89.9514M190.298 48.6489L206.818 73.7608L192.28 89.9514" stroke="black" stroke-width="3" stroke-linejoin="round"/>
<path d="M117.605 89.6208H147.343" stroke="black" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,42 +1,43 @@
@import '~antd/lib/style/core/iconfont'; @import "~antd/lib/style/core/iconfont";
@import '~antd/lib/style/core/motion'; @import "~antd/lib/style/core/motion";
@import '~antd/lib/alert/style/index'; @import "~antd/lib/alert/style/index";
@import '~antd/lib/input/style/index'; @import "~antd/lib/input/style/index";
@import '~antd/lib/input-number/style/index'; @import "~antd/lib/input-number/style/index";
@import '~antd/lib/date-picker/style/index'; @import "~antd/lib/date-picker/style/index";
@import '~antd/lib/modal/style/index'; @import "~antd/lib/modal/style/index";
@import '~antd/lib/tooltip/style/index'; @import "~antd/lib/tooltip/style/index";
@import '~antd/lib/select/style/index'; @import "~antd/lib/select/style/index";
@import '~antd/lib/checkbox/style/index'; @import "~antd/lib/checkbox/style/index";
@import '~antd/lib/upload/style/index'; @import "~antd/lib/upload/style/index";
@import '~antd/lib/form/style/index'; @import "~antd/lib/form/style/index";
@import '~antd/lib/button/style/index'; @import "~antd/lib/button/style/index";
@import '~antd/lib/radio/style/index'; @import "~antd/lib/radio/style/index";
@import '~antd/lib/time-picker/style/index'; @import "~antd/lib/time-picker/style/index";
@import '~antd/lib/pagination/style/index'; @import "~antd/lib/pagination/style/index";
@import '~antd/lib/table/style/index'; @import "~antd/lib/table/style/index";
@import '~antd/lib/popover/style/index'; @import "~antd/lib/popover/style/index";
@import '~antd/lib/icon/style/index'; @import "~antd/lib/tag/style/index";
@import '~antd/lib/tag/style/index'; @import "~antd/lib/grid/style/index";
@import '~antd/lib/grid/style/index'; @import "~antd/lib/switch/style/index";
@import '~antd/lib/switch/style/index'; @import "~antd/lib/empty/style/index";
@import '~antd/lib/empty/style/index'; @import "~antd/lib/drawer/style/index";
@import '~antd/lib/drawer/style/index'; @import "~antd/lib/card/style/index";
@import '~antd/lib/card/style/index'; @import "~antd/lib/steps/style/index";
@import '~antd/lib/steps/style/index'; @import "~antd/lib/divider/style/index";
@import '~antd/lib/divider/style/index'; @import "~antd/lib/dropdown/style/index";
@import '~antd/lib/dropdown/style/index'; @import "~antd/lib/menu/style/index";
@import '~antd/lib/menu/style/index'; @import "~antd/lib/list/style/index";
@import '~antd/lib/list/style/index';
@import "~antd/lib/badge/style/index"; @import "~antd/lib/badge/style/index";
@import "~antd/lib/card/style/index"; @import "~antd/lib/card/style/index";
@import "~antd/lib/spin/style/index"; @import "~antd/lib/spin/style/index";
@import "~antd/lib/skeleton/style/index";
@import "~antd/lib/tabs/style/index"; @import "~antd/lib/tabs/style/index";
@import "~antd/lib/notification/style/index"; @import "~antd/lib/notification/style/index";
@import "~antd/lib/collapse/style/index"; @import "~antd/lib/collapse/style/index";
@import "~antd/lib/progress/style/index"; @import "~antd/lib/progress/style/index";
@import "~antd/lib/typography/style/index"; @import "~antd/lib/typography/style/index";
@import 'inc/ant-variables'; @import "~antd/lib/descriptions/style/index";
@import "inc/ant-variables";
// Increase z-indexes to avoid conflicts with some other libraries (e.g. Plotly) // Increase z-indexes to avoid conflicts with some other libraries (e.g. Plotly)
@zindex-modal: 2000; @zindex-modal: 2000;
@@ -47,6 +48,7 @@
@zindex-dropdown: 2050; @zindex-dropdown: 2050;
@zindex-picker: 2050; @zindex-picker: 2050;
@zindex-tooltip: 2060; @zindex-tooltip: 2060;
@item-hover-bg: #e5f8ff;
.@{drawer-prefix-cls} { .@{drawer-prefix-cls} {
&.help-drawer { &.help-drawer {
@@ -60,6 +62,11 @@
font-weight: normal; font-weight: normal;
} }
.ant-select-dropdown-menu-item em {
color: @input-color-placeholder;
font-size: 11px;
}
// Fix for disabled button styles inside Tooltip component. // Fix for disabled button styles inside Tooltip component.
// Tooltip wraps disabled buttons with `<span>` and moves all styles // Tooltip wraps disabled buttons with `<span>` and moves all styles
// and classes to that `<span>`. This resets all button styles and // and classes to that `<span>`. This resets all button styles and
@@ -77,15 +84,14 @@
} }
} }
// Fix for Ant dropdowns when they are used in Boootstrap modals
// ANGULAR_REMOVE_ME Remove when all dialogs will be migrated to React (also search and remove usages)
.ant-dropdown-in-bootstrap-modal {
z-index: 1050;
}
// Button overrides // Button overrides
.@{btn-prefix-cls} { .@{btn-prefix-cls} {
transition-duration: 150ms; transition-duration: 150ms;
&.icon-button {
width: 32px;
padding: 0 10px;
}
} }
// Fix ant input number showing duplicate arrows // Fix ant input number showing duplicate arrows
@@ -156,6 +162,10 @@
border-color: transparent; border-color: transparent;
color: @pagination-color; color: @pagination-color;
line-height: @pagination-item-size - 2px; line-height: @pagination-item-size - 2px;
.@{pagination-prefix-cls}.mini & {
line-height: @pagination-item-size-sm - 2px;
}
} }
&:focus .@{pagination-prefix-cls}-item-link, &:focus .@{pagination-prefix-cls}-item-link,
@@ -228,11 +238,11 @@
&-item { &-item {
// custom rule // custom rule
&.selected { &.selected {
background-color: #F6F8F9; background-color: #f6f8f9;
} }
&.disabled { &.disabled {
background-color: fade(#F6F8F9, 40%); background-color: fade(#f6f8f9, 40%);
& > * { & > * {
opacity: 0.4; opacity: 0.4;
@@ -322,7 +332,7 @@
} }
.@{btn-prefix-cls} .@{iconfont-css-prefix}-ellipsis { .@{btn-prefix-cls} .@{iconfont-css-prefix}-ellipsis {
margin: 0 -7px; margin: 0 -7px 0 -8px;
} }
// Collapse // Collapse
@@ -358,10 +368,47 @@
top: auto !important; top: auto !important;
bottom: 8px; bottom: 8px;
// makes the icon white instead of see-through // makes the icon white instead of see-through
& svg { & svg {
background: white; background: white;
border-radius: 50%; border-radius: 50%;
} }
} }
}
// for form items that contain text
&.form-item-line-height-normal .@{form-prefix-cls}-item-control {
line-height: 20px;
margin-top: 9px;
}
}
.@{menu-prefix-cls} {
// invert stripe position with class .invert-stripe-position
&-inline.invert-stripe-position {
.@{menu-prefix-cls}-item {
&::after {
right: auto;
left: 0;
}
}
}
}
// overrides for checkbox
@checkbox-prefix-cls: ~"@{ant-prefix}-checkbox";
.@{checkbox-prefix-cls}-wrapper + span,
.@{checkbox-prefix-cls} + span {
padding-right: 0;
}
// make sure Multiple select has room for icons
.@{select-prefix-cls}-multiple {
&.@{select-prefix-cls}-show-arrow,
&.@{select-prefix-cls}-show-search,
&.@{select-prefix-cls}-loading {
.@{select-prefix-cls}-selector {
padding-right: 30px;
}
}
}

View File

@@ -1,7 +1,25 @@
.ace_editor { .ace_editor {
border: 1px solid #eee; border: 1px solid fade(@redash-gray, 15%);
height: 100%; height: 100%;
margin-bottom: 10px; margin-bottom: 10px;
&.ace_autocomplete .ace_completion-highlight {
text-shadow: none !important;
background: #ffff005e;
font-weight: 600;
}
&.ace-tm {
.ace_gutter {
background: #fff !important;
}
.ace_gutter-active-line {
background-color: fade(@redash-gray, 20%) !important;
}
.ace_marker-layer .ace_active-line {
background: fade(@redash-gray, 9%) !important;
}
}
} }

View File

@@ -1,45 +1,49 @@
.alert { .alert-page h3 {
padding-left: 30px; flex-grow: 1;
padding-right: 30px;
input {
span { margin: -0.2em 0;
cursor: pointer; width: 100%;
} min-width: 170px;
}
} }
.alert-dismissable, .btn-create-alert[disabled] {
.alert-dismissible { display: block;
padding-right: 44px; margin-top: -20px;
}
.alert-inverse {
.alert-variant(@alert-inverse-bg; @alert-inverse-border; @alert-inverse-text);
} }
.alert-link { .alert-state {
color: #fff !important; border-bottom: 1px solid @input-border;
font-weight: normal !important; padding-bottom: 30px;
text-decoration: underline;
.alert-state-indicator {
text-transform: uppercase;
font-size: 14px;
padding: 5px 8px;
}
.ant-form-item-explain {
margin-top: 10px;
}
.alert-last-triggered {
color: @headings-color;
}
} }
.growl-animated { .alert-query-selector {
&.alert-inverse { min-width: 250px;
box-shadow: 0 0 5px fade(@alert-inverse-bg, 50%); width: auto !important;
} }
&.alert-info { // allow form item labels to gracefully break line
box-shadow: 0 0 5px fade(@alert-info-bg, 50%); .alert-form-item label {
} white-space: initial;
padding-right: 8px;
&.alert-success { line-height: 21px;
box-shadow: 0 0 5px fade(@alert-success-bg, 50%);
} &::after {
margin-right: 0 !important;
&.alert-warning { }
box-shadow: 0 0 5px fade(@alert-warning-bg, 50%);
}
&.alert-danger {
box-shadow: 0 0 5px fade(@alert-danger-bg, 50%);
}
} }

View File

@@ -1,8 +0,0 @@
a[ng-click] {
cursor: pointer;
}
/* Immediately apply ng-cloak, instead of waiting for angular.js to load: */
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}

View File

@@ -1,8 +1,8 @@
/* -------------------------------------------------------- /* --------------------------------------------------------
Colors Colors
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@lightblue: #03A9F4; @lightblue: #03a9f4;
@primary-color: #2196F3; @primary-color: #2196f3;
@redash-gray: rgba(102, 136, 153, 1); @redash-gray: rgba(102, 136, 153, 1);
@redash-orange: rgba(255, 120, 100, 1); @redash-orange: rgba(255, 120, 100, 1);
@@ -12,40 +12,31 @@
/* -------------------------------------------------------- /* --------------------------------------------------------
Font Font
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@redash-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; @redash-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue",
@font-family-no-number: @redash-font; sans-serif;
@font-family: @redash-font; @font-family-no-number: @redash-font;
@code-family: @redash-font; @font-family: @redash-font;
@font-size-base: 13px; @code-family: @redash-font;
@font-size-base: 13px;
/* -------------------------------------------------------- /* --------------------------------------------------------
Borders Borders
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@border-color-split: #f0f0f0; @border-color-split: #f0f0f0;
/* -------------------------------------------------------- /* --------------------------------------------------------
Typograpgy Typograpgy
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@text-color: #595959; @text-color: #595959;
/* -------------------------------------------------------- /* --------------------------------------------------------
Form Form
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@input-height-base: 35px; @input-height-base: 35px;
@input-color: #595959; @input-color: #595959;
@input-color-placeholder: #b4b4b4;
@border-radius-base: 2px; @border-radius-base: 2px;
@border-color-base: #E8E8E8; @border-color-base: #e8e8e8;
/* --------------------------------------------------------
Button
-----------------------------------------------------------*/
@btn-danger-bg: fade(@redash-gray, 10%);
@btn-danger-border: fade(@redash-gray, 15%);
/* -------------------------------------------------------- /* --------------------------------------------------------
Pagination Pagination
@@ -54,14 +45,13 @@
@pagination-font-family: @redash-font; @pagination-font-family: @redash-font;
@pagination-font-weight-active: normal; @pagination-font-weight-active: normal;
@pagination-bg: fade(@redash-gray, 15%); @pagination-bg: fade(@redash-gray, 15%);
@pagination-color: #7E7E7E; @pagination-color: #7e7e7e;
@pagination-active-bg: @lightblue; @pagination-active-bg: @lightblue;
@pagination-active-color: #FFF; @pagination-active-color: #fff;
@pagination-disabled-bg: fade(@redash-gray, 15%); @pagination-disabled-bg: fade(@redash-gray, 15%);
@pagination-hover-color: #333; @pagination-hover-color: #333;
@pagination-hover-bg: fade(@redash-gray, 25%); @pagination-hover-bg: fade(@redash-gray, 25%);
/* -------------------------------------------------------- /* --------------------------------------------------------
Table Table

View File

@@ -1,97 +1,227 @@
*, button, input, i, a { *,
-webkit-font-smoothing: antialiased; button,
input,
i,
a {
-webkit-font-smoothing: antialiased;
} }
*, *,
*:active, *:active,
*:hover { *:hover {
outline: none !important; outline: none !important;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;
} }
html { html {
overflow-x: ~"hidden\0/"; overflow-x: ~"hidden\0/";
-ms-overflow-style: auto; -ms-overflow-style: auto;
} }
html, body { html,
min-height: 100vh; body {
min-height: 100vh;
} }
body { body {
padding-top: @header-height; padding-top: 0;
position: relative; background: #f6f8f9;
&.headless { font-family: @redash-font;
padding-top: 0; position: relative;
.nav.app-header {
display: none; #application-root {
} padding-bottom: 15px;
} }
} }
app-view { #application-root {
min-height: 100vh; min-height: 100vh;
} }
app-view, #app-content { #application-root,
display: flex; #app-content {
flex-direction: column; display: flex;
flex-grow: 1; flex-direction: column;
flex-grow: 1;
} }
strong { strong {
font-weight: 500; font-weight: 500;
} }
#content { #content {
position: relative; position: relative;
padding-top: 30px; padding-top: 30px;
padding-bottom: 30px; padding-bottom: 30px;
@media (min-width: (@screen-sm-min + 1)) { @media (min-width: (@screen-sm-min + 1)) {
padding-right: 15px; padding-right: 15px;
padding-left: 15px; padding-left: 15px;
} }
@media (min-width: (@screen-lg-min + 80px)) { @media (min-width: (@screen-lg-min + 80px)) {
margin-left: @sidebar-left-width; margin-left: @sidebar-left-width;
} }
@media (min-width: @screen-sm-min) and (max-width: (@screen-md-max + 80px)) { @media (min-width: @screen-sm-min) and (max-width: (@screen-md-max + 80px)) {
margin-left: @sidebar-left-mid-width; margin-left: @sidebar-left-mid-width;
} }
@media (max-width: (@screen-sm-min)) { @media (max-width: (@screen-sm-min)) {
margin-left: 0; margin-left: 0;
} }
} }
.container { .container {
&.c-boxed { &.c-boxed {
max-width: @boxed-width; max-width: @boxed-width;
} }
}
.settings-screen,
.home-page,
.page-dashboard-list,
.page-queries-list,
.page-alerts-list,
.alert-page,
.admin-page-layout {
.container {
width: 100%;
max-width: none;
}
} }
.scrollbox { .scrollbox {
overflow: auto; overflow: auto;
position: relative; position: relative;
} }
.clickable { .clickable {
cursor: pointer; cursor: pointer;
} }
.resize-vertical { .resize-vertical {
resize: vertical !important; resize: vertical !important;
transition: height 0s !important; transition: height 0s !important;
} }
.resize-horizontal { .resize-horizontal {
resize: horizontal !important; resize: horizontal !important;
transition: width 0s !important; transition: width 0s !important;
} }
.resize-both, .resize-both,
.resize-vertical.resize-horizontal { .resize-vertical.resize-horizontal {
resize: both !important; resize: both !important;
transition: height 0s, width 0s !important; transition: height 0s, width 0s !important;
}
.bg-ace {
background-color: fade(@redash-gray, 12%) !important;
}
// resizeable
.rg-top span,
.rg-bottom span {
height: 3px;
border-color: #b1c1ce; // TODO: variable
}
.rg-bottom {
bottom: 15px;
span {
margin: 1.5px 0 0 -10px;
}
}
// Plotly
text.slicetext {
text-shadow: 1px 1px 5px #333;
}
// markdown
.markdown strong {
font-weight: bold;
}
.markdown img {
max-width: 100%;
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: fade(@redash-gray, 15%);
color: #111;
}
.profile__image--sidebar {
border-radius: 100%;
margin-right: 3px;
margin-top: -2px;
}
.profile__image--settings {
border-radius: 100%;
}
.profile__image_thumb {
border-radius: 100%;
margin-right: 3px;
margin-top: -2px;
width: 20px;
height: 20px;
}
// Error state
.error-state {
display: flex;
flex-direction: column;
justify-content: flex-start;
text-align: center;
margin-top: 25vh;
padding: 35px;
font-size: 14px;
line-height: 21px;
.error-state__icon {
.zmdi {
font-size: 64px;
color: @redash-gray;
}
}
@media (max-width: 767px) {
margin-top: 10vh;
}
}
.warning-icon-danger {
color: @red !important;
}
// page
.page-title {
display: flex;
align-items: center;
.label {
margin-top: 3px;
display: inline-block;
}
.favorites-control {
font-size: 19px;
margin-right: 10px;
}
}
.page-header--new {
h3 {
margin: 0.2em 0;
line-height: 1.3;
font-weight: 500;
}
}
.select-option-divider {
margin: 10px 0 !important;
} }

View File

@@ -31,7 +31,7 @@
.collapsing, .collapsing,
.collapse.in { .collapse.in {
padding: 5px 10px; padding: 0;
transition: all 0.35s ease; transition: all 0.35s ease;
} }

View File

@@ -122,3 +122,21 @@
top: 1px; top: 1px;
position: relative; position: relative;
} }
.btn-default {
background-color: fade(@redash-gray, 15%);
}
.btn-transparent {
background-color: transparent !important;
}
.btn-default:hover, .btn-default:focus, .btn-default.focus, .btn-default:active, .btn-default.active, .open > .dropdown-toggle.btn-default {
background-color: fade(@redash-gray, 25%);
}
.btn-default:active:hover, .btn-default.active:hover, .open > .dropdown-toggle.btn-default:hover, .btn-default:active:focus, .btn-default.active:focus, .open > .dropdown-toggle.btn-default:focus, .btn-default:active.focus, .btn-default.active.focus, .open > .dropdown-toggle.btn-default.focus {
color: #333;
background-color: fade(@redash-gray, 45%);
}

View File

@@ -7,6 +7,7 @@
} }
.edit-in-place span.editable { .edit-in-place span.editable {
display: inline-block;
cursor: pointer; cursor: pointer;
} }
@@ -23,32 +24,3 @@
.edit-in-place { .edit-in-place {
display: inline-block; display: inline-block;
} }
.edit-in-place {
.rd-form-control {
padding: 0px 6px;
width: 30vw;
}
&.active {
textarea.rd-form-control {
height: 29px;
width: 40vw;
}
}
}
@media (max-width: 880px) {
.edit-in-place {
.rd-form-control {
width: 50vw;
}
&.active {
textarea.rd-form-control {
width: 50vw;
}
}
}
}

View File

@@ -1,9 +1,9 @@
label { label {
font-weight: 500; font-weight: 500;
} }
textarea.v-resizable { textarea.v-resizable {
resize: vertical; resize: vertical;
} }
.form-group { .form-group {
@@ -29,282 +29,266 @@ textarea.v-resizable {
} }
} }
/* light version of bootstrap's form-control */
.rd-form-control {
display: block;
padding: 6px 12px;
line-height: 1.428571429;
color: #555555;
vertical-align: middle;
background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 4px;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
width: 90%;
}
/* -------------------------------------------------------- /* --------------------------------------------------------
Input Fields Input Fields
-----------------------------------------------------------*/ -----------------------------------------------------------*/
.form-control { .form-control {
.transition(all); .transition(all);
.transition-duration(300ms); .transition-duration(300ms);
resize: none; resize: none;
box-shadow: 0 0 0 40px rgba(0, 0, 0, 0) !important; box-shadow: 0 0 0 40px rgba(0, 0, 0, 0) !important;
border-radius: 0; border-radius: @redash-input-radius;
&:focus { &:focus {
box-shadow: 0 0 1px -2px rgba(121,194,255,0.5) !important; box-shadow: none !important;
} border-color: @blue;
}
&:hover {
border-color: @blue;
}
} }
/* -------------------------------------------------------- /* --------------------------------------------------------
Custom Checkbox + Radio Custom Checkbox + Radio
-----------------------------------------------------------*/ -----------------------------------------------------------*/
.cra-validatation(@color) { .cra-validatation(@color) {
input[type="checkbox"], input[type="radio"] { input[type="checkbox"],
& + .input-helper { input[type="radio"] {
border-color: @color; & + .input-helper {
} border-color: @color;
&:checked + .input-helper:before {
background: @color;
}
} }
&:checked + .input-helper:before {
background: @color;
}
}
} }
.cr-alt { .cr-alt {
position: relative;
padding-top: 0;
margin: 0;
label {
position: relative; position: relative;
padding-top: 0; padding-left: 28px;
}
&.has-success {
.cra-validatation(@green);
}
&.has-warning {
.cra-validatation(@orange);
}
&.has-error {
.cra-validatation(@red);
}
input[type="checkbox"],
input[type="radio"] {
.opacity(0);
width: 20px;
height: 20px;
position: absolute;
z-index: 10;
margin: 0; margin: 0;
top: 0;
left: 0;
cursor: pointer;
label { & + .input-helper {
position: relative; border: 1px solid @input-border;
padding-left: 28px; width: 19px;
height: 19px;
background: #fff;
position: absolute;
left: 0;
top: -1px;
cursor: pointer;
} }
&.has-success { &:checked + .input-helper:before {
.cra-validatation(@green); content: "";
width: 9px;
height: 9px;
background: #31acff;
position: absolute;
left: 4px;
top: 4px;
}
}
input[type="radio"] {
& + i {
border-radius: 50%;
} }
&.has-warning { &:checked + i:before {
.cra-validatation(@orange); border-radius: 50%;
} }
}
&.has-error { &.disabled {
.cra-validatation(@red); .opacity(0.7);
}
}
input[type="checkbox"], input[type="radio"] {
.opacity(0);
width: 20px;
height: 20px;
position: absolute;
z-index: 10;
margin: 0;
top: 0;
left: 0;
cursor: pointer;
& + .input-helper {
border: 1px solid @input-border;
width: 19px;
height: 19px;
background: #fff;
position: absolute;
left: 0;
top: -1px;
cursor: pointer;
}
&:checked + .input-helper:before {
content: "";
width: 9px;
height: 9px;
background: #31ACFF;
position: absolute;
left: 4px;
top: 4px;
}
}
input[type="radio"] {
& + i {
border-radius: 50%;
}
&:checked + i:before {
border-radius: 50%;
}
}
&.disabled {
.opacity(0.7);
}
} }
.checkbox-inline, .checkbox-inline,
.radio-inline { .radio-inline {
padding-left: 27px; padding-left: 27px;
} }
/* -------------------------------------------------------- /* --------------------------------------------------------
Input Addon Input Addon
-----------------------------------------------------------*/ -----------------------------------------------------------*/
.input-group { .input-group {
.input-group-addon {
min-width: 40px;
color: #333;
padding: 0;
}
&:not([class*="input-group-"]) {
.input-group-addon { .input-group-addon {
min-width: 40px; font-size: 15px;
color: #333;
padding: 0;
}
&:not([class*="input-group-"]) {
.input-group-addon {
font-size: 15px;
}
} }
}
} }
/* -------------------------------------------------------- /* --------------------------------------------------------
Toggle Switch Toggle Switch
-----------------------------------------------------------*/ -----------------------------------------------------------*/
.ts-color(@color){ .ts-color(@color) {
input { input {
&:not(:disabled) { &:not(:disabled) {
&:checked { &:checked {
& + .ts-helper { & + .ts-helper {
background: fade(@color, 50%); background: fade(@color, 50%);
&:before { &:before {
background: @color; background: @color;
} }
&:active { &:active {
&:before { &:before {
box-shadow: 0 2px 8px rgba(0,0,0,0.28), 0 0 0 20px fade(@color, 20%); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px fade(@color, 20%);
}
}
}
} }
}
} }
}
} }
}
} }
.toggle-switch { .toggle-switch {
display: inline-block;
vertical-align: top;
.user-select(none);
.ts-label {
display: inline-block; display: inline-block;
margin: 0 20px 0 0;
vertical-align: top; vertical-align: top;
.user-select(none); -webkit-transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);
transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);
}
.ts-label { .ts-helper {
display: inline-block; display: inline-block;
margin: 0 20px 0 0; position: relative;
vertical-align: top; width: 40px;
-webkit-transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1); height: 16px;
transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1); border-radius: 8px;
background: rgba(0, 0, 0, 0.26);
-webkit-transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
vertical-align: middle;
cursor: pointer;
&:before {
content: "";
position: absolute;
top: -4px;
left: -4px;
width: 24px;
height: 24px;
background: #fafafa;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
border-radius: 50%;
webkit-transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
} }
}
&:not(.disabled) {
.ts-helper { .ts-helper {
display: inline-block; &:active {
position: relative;
width: 40px;
height: 16px;
border-radius: 8px;
background: rgba(0,0,0,0.26);
-webkit-transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
vertical-align: middle;
cursor: pointer;
&:before { &:before {
content: ''; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(128, 128, 128, 0.1);
position: absolute;
top: -4px;
left: -4px;
width: 24px;
height: 24px;
background: #fafafa;
box-shadow: 0 2px 8px rgba(0,0,0,0.28);
border-radius: 50%;
webkit-transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
} }
}
} }
}
&:not(.disabled) { input {
.ts-helper { position: absolute;
&:active { z-index: 1;
&:before { width: 46px;
box-shadow: 0 2px 8px rgba(0,0,0,0.28), 0 0 0 20px rgba(128,128,128,0.1); margin: 0 0 0 -4px;
} height: 24px;
} .opacity(0);
cursor: pointer;
&:checked {
& + .ts-helper {
&:before {
left: 20px;
} }
}
} }
}
input { &:not([data-ts-color]) {
position: absolute; .ts-color(@teal);
z-index: 1; }
width: 46px;
margin: 0 0 0 -4px;
height: 24px;
.opacity(0);
cursor: pointer;
&:checked { &.disabled {
& + .ts-helper { .opacity(0.6);
&:before { }
left: 20px;
}
}
}
}
&:not([data-ts-color]){ &[data-ts-color="red"] {
.ts-color(@teal); .ts-color(@red);
} }
&.disabled { &[data-ts-color="blue"] {
.opacity(0.6); .ts-color(@blue);
} }
&[data-ts-color="red"] { &[data-ts-color="amber"] {
.ts-color(@red); .ts-color(@amber);
} }
&[data-ts-color="blue"] { &[data-ts-color="purple"] {
.ts-color(@blue); .ts-color(@purple);
} }
&[data-ts-color="amber"] { &[data-ts-color="pink"] {
.ts-color(@amber); .ts-color(@pink);
} }
&[data-ts-color="purple"] { &[data-ts-color="lime"] {
.ts-color(@purple); .ts-color(@lime);
} }
&[data-ts-color="pink"] { &[data-ts-color="cyan"] {
.ts-color(@pink); .ts-color(@cyan);
} }
&[data-ts-color="lime"] {
.ts-color(@lime);
}
&[data-ts-color="cyan"] {
.ts-color(@cyan);
}
&[data-ts-color="green"] {
.ts-color(@green);
}
&[data-ts-color="green"] {
.ts-color(@green);
}
} }

View File

@@ -76,6 +76,8 @@
.font-size(20, 8px, 8); .font-size(20, 8px, 8);
.f-inherit { font-size: inherit !important; }
/* -------------------------------------------------------- /* --------------------------------------------------------
Font Weight Font Weight
@@ -153,4 +155,10 @@
/* -------------------------------------------------------- /* --------------------------------------------------------
Border Radius Border Radius
-----------------------------------------------------------*/ -----------------------------------------------------------*/
.brd-2 { border-radius: 2px; } .brd-2 { border-radius: 2px; }
/* --------------------------------------------------------
Alignment
-----------------------------------------------------------*/
.va-top { vertical-align: top; }

View File

@@ -1,28 +0,0 @@
/* angular-growl */
.growl {
position: fixed;
bottom: 10px;
right: 10px;
float: right;
width: 250px;
z-index: 10000;
}
.growl-item.ng-enter,
.growl-item.ng-leave {
-webkit-transition: 0.5s linear all;
-moz-transition: 0.5s linear all;
-o-transition: 0.5s linear all;
transition: 0.5s linear all;
}
.growl-item.ng-enter,
.growl-item.ng-leave.ng-leave-active {
opacity: 0;
}
.growl-item.ng-leave,
.growl-item.ng-enter.ng-enter-active {
opacity: 1;
}

View File

@@ -1,14 +1,37 @@
.label { .label {
border-radius: 1px; border-radius: 2px;
padding: 4px 5px 3px; padding: 3px 6px 4px;
} font-weight: 500;
font-size: 11px;
h1, h2, h3, h4, h5, h6 {
.label {
border-radius: 2px;
}
} }
.badge { .badge {
border-radius: 1px; border-radius: 1px;
}
.label-default {
background: fade(@redash-gray, 85%);
}
.label-tag-unpublished {
background: fade(@redash-gray, 85%);
}
.label-tag-archived {
.label-warning();
}
.label-tag {
background: fade(@redash-gray, 10%);
color: fade(@redash-gray, 75%);
}
.label-tag-unpublished,
.label-tag-archived,
.label-tag {
margin-right: 3px;
display: inline;
margin-top: 2px;
max-width: 24ch;
.text-overflow();
} }

View File

@@ -17,20 +17,6 @@
} }
} }
tags-list {
a {
line-height: 1.1;
}
}
.tags-list__name {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
width: 88%;
line-height: 1.3;
}
.max-character { .max-character {
.text-overflow(); .text-overflow();
} }
@@ -45,6 +31,11 @@ tags-list {
line-height: 100%; line-height: 100%;
margin-top: 2px; margin-top: 2px;
} }
&.active, &.active:hover, &.active:focus {
background-color: #fff;
box-shadow: inset 3px 0px 0px @brand-primary;
}
} }
.list-group-item-heading { .list-group-item-heading {
@@ -76,3 +67,18 @@ tags-list {
height: 38px; height: 38px;
border-radius: 2px; border-radius: 2px;
} }
.ui-select-choices-row.disabled > span {
background-color: inherit !important;
}
.list-group-item.inactive,
.ui-select-choices-row.disabled {
background-color: #eee !important;
border-color: transparent;
opacity: 0.5;
box-shadow: none;
color: #333;
pointer-events: none;
cursor: not-allowed;
}

View File

@@ -234,4 +234,9 @@
.hide-in-percy, .pace { .hide-in-percy, .pace {
visibility: hidden; visibility: hidden;
} }
// hide tooltips in Percy
.ant-tooltip {
display: none !important;
}
} }

View File

@@ -1,32 +0,0 @@
a.navbar-brand {
padding: 5px 5px 0px 0px;
}
.navbar .fa {
font-size: 18px;
}
.navbar .collapse.in {
background: #222;
}
a.navbar-brand img {
height: 40px;
}
.avatar {
margin-top: 5px;
margin-bottom: 5px;
}
.avatar img {
width: 40px;
height: 40px;
}
#logout {
color: white;
position: relative;
left: -9px;
bottom: -11px;
}

View File

@@ -1,11 +0,0 @@
.overlay {
background-color: #808080;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
padding: 0;
z-index: 1000;
opacity: 0.8;
}

View File

@@ -1,54 +0,0 @@
.pagination {
border-radius: 0;
& > li {
margin: 0 2px;
display: inline-block;
vertical-align: top;
& > a,
& > span {
border-radius: 50% !important;
padding: 0;
width: 40px;
height: 40px;
line-height: 38px;
text-align: center;
font-size: 14px;
z-index: 1;
position: relative;
& > .zmdi {
font-size: 22px;
line-height: 39px;
}
}
&.disabled {
.opacity(0.5);
}
}
}
/* --------------------------------------------------------
Listview Pagination
-----------------------------------------------------------*/
.lv-pagination {
width: 100%;
text-align: center;
padding: 40px 0;
border-top: 1px solid #F0F0F0;
margin-top: 0;
margin-bottom: 0;
}
/* --------------------------------------------------------
Pager
-----------------------------------------------------------*/
.pager li > a, .pager li > span {
padding: 5px 10px 6px;
color: @pagination-color;
}

View File

@@ -1,5 +1,5 @@
.popover { .popover {
box-shadow: 0 2px 30px rgba(0, 0, 0, 0.2); box-shadow: fade(@redash-gray, 25%) 0px 0px 15px 0px;
} }
.popover-title { .popover-title {

View File

@@ -6,6 +6,7 @@ div.table-name {
padding: 2px 22px 2px 10px; padding: 2px 22px 2px 10px;
border-radius: @redash-radius; border-radius: @redash-radius;
position: relative; position: relative;
height: 22px;
.copy-to-editor { .copy-to-editor {
display: none; display: none;
@@ -27,10 +28,18 @@ div.table-name {
} }
.schema-browser { .schema-browser {
overflow-y: auto; overflow: hidden;
overflow-x: hidden;
border: none; border: none;
margin-top: 10px; padding-top: 10px;
position: relative;
height: 100%;
.schema-loading-state {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.collapse.in { .collapse.in {
background: transparent; background: transparent;
@@ -55,6 +64,14 @@ div.table-name {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
position: relative; position: relative;
height: 18px;
.column-type {
color: fade(@text-color, 80%);
font-size: 10px;
margin-left: 2px;
text-transform: uppercase;
}
.copy-to-editor { .copy-to-editor {
display: none; display: none;
@@ -72,11 +89,12 @@ div.table-name {
.schema-control { .schema-control {
display: flex; display: flex;
flex-wrap: nowrap;
padding: 0; padding: 0;
.form-control { .ant-btn {
margin-right: 5px; height: auto;
} }
} }
.parameter-label { .parameter-label {

View File

@@ -1,140 +0,0 @@
.tab-nav {
list-style: none;
padding: 0;
white-space: nowrap;
margin: 0 0 10px 0;
overflow: auto;
box-shadow: inset 0 -2px 0 0 #eee;
& > li {
display: inline-block;
vertical-align: top;
& > a {
display: inline-block;
color: #7a7a7a;
text-transform: uppercase;
position: relative;
width: 100%;
font-weight: 500;
&:after {
content: "";
height: 2px;
position: absolute;
width: 100%;
left: 0;
bottom: 0;
display: none;
}
@media (min-width: @screen-sm-min) {
padding: 15px;
}
@media (max-width: @screen-sm-min) {
padding: 15px 8px;
}
}
&.active {
& > a {
color: #000;
&:after {
display: block;
}
}
}
}
&.tab-nav-right {
text-align: right;
}
&.tn-justified {
& > li {
display: table-cell;
width: 1%;
text-align: center;
}
}
&.tn-icon {
& > li {
.zmdi {
font-size: 22px;
line-height: 100%;
min-height: 25px;
}
}
}
&:not([data-tab-color]) {
& > li > a:after {
background: @blue;
}
}
&[data-tab-color="green"] {
& > li > a:after {
background: @green;
}
}
&[data-tab-color="red"] {
& > li > a:after {
background: @red;
}
}
&[data-tab-color="teal"] {
& > li > a:after {
background: @teal;
}
}
&[data-tab-color="amber"] {
& > li > a:after {
background: @amber;
}
}
&[data-tab-color="black"] {
& > li > a:after {
background: @black;
}
}
&[data-tab-color="cyan"] {
& > li > a:after {
background: @cyan;
}
}
}
.tab-content {
padding: 20px 0;
}
.rd-tab {
.remove {
cursor: pointer;
color: #A09797;
padding: 0 3px 1px 4px;
font-size: 11px;
&:hover {
color: white;
background-color: #FF8080;
border-radius: 50%;
}
}
}
.tab-nav {
> li.rd-tab-btn {
float: right;
padding-right: 10px;
padding-top: 10px;
}
}

View File

@@ -1,99 +1,153 @@
.table { .table {
margin-bottom: 0; margin-bottom: 0;
th.sortable-column { th.sortable-column {
cursor: pointer; cursor: pointer;
}
&:not(.table-striped) > thead > tr > th {
background-color: #fafafa;
}
[class*="bg-"] {
& > tr > th {
color: #fff;
border-bottom: 0;
background: transparent !important;
} }
&:not(.table-striped) > thead > tr > th { & + tbody > tr:first-child > td {
background-color: #FAFAFA; border-top: 0;
} }
}
[class*="bg-"] { & > thead > tr > th {
& > tr > th { vertical-align: middle;
color: #fff; font-weight: 500;
border-bottom: 0; color: #333;
background: transparent !important; border-width: 1px;
} text-transform: uppercase;
padding: 15px 10px;
}
& + tbody > tr:first-child > td { & > thead > tr,
border-top: 0; & > tbody > tr,
} & > tfoot > tr {
& > th,
& > td {
&:first-child {
padding-left: 30px;
}
&:last-child {
padding-right: 30px;
}
} }
}
& > thead > tr > th { tbody > tr:last-child > td {
vertical-align: middle; padding-bottom: 20px;
font-weight: 500; }
color: #333;
border-width: 1px;
text-transform: uppercase;
padding: 15px 10px;
}
& > thead > tr,
& > tbody > tr,
& > tfoot > tr {
& > th, & > td {
&:first-child {
padding-left: 30px;
}
&:last-child {
padding-right: 30px;
}
}
}
tbody > tr:last-child > td {
padding-bottom: 20px;
}
} }
.table-bordered { .table-bordered {
border: 0; border: 0;
& > tbody > tr { & > tbody > tr {
& > td, & > th { & > td,
border-bottom: 0; & > th {
border-left: 0; border-bottom: 0;
border-left: 0;
&:last-child { &:last-child {
border-right: 0; border-right: 0;
} }
}
} }
}
& > thead > tr > th { & > thead > tr > th {
border-left: 0; border-left: 0;
&:last-child { &:last-child {
border-right: 0; border-right: 0;
}
} }
}
} }
.table-vmiddle { .table-vmiddle {
td { td {
vertical-align: middle !important; vertical-align: middle !important;
} }
} }
.table-responsive { .table-responsive {
border: 0; border: 0;
} }
.tile .table { .tile .table {
& > thead:not([class*="bg-"]) > tr > th {
& > thead:not([class*="bg-"]) > tr > th { border-top: 1px solid @table-border-color;
border-top: 1px solid @table-border-color; }
}
} }
.table-hover > tbody > tr:hover { .table-hover > tbody > tr:hover {
background-color: #f4f4f4; background-color: #f4f4f4;
} }
.table-data {
thead > tr > th {
white-space: nowrap;
}
tbody > tr > td {
padding-top: 5px !important;
}
.btn-favourite,
.btn-archive {
font-size: 15px;
}
}
.table-main-title {
font-weight: 500;
line-height: 1.7 !important;
}
.btn-favourite {
color: #d4d4d4;
transition: all 0.25s ease-in-out;
&:hover,
&:focus {
color: @yellow-darker;
cursor: pointer;
}
.fa-star {
color: @yellow-darker;
}
}
.btn-archive {
color: #d4d4d4;
transition: all 0.25s ease-in-out;
&:hover,
&:focus {
color: @gray-light;
}
.fa-archive {
color: @gray-light;
}
}
.table > thead > tr > th {
text-transform: none;
}
.table-data .label-tag {
display: inline-block;
max-width: 135px;
}

View File

@@ -2,7 +2,8 @@
background-color: #fff; background-color: #fff;
margin-bottom: @grid-gutter-width; margin-bottom: @grid-gutter-width;
position: relative; position: relative;
box-shadow: @tile-shadow; border-radius: 3px;
box-shadow: fade(@redash-gray, 15%) 0px 4px 9px -3px;
&[class*="bg-"] { &[class*="bg-"] {
color: #fff; color: #fff;
@@ -12,6 +13,10 @@
margin-bottom: @grid-gutter-width/2; margin-bottom: @grid-gutter-width/2;
} }
} }
.tiled {
border-radius: 3px;
box-shadow: fade(@redash-gray, 15%) 0px 4px 9px -3px;
}
.t-header { .t-header {
.th-title { .th-title {
@@ -74,6 +79,15 @@
} }
} }
.t-header:not(.th-alt) {
padding: 15px;
ul {
margin-bottom: 0;
line-height: 2.2;
}
}
.tb-padding { .tb-padding {
padding: 20px 23px 30px; padding: 20px 23px 30px;
} }

View File

@@ -1,29 +0,0 @@
#toast-container .toast {
margin: 0 6px 6px 0;
box-shadow: none;
color: #ffffff;
opacity: 0.75;
border-radius: 2px;
transition: opacity 0.35s ease-in-out;
}
#toast-container .toast:hover {
box-shadow: none;
opacity: 1;
cursor: pointer;
}
.toast {
background-color: #030303;
}
.toast-success {
background-color: #3BD973;
}
.toast-error {
background-color: #E92828;
}
.toast-info {
background-color: #356AFF;
}
.toast-warning {
background-color: #FB8D3D;
}

View File

@@ -23,6 +23,8 @@
@logo-height: @header-height; @logo-height: @header-height;
@boxed-width: 1170px; @boxed-width: 1170px;
@body-bg: #edecec; @body-bg: #edecec;
@spacing: 15px;
@redash-radius: 3px;
/* -------------------------------------------------------- /* --------------------------------------------------------
@@ -39,6 +41,7 @@
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@font-icon: 'Material-Design-Iconic-Font'; @font-icon: 'Material-Design-Iconic-Font';
@font-family-sans-serif: 'Roboto', sans-serif; @font-family-sans-serif: 'Roboto', sans-serif;
@redash-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
@font-size-base: 13px; @font-size-base: 13px;
@@ -59,6 +62,7 @@
@input-border: #e8e8e8; @input-border: #e8e8e8;
@input-border-radius: 0; @input-border-radius: 0;
@input-border-radius-large: 0px; @input-border-radius-large: 0px;
@redash-input-radius: 2px;
@input-height-large: 40px; @input-height-large: 40px;
@input-height-base: 35px; @input-height-base: 35px;
@input-height-small: 30px; @input-height-small: 30px;
@@ -94,6 +98,11 @@
@gray-light: #828282; @gray-light: #828282;
@ace: #f8f8f8; @ace: #f8f8f8;
@redash-gray: rgba(102, 136, 153, 1);
@redash-orange: rgba(255, 120, 100, 1);
@redash-black: rgba(0, 0, 0, 1);
@redash-yellow: rgba(252, 252, 161, 0.75);
/** Form States **/ /** Form States **/
@state-success-text: @green; @state-success-text: @green;
@state-info-text: @blue; @state-info-text: @blue;
@@ -192,7 +201,6 @@
@pagination-hover-color: #333; @pagination-hover-color: #333;
@pagination-hover-bg: #d7d7d7; @pagination-hover-bg: #d7d7d7;
@pagination-hover-border: @pagination-border; @pagination-hover-border: @pagination-border;
@pager-border-radius: 5px;
/* -------------------------------------------------------- /* --------------------------------------------------------

View File

@@ -1,125 +0,0 @@
.bootgrid-table {
margin: 0;
box-shadow: none;
}
.bootgrid-footer .infoBar,
.bootgrid-header .actionBar {
text-align: left;
}
.bootgrid-footer .search,
.bootgrid-header .search {
vertical-align: top;
}
.bootgrid-header {
margin: 0;
padding: 25px;
.search {
border: 1px solid @input-border;
.form-control, .input-group-addon {
border: 0;
}
.input-group-addon {
font-size: 18px;
color: #333;
padding-right: 0 !important;
min-width: 26px;
text-align: right;
}
@media (min-width: @screen-xs-min) {
width: 300px;
}
@media (max-width: @screen-xs-min) {
width: 100%;
padding-right: 90px;
}
}
.actions {
box-shadow: none;
.btn-group {
.btn {
height: 37px;
background: #fff;
border-radius: 0;
border: 1px solid @input-border;
}
.dropdown-menu {
@media (min-width: @screen-sm-min) {
left: 0;
margin-top: 1px;
}
.dropdown-item {
padding: 5px 10px;
.input-helper {
top: 5px;
}
}
}
.caret {
display: none;
}
.zmdi {
line-height: 100%;
font-size: 18px;
vertical-align: top;
}
}
@media (max-width: @screen-xs-min) {
position: absolute;
top: 0;
right: 15px;
}
}
}
.bootgrid-footer {
border-top: 1px solid @table-border-color;
margin-top: 0;
.col-sm-6 {
padding: 25px;
@media (max-width: @screen-sm-min) {
text-align: center;
}
}
.infoBar {
@media (max-width: @screen-sm-min) {
display: none;
}
.infos {
border: 1px solid #EEE;
display: inline-block;
float: right;
padding: 7px 30px;
font-size: 12px;
margin-top: 3px;
}
}
}
.select-cell .checkbox {
margin: 0px 0 0 -19px;
top: 3px;
}

View File

@@ -1,215 +0,0 @@
.bootstrap-datetimepicker-widget {
padding: 0 !important;
margin: 0 !important;
width: auto !important;
&:after, &:before { display: none !important; }
table td {
text-shadow: none;
span {
margin: 0;
&:hover { background: transparent; }
}
}
.glyphicon { font-family: @font-icon; font-size: 18px; }
.glyphicon-chevron-left:before { content: "\f2ff"; }
.glyphicon-chevron-right:before { content: "\f301"; }
.glyphicon-time:before { content: "\f337"; }
.glyphicon-calendar:before { content: "\f32e"; }
.glyphicon-chevron-up:before { content: "\f1e5"; }
.glyphicon-chevron-down:before { content: "\f1e4"; }
[data-action="togglePicker"] span {
font-size: 25px;
color: #ccc;
&:hover {
color: #333;
}
}
a[data-action] {
color: @blue;
}
}
.timepicker-picker {
.btn { box-shadow: none !important; }
table {
tbody tr + tr:not(:last-child) {
background: @blue;
color: #fff;
td {
border-radius: 0;
}
}
}
.btn {
background: #fff;
color: #333;
}
}
.datepicker {
&.top {
.transform-origin(0 100%) !important;
}
table {
thead {
tr {
th {
border-radius: 0;
color: #fff;
.glyphicon {
width: 30px;
height: 30px;
border-radius: 50%;
line-height: 29px;
}
&:hover .glyphicon {
background: rgba(0, 0, 0, 0.2);
}
}
&:first-child {
th {
background: @blue;
padding: 20px 0;
&:hover {
background: @blue;
}
&.picker-switch {
font-size: 16px;
font-weight: 400;
text-transform: uppercase;
}
}
}
&:last-child {
th {
&:first-child { padding-left: 20px; }
&:last-child { padding-right: 20px; }
text-transform: uppercase;
font-weight: normal;
font-size: 11px;
}
&:not(:only-child) {
background: darken(@blue, 3%);
}
}
}
}
tbody {
tr {
&:last-child {
td {
padding-bottom: 25px;
}
}
td {
&:first-child {
padding-left: 13px;
}
&:last-child {
padding-right: 13px;
}
}
}
}
td {
&.day {
width: 35px;
height: 35px;
line-height: 20px;
color: #333;
position: relative;
padding: 0;
background: transparent;
&:hover {
background: none;
}
&:before {
content: "";
width: 35px;
height: 35px;
border-radius: 50%;
margin-bottom: -33px;
display: inline-block;
background: transparent;
position: static;
text-shadow: none;
}
&.old, &.new {
color: #CDCDCD;
}
}
&:not(.today):not(.active) {
&:hover:before {
background: #F0F0F0;
}
}
&.today {
color: #333;
&:before {
background-color: #E2E2E2;
}
}
&.active {
color: #fff;
&:before {
background-color: @blue;
}
}
}
}
}
.datepicker-months .month,
.datepicker-years .year,
.timepicker-minutes .minute,
.timepicker-hours .hour {
border-radius: 50%;
&:not(.active) {
&:hover {
background: #F0F0F0;
}
}
&.active {
background: @blue;
}
}
.timepicker-minutes .minute,
.timepicker-hours .hour {
padding: 0;
}

View File

@@ -1,72 +0,0 @@
.bootstrap-select {
.bs-searchbox {
padding: 0 18px;
margin: 5px 0 10px;
position: relative;
&:before {
position: absolute;
left: 14px;
top: 2px;
width: 30px;
height: 100%;
content: "\f1c3";
font-family: @font-icon;
font-size: 25px;
}
input {
padding-left: 25px;
border: 0;
}
}
&.btn-group {
.dropdown-menu li a.opt {
padding-left: 17px;
}
}
.check-mark {
margin-top: -5px !important;
font-size: 19px;
display: none;
position: absolute;
top: 11px;
right: 15px;
&:before {
content: "\f26b";
font-family: @font-icon;
}
}
.selected {
.check-mark {
display: block !important;
}
}
.notify {
bottom: 0 !important;
margin: 0 !important;
width: 100% !important;
border: 0 !important;
background: @red !important;
color: #fff !important;
text-align: center;
}
&:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 100%;
}
.btn-default {
background-color: #fff;
border-radius: 0;
border: 1px solid @input-border;
}
}

View File

@@ -1,114 +0,0 @@
.chosen-container {
.chosen-drop {
border-color: @input-border;
border-radius: 0;
}
.chosen-results {
margin: 10px 0 0 0;
padding: 0;
li {
padding: 10px 17px;
width: 100%;
&.highlighted {
background: @dropdown-link-hover-bg;
color: @dropdown-link-hover-color;
}
&.result-selected {
background: @lightblue;
color: @white;
position: relative;
&:before {
content: "\f26b";
font-family: @font-icon;
position: absolute;
right: 15px;
top: 10px;
font-size: 19px;
}
}
&.group-result {
&:not(:first-child) {
border-top: 1px solid #eee;
}
color: #B2B2B2;
font-weight: normal;
padding: 16px 15px 6px;
margin-top: 9px;
}
}
}
}
.chosen-container-single {
.chosen-single {
border-radius: 0;
height: 35px;
padding: 7px 12px 6px;
line-height: 1.42857143;
border-color: @input-border;
}
.chosen-search {
padding: 5px 12px;
&:before {
content: "\f1c3";
font-family: @font-icon;
position: absolute;
left: 25px;
top: 9px;
font-size: 19px;
}
input[type=text] {
border-color: @input-border;
padding: 8px 10px 8px 35px;
}
}
}
.chosen-container-multi {
.chosen-choices {
padding: 0 4px;
border-color: @input-border;
li {
&.search-choice {
border-radius: 0;
margin: 4px 4px 0 0;
background: @blue;
border-color: @blue;
color: #fff;
padding: 5px 23px 5px 8px;
.search-choice-close {
&:before {
display: inline-block;
font-family: @font-icon;
content: "\f135";
position: relative;
top: 1px;
color: #fff;
z-index: 2;
font-size: 12px;
}
}
}
&.search-field {
input[type=text] {
padding: 0 8px;
height: 31px;
}
}
}
}
}

View File

@@ -1,25 +0,0 @@
.cp-container {
position: relative;
& > .input-group {
input.cp-value {
color: #000 !important;
background: transparent !important;
}
.dropdown-menu {
padding: 20px;
margin-top: 30px;
}
}
i.cp-value {
width: 25px;
height: 25px;
border-radius: 50%;
position: absolute;
top: 5px;
right: 5px;
}
}

View File

@@ -1,51 +0,0 @@
.fileinput {
position: relative;
padding-right: 35px;
.close {
position: absolute;
top: 5px;
font-size: 12px;
float: none;
opacity: 1;
font-weight: 500;
border: 1px solid #ccc;
width: 19px;
text-align: center;
height: 19px;
line-height: 15px;
border-radius: 50%;
right: 0;
&:hover {
background: #eee;
}
}
.btn-file {
}
.input-group-addon {
padding: 0 10px;
vertical-align: middle;
}
.fileinput-preview {
width: 200px;
height: 150px;
position: relative;
img {
display: inline-block;
vertical-align: middle;
margin-top: -13px;
}
&:after {
content: "";
display: inline-block;
vertical-align: middle;
}
}
}

View File

@@ -1,207 +0,0 @@
/** CALENDAR WIDGET **/
#calendar-widget {
margin-bottom: 30px;
box-shadow: 0 1px 1px rgba(0,0,0,.15);
}
#fc-actions {
position: absolute;
bottom: 23px;
right: 22px;
& > li > a {
font-size: 20px;
color: #fff;
width: 30px;
height: 30px;
border-radius: 50%;
line-height: 30px;
}
& > li.open > a,
& > li > a:hover {
background: darken(@teal, 7%);
}
}
.fc {
background-color: #fff;
margin-bottom: 20px;
td {
border-color: @table-border-color !important;
}
th {
background: darken(@teal, 7%);
color: #fff;
font-weight: 400;
padding: 6px 0;
}
table tr {
& > td:first-child {
border-left-width: 0;
}
}
.ui-widget-header {
border-width: 0;
}
.fc-day-number {
color: #CCC;
}
.fc-event-container {
padding: 0 2px 2px;
}
}
.fc-toolbar {
background: @teal;
margin-bottom: 0;
padding: 25px 7px 25px;
position: relative;
.user-select(none);
&:before {
content: "";
bottom: -30px;
height: 30px;
width: 100%;
background: darken(@teal, 7%);
position: absolute;
left: 0;
z-index: 0;
}
h2 {
color: rgba(255, 255, 255, 0.9);
margin-top: 7px;
font-size: 19px;
font-weight: 400;
}
.ui-button {
border: 0;
background: 0 0;
padding: 0;
outline: none !important;
text-align: center;
& > span {
position: relative;
font-family: @font-icon;
font-size: 20px;
color: #FFF;
line-height: 100%;
width: 31px;
height: 31px;
border-radius: 50%;
padding-top: 6px;
display: block;
margin-top: 2px;
&:before {
position: relative;
z-index: 1;
}
&.ui-icon-circle-triangle-w:before {
content: "\f2fa";
}
&.ui-icon-circle-triangle-e:before {
content: "\f2fb";
}
&:hover {
background: darken(@teal, 7%);
color: #fff;
}
}
}
}
.fc-event {
padding: 0;
font-size: 11px;
border-radius: 0;
border: 0;
.fc-title {
padding: 3px 5px 2px;
display: block;
}
.fc-time {
float: left;
background: rgba(0, 0, 0, 0.2);
padding: 2px 6px;
margin: 0 0 0 -1px;
}
}
.fc-view, .fc-view > table {
border: 0;
overflow: hidden;
}
.fc-content-skeleton {
table {
background: transparent;
}
}
#calendar {
.fc-day-number {
@media screen and (min-width: @screen-sm-max) {
font-size: 25px;
letter-spacing: -2px;
}
padding-left: 10px !important;
text-align: left !important;
}
}
/* Even Tag Color */
.event-tag {
margin-top: 5px;
& > span {
border-radius: 50%;
width: 30px;
height: 30px;
margin-right: 3px;
position: relative;
display: inline-block;
cursor: pointer;
&:hover {
.opacity(0.8);
}
&.selected {
&:before {
font-family: @font-icon;
content: "\f26b";
position: absolute;
text-align: center;
top: 3px;
width: 100%;
font-size: 17px;
color: #FFF;
}
}
}
}
/* Height Fix */
.fc-day-grid-container {
height: auto !important;
}

View File

@@ -1,69 +0,0 @@
.lg-outer .lg-item {
background-image: none;
}
.lg-slide {
&:after {
content: "";
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
height: 50px;
width: 50px;
border-radius: 100%;
border: 2px solid @white;
-webkit-animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);
animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);
position: absolute;
left: 50%;
margin-left: -25px;
top: 50%;
margin-top: -25px;
z-index: -1;
}
em {
font-style: normal;
display: block;
margin-bottom: 20px;
h3 {
margin-bottom: 5px;
color: #D2D2D2;
font-weight: 100;
}
p {
color: #6B6B6B;
}
}
}
@-webkit-keyframes ball-scale-ripple {
0% {
-webkit-transform: scale(0.1);
transform: scale(0.1);
opacity: 1; }
70% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 0.7; }
100% {
opacity: 0.0; }
}
@keyframes ball-scale-ripple {
0% {
-webkit-transform: scale(0.1);
transform: scale(0.1);
opacity: 1; }
70% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 0.7; }
100% {
opacity: 0.0; }
}

View File

@@ -1,25 +0,0 @@
.mCSB_container,
.mCustomScrollBox {
overflow: visible;
}
.mCSB_scrollTools {
width: 12px;
.mCSB_draggerRail,
.mCSB_dragger .mCSB_dragger_bar {
border-radius: 0;
}
.mCSB_draggerRail {
background: transparent !important;
}
}
.mCS-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
background: rgba(0,0,0,0.4);
}
.mCSB_inside > .mCSB_container {
margin-right: 0;
}

View File

@@ -1,172 +0,0 @@
.noUi-target {
border-radius: 0;
box-shadow: none;
border: 0;
}
.noUi-background {
background: #d4d4d4;
box-shadow: none;
}
.noUi-horizontal {
height: 3px;
.noUi-handle {
top: -8px;
}
}
.noUi-vertical {
width: 3px;
}
.noUi-horizontal,
.noUi-vertical {
.noUi-handle {
width: 19px;
height: 19px;
border: 0;
border-radius: 100%;
box-shadow: none;
.transition(box-shadow);
.transition-duration(200ms);
cursor: pointer;
position: relative;
&:before,
&:after {
display: none;
}
&:active {
background: #ccc !important;
}
.is-tooltip {
position: absolute;
bottom: 32px;
height: 35px;
border-radius: 2px;
color: #fff;
text-align: center;
line-height: 33px;
width: 50px;
left: 50%;
margin-left: -25px;
padding: 0 10px;
.transition(all);
.transition-duration(200ms);
.backface-visibility(hidden);
.opacity(0);
.scale(0);
&:after {
width: 0;
height: 0;
border-style: solid;
border-width: 15px 10px 0 10px;
position: absolute;
bottom: -8px;
left: 50%;
margin-left: -9px;
content: "";
}
}
}
.noUi-active {
box-shadow: 0 0 0 13px rgba(0,0,0,0.1);
.is-tooltip {
.scale(1);
bottom: 40px;
.opacity(1);
}
}
}
.input-slider,
.input-slider-range,
.input-slider-values {
&:not([data-is-color]) {
.noUi-handle,
.noUi-connect, {
background: @teal !important;
}
.is-tooltip {
background: @teal;
&:after {
border-color: @teal transparent transparent transparent;
}
}
}
&[data-is-color=red] {
.is-color-handle(@red);
}
&[data-is-color=blue] {
.is-color-handle(@blue);
}
&[data-is-color=cyan] {
.is-color-handle(@cyan);
}
&[data-is-color=amber] {
.is-color-handle(@amber);
}
&[data-is-color=green] {
.is-color-handle(@green);
}
}
.input-slider {
.noUi-origin {
background: #d4d4d4;
}
&:not([data-is-color]) {
.noUi-base {
background: @teal !important;
}
}
&[data-is-color=red] {
.is-color-base(@red);
}
&[data-is-color=blue] {
.is-color-base(@blue);
}
&[data-is-color=cyan] {
.is-color-base(@cyan);
}
&[data-is-color=amber] {
.is-color-base(@amber);
}
&[data-is-color=green] {
.is-color-base(@green);
}
}
.is-color-handle(@color) {
.noUi-handle,
.noUi-connect {
background: @color !important;
}
}
.is-color-base(@color) {
.noUi-base {
background: @color !important;
}
}

View File

@@ -1,194 +0,0 @@
.note-editor,
.note-popover {
.note-toolbar,
.popover-content {
background: #fff;
border-color: #e4e4e4;
margin: 0;
padding: 10px 0 15px;
text-align: center;
& > .btn-group {
display: inline-block;
float: none;
box-shadow: none;
.btn {
margin: 0 1px;
border: 0;
}
& > .active {
background: @cyan;
color: #fff;
}
}
.btn {
height: 40px;
border-radius: 2px !important;
box-shadow: none !important;
background: #fff;
&:active {
box-shadow: none;
}
}
.note-palette-title {
margin: 0 !important;
padding: 10px 0 !important;
font-size: 13px !important;
text-align: center !important;
border: 0 !important;
}
.note-color-reset {
padding: 0 0 10px !important;
margin: 0 !important;
background: none;
text-align: center;
}
.note-color {
.dropdown-menu {
min-width: 335px;
}
}
}
.note-statusbar {
.note-resizebar {
border-color: #E8E8E8;
.note-icon-bar {
border-color: #BCBCBC;
}
}
}
.fa {
font-style: normal;
font-size: 20px;
vertical-align: middle;
&:before {
font-family: @font-icon;
}
&.fa-magic:before {
content: "\f16a";
}
&.fa-bold:before {
content: "\f23d";
}
&.fa-italic:before {
content: "\f245";
}
&.fa-underline:before {
content: "\f24f";
}
&.fa-font:before {
content: "\f242";
}
&.fa-list-ul:before {
content: "\f247";
}
&.fa-list-ol:before {
content: "\f248";
}
&.fa-align-left:before {
content: "\f23b";
}
&.fa-align-right:before {
content: "\f23c";
}
&.fa-align-center:before {
content: "\f239";
}
&.fa-align-justify:before {
content: "\f23a";
}
&.fa-indent:before {
content: "\f244";
}
&.fa-outdent:before {
content: "\f243";
}
&.fa-text-height:before {
content: "\f246";
}
&.fa-table:before {
content: "\f320";
}
&.fa-link:before {
content: "\f18e";
}
&.fa-picture-o:before {
content: "\f17f";
}
&.fa-minus:before {
content: "\f22f";
}
&.fa-arrows-alt:before {
content: "\f16d";
}
&.fa-code:before {
content: "\f13a";
}
&.fa-question:before {
content: "\f1f5";
}
&.fa-eraser:before {
content: "\f23f";
}
&.fa-square:before {
content: "\f279";
}
&.fa-circle-o:before {
content: "\f26c";
}
&.fa-times:before {
content: "\f136";
}
}
.note-air-popover {
.arrow {
left: 20px;
}
}
}
.note-editor {
border: 1px solid #e4e4e4;
.note-editable {
padding: 20px 23px;
}
}

View File

@@ -1,21 +0,0 @@
.sweet-alert {
border-radius: 2px;
padding: 10px 30px;
h2 {
font-size: 16px;
font-weight: 400;
position: relative;
z-index: 1;
}
.lead {
font-size: 13px;
}
.btn {
padding: 6px 12px;
font-size: 13px;
margin: 20px 2px 0;
}
}

View File

@@ -1,24 +0,0 @@
.twitter-typeahead {
width: 100%;
.tt-menu {
min-width: 200px;
background: #fff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.tt-suggestion:hover,
.tt-cursor {
background-color: rgba(0,0,0,0.075);
}
.tt-suggestion {
padding: 8px 17px;
color: #333;
cursor: pointer;
}
.tt-hint {
color: #818181 !important;
}
}

View File

@@ -1,35 +0,0 @@
/* ui-select adjustments for SuperFlat */
.clearable button {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
/* Same definition as .form-control */
.ui-select-toggle.btn-default {
height: 35px;
padding: 6px 12px;
font-size: 13px;
line-height: 1.42857143;
color: #9E9E9E;
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 2px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
&:hover, &:active, &.active, &:focus, &.focus {
background: #fff;
}
}
.btn-default-focus {
outline: none;
outline-offset: 0;
box-shadow: none;
background: none;
}

View File

@@ -1,28 +0,0 @@
cohort-renderer {
display: block;
}
.cornelius-container {
padding: 0;
margin: 0;
.cornelius-table {
width: 100%;
margin: 0;
box-shadow: none;
border-radius: 0;
background: transparent;
tr, th, td {
border-color: @table-border-color;
}
td {
border-radius: 0 !important;
}
.cornelius-time, .cornelius-label, .cornelius-people {
background-color: fade(@redash-gray, 3%) !important;
}
}
}

View File

@@ -1,45 +0,0 @@
counter-renderer {
display: block;
text-align: center;
padding: 15px 10px;
overflow: hidden;
counter {
margin: 0;
padding: 0;
font-size: 80px;
line-height: normal;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
value,
counter-target {
font-size: 1em;
display: block;
}
counter-name {
font-size: 0.5em;
display: block;
}
&.positive value {
color: #5cb85c;
}
&.negative value {
color: #d9534f;
}
}
counter-target {
color: #ccc;
}
counter-name {
font-size: 0.5em;
display: block;
}
}

View File

@@ -1,15 +0,0 @@
.col-table .missing-value {
color: #b94a48;
}
.col-table .super-small-input {
padding-left: 3px;
height: 24px;
}
.col-table .ui-select-toggle, .col-table .ui-select-search {
padding: 2px;
padding-left: 5px;
height: 24px;
}

View File

@@ -6,32 +6,9 @@
height: 100%; height: 100%;
z-index: 0; z-index: 0;
} }
}
.map-custom-control.leaflet-bar {
background: #fff; .leaflet-popup-content img {
padding: 10px; max-width: 100%;
margin: 10px; height: auto;
position: absolute;
z-index: 1;
&.top-left {
left: 0;
top: 0;
}
&.top-right {
right: 0;
top: 0;
}
&.bottom-left {
left: 0;
bottom: 0;
}
&.bottom-right {
right: 0;
bottom: 0;
}
}
} }

View File

@@ -1,4 +1,4 @@
visualization-renderer { .visualization-renderer {
display: block; display: block;
.pagination, .pagination,

View File

@@ -1,3 +1,4 @@
.pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div { .pivot-table-visualization-container > table,
.visualization-renderer > .visualization-renderer-wrapper {
overflow: auto; overflow: auto;
} }

View File

@@ -1,81 +1,56 @@
/** LESS Plugins **/ /** LESS Plugins **/
@import 'inc/less-plugins/for'; @import "inc/less-plugins/for";
/** Load Main Bootstrap LESS files **/ /** Load Main Bootstrap LESS files **/
@import '~bootstrap/less/bootstrap'; @import "~bootstrap/less/bootstrap";
/** Load Vendors Dependencies **/ /** Load Vendors Dependencies **/
@import '~font-awesome/less/font-awesome'; @import "~font-awesome/less/font-awesome";
@import '~ui-select/dist/select.css'; @import "~material-design-iconic-font/dist/css/material-design-iconic-font.css";
@import '~angular-resizable/src/angular-resizable.css';
@import '~material-design-iconic-font/dist/css/material-design-iconic-font.css';
@import '~pace-progress/themes/blue/pace-theme-minimal.css';
@import 'inc/angular'; @import "inc/variables";
@import 'inc/variables'; @import "inc/mixins";
@import 'inc/mixins'; @import "inc/font";
@import 'inc/font'; @import "inc/print";
@import 'inc/print';
@import 'inc/bootstrap-overrides'; @import "inc/bootstrap-overrides";
@import 'inc/base'; @import "inc/base";
@import 'inc/generics'; @import "inc/generics";
@import 'inc/form'; @import "inc/form";
@import 'inc/button'; @import "inc/button";
@import 'inc/list'; @import "inc/list";
@import 'inc/header'; @import "inc/header";
@import 'inc/tile'; @import "inc/tile";
@import 'inc/label'; @import "inc/label";
@import 'inc/dropdown'; @import "inc/dropdown";
@import 'inc/list-group'; @import "inc/list-group";
@import 'inc/misc'; @import "inc/misc";
@import 'inc/progress-bar'; @import "inc/progress-bar";
@import 'inc/widgets'; @import "inc/widgets";
@import 'inc/table'; @import "inc/table";
@import 'inc/pagination'; @import "inc/alert";
@import 'inc/alert'; @import "inc/media";
@import 'inc/media'; @import "inc/modal";
@import 'inc/modal'; @import "inc/panel";
@import 'inc/tab'; @import "inc/tooltips";
@import 'inc/panel'; @import "inc/popover";
@import 'inc/tooltips'; @import "inc/breadcrumb";
@import 'inc/popover'; @import "inc/jumbotron";
@import 'inc/breadcrumb'; @import "inc/profile";
@import 'inc/jumbotron'; @import "inc/404";
@import 'inc/profile'; @import "inc/ie-warning";
@import 'inc/404'; @import "inc/edit-in-place";
@import 'inc/ie-warning'; @import "inc/flex";
@import 'inc/navbar'; @import "inc/ace-editor";
@import 'inc/edit-in-place'; @import "inc/schema-browser";
@import 'inc/growl'; @import "inc/visualizations/box";
@import 'inc/flex'; @import "inc/visualizations/pivot-table";
@import 'inc/ace-editor'; @import "inc/visualizations/map";
@import 'inc/overlay'; @import "inc/visualizations/misc";
@import 'inc/schema-browser';
@import 'inc/toast';
@import 'inc/visualizations/box';
@import 'inc/visualizations/counter-render';
@import 'inc/visualizations/sankey';
@import 'inc/visualizations/pivot-table';
@import 'inc/visualizations/map';
@import 'inc/visualizations/chart';
@import 'inc/visualizations/sunburst';
@import 'inc/visualizations/cohort';
@import 'inc/visualizations/misc';
/** VENDOR OVERRIDES **/
@import 'inc/vendor-overrides/bootstrap-select';
@import 'inc/vendor-overrides/bootstrap-datetimepicker';
@import 'inc/vendor-overrides/typeahead';
@import 'inc/vendor-overrides/sweetalert';
@import 'inc/vendor-overrides/ui-select';
/** REDASH STYLING **/ /** REDASH STYLING **/
@import 'redash/redash-newstyle'; @import "redash/redash-table";
@import 'redash/redash-table'; @import "redash/query";
@import 'redash/query'; @import "redash/tags-control";
@import 'redash/tags-control'; @import "redash/css-logo";
@import 'redash/css-logo'; @import "redash/loading-indicator";

View File

@@ -0,0 +1,51 @@
.loading-indicator {
position: fixed;
top: 50%;
left: 50%;
margin: -50px 0 0 -50px; // center
width: 100px;
height: 100px;
transition-duration: 150ms;
transition-timing-function: linear;
transition-property: opacity, transform;
#css-logo {
animation: hover 2s infinite;
}
#shadow {
width: 33px;
height: 12px;
border-radius: 50%;
background-color: black;
opacity: 0.25;
display: block;
position: absolute;
left: 34px;
top: 115px;
animation: shadow 2s infinite;
}
@keyframes hover {
50% {
transform: translateY(-5px);
}
}
@keyframes shadow {
50% {
transform: scaleX(0.9);
opacity: 0.2;
}
}
}
// hide indicator when application has content
#application-root:not(:empty) ~ .loading-indicator {
opacity: 0;
transform: scale(0.9);
pointer-events: none;
* {
animation: none !important;
}
}

View File

@@ -2,59 +2,22 @@ body.fixed-layout {
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
app-view { #application-root {
display: flex; display: flex;
flex-direction: column; flex-direction: row;
padding-bottom: 0;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
> div { .application-layout-content > div {
flex-grow: 1;
display: flex; display: flex;
} }
} }
} }
.tab-nav .tab-new-vis {
margin: 0 5px;
> a {
color: @headings-color;
margin-top: 8px;
padding: 7px;
font-weight: 400;
}
}
.bottom-controller {
padding: 10px 15px;
background: #fff;
display: flex;
align-items: center;
button, div, span {
position: relative;
}
div:last-child {
flex-grow: 1;
text-align: right;
}
&:before {
content: '';
height: 50px;
position: fixed;
bottom: 0;
width: 100%;
pointer-events: none;
left: 0;
}
}
.p-b-60 { .p-b-60 {
padding-bottom: 60px !important; padding-bottom: 60px !important;
} }
.bottom-controller-container { .bottom-controller-container {
@@ -64,89 +27,9 @@ body.fixed-layout {
flex-shrink: 0; flex-shrink: 0;
} }
.query-metadata__bottom {
margin: 0 10px;
}
.bottom-controller, .bottom-controller-container {
.query-metadata__property {
margin-right: 5px;
}
}
// Editor // Editor
edit-in-place p, span.editable {
display: inline-block;
}
edit-in-place p.editable:hover {
display: inline-block;
}
.editor__control {
margin-top: 10px;
.dropdown-toggle {
margin-right: 0;
}
}
.filter-container { .filter-container {
margin-bottom: 10px; margin-bottom: 5px;
}
.ace_editor.ace_autocomplete .ace_completion-highlight {
text-shadow: none !important;
background: #ffff005e;
font-weight: 600;
}
.query-metadata {
background: #fff;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
table {
width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
td {
padding: 3px 0;
vertical-align: top;
}
tr {
td:first-of-type {
padding-right: 5px;
}
}
}
p {
&:last-of-type {
margin-bottom: 0;
}
display: flex;
justify-content: space-between;
}
.query-metadata__property {
width: 60px;
display: inline-block;
}
._query-metadata__time {
}
}
.editor__control {
.form-control {
height: 30px;
}
} }
.schema-container { .schema-container {
@@ -158,7 +41,7 @@ edit-in-place p.editable:hover {
.editor__left { .editor__left {
height: 100% !important; height: 100% !important;
width: calc(~'25% - 10px'); width: calc(~"25% - 10px");
margin-right: 10px; margin-right: 10px;
.form-control { .form-control {
@@ -189,10 +72,6 @@ edit-in-place p.editable:hover {
} }
} }
.embed__vis {
}
.query__vis { .query__vis {
table { table {
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
@@ -208,16 +87,17 @@ edit-in-place p.editable:hover {
} }
} }
.visualization-renderer {
.pagination,
.ant-pagination {
margin-top: 10px;
}
}
.embed__vis { .embed__vis {
display: flex; display: flex;
flex-flow: column; flex-flow: column;
width: 100%;
}
.embed-heading {
h3 {
line-height: 1.75;
margin: 0;
}
} }
.widget-wrapper { .widget-wrapper {
@@ -229,6 +109,14 @@ edit-in-place p.editable:hover {
} }
} }
// Don't let filters take all visualization space on query fixed layout
.query-fixed-layout {
.filters-wrapper {
max-height: 40%;
overflow: auto;
}
}
.page-header--new { .page-header--new {
.query-tags, .query-tags,
.query-tags__mobile { .query-tags__mobile {
@@ -239,14 +127,6 @@ edit-in-place p.editable:hover {
} }
} }
.page-header--query {
.page-title {
display: block;
margin-left: 15px;
margin-right: 15px;
}
}
a.label-tag { a.label-tag {
background: fade(@redash-gray, 15%); background: fade(@redash-gray, 15%);
color: darken(@redash-gray, 15%); color: darken(@redash-gray, 15%);
@@ -257,14 +137,11 @@ a.label-tag {
} }
} }
.schema-browser {
overflow-y: auto;
}
.query-page-wrapper { .query-page-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
position: relative;
} }
.query-fullscreen { .query-fullscreen {
@@ -273,9 +150,23 @@ a.label-tag {
box-shadow: rgba(102, 136, 153, 0.15) 0 4px 9px -3px; box-shadow: rgba(102, 136, 153, 0.15) 0 4px 9px -3px;
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
width: 100vw;
.tile, .tiled { .resizable-component.react-resizable {
.react-resizable-handle-horizontal {
border-right: 1px solid #efefef;
}
.react-resizable-handle-vertical {
border-bottom: 1px solid #efefef;
}
}
.query-metadata.query-metadata-horizontal {
border-bottom: 1px solid #efefef;
}
.tile,
.tiled {
box-shadow: none; box-shadow: none;
padding: 15px 0 !important; padding: 15px 0 !important;
} }
@@ -290,22 +181,26 @@ a.label-tag {
min-width: 10px; min-width: 10px;
overflow-x: hidden; overflow-x: hidden;
.schema-container {
}
.editor__left__data-source, .editor__left__data-source,
.schema-control, .schema-control,
.query-metadata--history,
.editor { .editor {
flex-shrink: 0; flex-shrink: 0;
} }
.query-metadata { .editor__left__schema,
border-top: 1px solid #efefef; .editor__left__data-source {
padding: 15px;
} }
.query-metadata, .editor__left__schema, .editor__left__data-source { .editor__left__data-source {
padding: 15px; .ant-select {
.ant-select-selection-selected-value {
img,
span {
vertical-align: middle;
}
}
}
} }
.editor__left__schema { .editor__left__schema {
@@ -316,7 +211,7 @@ a.label-tag {
padding-top: 0 !important; padding-top: 0 !important;
position: relative; position: relative;
schema-browser { .schema-container {
position: absolute; position: absolute;
left: 15px; left: 15px;
top: 0; top: 0;
@@ -325,10 +220,6 @@ a.label-tag {
} }
} }
} }
main {
display: flex;
height: 100%;
}
.content { .content {
background: #fff; background: #fff;
flex-grow: 1; flex-grow: 1;
@@ -338,22 +229,9 @@ a.label-tag {
align-content: space-around; align-content: space-around;
padding: 0; padding: 0;
overflow-x: hidden; overflow-x: hidden;
.editor {
border-bottom: 1px solid #efefef;
}
.pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div {
overflow: visible;
}
.tab-nav {
flex-shrink: 0;
}
} }
.row { .row {
background: #fff; background: #fff;
z-index: 9;
min-height: 50px; min-height: 50px;
&.resizable { &.resizable {
@@ -366,6 +244,10 @@ a.label-tag {
justify-content: space-around; justify-content: space-around;
align-content: space-around; align-content: space-around;
overflow: hidden; overflow: hidden;
min-height: 10px;
max-height: 70vh;
flex: 0 0 300px;
} }
.row { .row {
@@ -392,7 +274,10 @@ a.label-tag {
transition: none !important; transition: none !important;
} }
} }
.rg-right, .rg-left, .rg-top, .rg-bottom { .rg-right,
.rg-left,
.rg-top,
.rg-bottom {
display: block; display: block;
width: 10px; width: 10px;
height: 10px; height: 10px;
@@ -407,32 +292,34 @@ a.label-tag {
border: 1px solid #ccc; border: 1px solid #ccc;
} }
} }
.rg-right, .rg-left { .rg-right,
.rg-left {
span { span {
border-width: 0 1px; border-width: 0 1px;
top: 50%; top: 50%;
margin: -10px 0 0 @spacing/4; margin: -10px 0 0 @spacing / 4;
height: 20px; height: 20px;
width: 3px; width: 3px;
} }
} }
.rg-top, .rg-bottom { .rg-top,
.rg-bottom {
span { span {
border-width: 1px 0; border-width: 1px 0;
left: 50%; left: 50%;
margin: @spacing/4 0 0 -10px; margin: @spacing / 4 0 0 -10px;
width: 20px; width: 20px;
height: 3px; height: 3px;
} }
} }
.rg-top { .rg-top {
cursor: row-resize; cursor: row-resize;
width: 100%; width: 100%;
top: 0; top: 0;
left: 0; left: 0;
margin-top: -@spacing/2; margin-top: -@spacing / 2;
} }
.rg-right { .rg-right {
cursor: col-resize; cursor: col-resize;
border-right: 1px solid #efefef; border-right: 1px solid #efefef;
height: 100%; height: 100%;
@@ -444,7 +331,7 @@ a.label-tag {
background: fade(@redash-gray, 6%); background: fade(@redash-gray, 6%);
} }
} }
.rg-bottom { .rg-bottom {
cursor: row-resize; cursor: row-resize;
background: #fff; background: #fff;
width: 100%; width: 100%;
@@ -456,7 +343,7 @@ a.label-tag {
background: fade(@redash-gray, 6%); background: fade(@redash-gray, 6%);
} }
} }
.rg-left { .rg-left {
cursor: col-resize; cursor: col-resize;
height: 100%; height: 100%;
left: 0; left: 0;
@@ -469,11 +356,6 @@ a.label-tag {
visibility: hidden; visibility: hidden;
} }
.query-fullscreen .query-metadata__mobile {
display: none;
}
// Visualization editor // Visualization editor
.modal-xl .modal-content { .modal-xl .modal-content {
border: none; border: none;
@@ -510,42 +392,13 @@ nav .rg-bottom {
visibility: hidden; visibility: hidden;
} }
.query-metadata--description {
max-height: 125px;
overflow-y: auto;
.edit-in-place.active {
width: 100% !important;
}
.edit-in-place .rd-form-control {
width: 100% !important;
}
}
.query-metadata--refresh {
height: 50px;
border: none !important;
.query-metadata__property {
width: auto;
}
p {
display: block;
}
}
.query-tags { .query-tags {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
margin-top: -3px; // padding-top of tags
} }
.query-tags__mobile { .query-tags__mobile {
display: none; display: none;
margin: -5px 0 0 0;
padding: 0 0 0 23px;
} }
.table--permission { .table--permission {
@@ -559,27 +412,20 @@ nav .rg-bottom {
} }
.edit-visualization { .edit-visualization {
margin-right: 5px; margin-right: 5px;
}
@media (min-width: 880px) {
.query-fullscreen {
.query-metadata.query-metadata-horizontal {
display: none;
}
}
} }
// Smaller screens // Smaller screens
@media (max-width: 880px) { @media (max-width: 880px) {
.page-header--query {
.page-title {
margin-left: 0;
margin-right: 0;
}
}
.query-tags:not(.query-tags__empty) {
display: none;
}
.query-tags__mobile:not(.query-tags__empty) {
display: block;
}
.btn--showhide, .btn--showhide,
.query-actions-menu .dropdown-toggle { .query-actions-menu .dropdown-toggle {
margin-bottom: 5px; margin-bottom: 5px;
@@ -589,10 +435,6 @@ nav .rg-bottom {
display: none; display: none;
} }
.tab-nav .tab-new-vis {
display: none;
}
.query-fullscreen { .query-fullscreen {
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
@@ -605,25 +447,6 @@ nav .rg-bottom {
display: none; display: none;
} }
.query-metadata__mobile {
border-bottom: 1px solid #efefef;
min-height: 0 !important;
flex-shrink: 0;
padding: 10px 15px;
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
.profile__image_thumb {
margin: 0 5px 0 0;
}
.query-metadata__property {
white-space: nowrap;
}
}
main { main {
flex-direction: column-reverse; flex-direction: column-reverse;
@@ -656,28 +479,18 @@ nav .rg-bottom {
} }
} }
.query-page-wrapper {
.container {
margin-left: 0;
margin-right: 0;
}
}
.datasource-small { .datasource-small {
visibility: visible; visibility: visible;
} }
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.editor__left__schema, .editor__left__data-source { .editor__left__schema,
.editor__left__data-source {
display: none; display: none;
} }
.filter-container { .filter-container {
padding-right: 0; padding-right: 0;
} }
.btn-edit-visualisation {
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -10,13 +10,11 @@
display: inline-block; display: inline-block;
} }
.tag-separator {
margin: 4px 3px 0 0;
}
&.disabled { &.disabled {
opacity: 0.4; opacity: 0.4;
} }
} }
// This is for using .inline-tags-control in Angular which renders
// a little differently than React (e.g. in Alert.html)
.inline-tags-control .tags-control {
display: inline-block;
}

View File

@@ -19,8 +19,6 @@
@import 'inc/ie-warning'; @import 'inc/ie-warning';
@import 'inc/flex'; @import 'inc/flex';
@import 'redash/redash-newstyle';
html, body { html, body {
height: 100%; height: 100%;
margin: 0; margin: 0;

View File

@@ -1,11 +1,11 @@
import React, { forwardRef } from 'react'; import React, { forwardRef } from "react";
import AceEditor from 'react-ace'; import AceEditor from "react-ace";
import './AceEditorInput.less'; import "./AceEditorInput.less";
function AceEditorInput(props, ref) { function AceEditorInput(props, ref) {
return ( return (
<div className="ace-editor-input"> <div className="ace-editor-input" data-test={props["data-test"]}>
<AceEditor <AceEditor
ref={ref} ref={ref}
mode="sql" mode="sql"

View File

@@ -0,0 +1,176 @@
import { first } from "lodash";
import React, { useState } from "react";
import Button from "antd/lib/button";
import Menu from "antd/lib/menu";
import Link from "@/components/Link";
import HelpTrigger from "@/components/HelpTrigger";
import CreateDashboardDialog from "@/components/dashboards/CreateDashboardDialog";
import { Auth, currentUser } from "@/services/auth";
import settingsMenu from "@/services/settingsMenu";
import logoUrl from "@/assets/images/redash_icon_small.png";
import DesktopOutlinedIcon from "@ant-design/icons/DesktopOutlined";
import CodeOutlinedIcon from "@ant-design/icons/CodeOutlined";
import AlertOutlinedIcon from "@ant-design/icons/AlertOutlined";
import PlusOutlinedIcon from "@ant-design/icons/PlusOutlined";
import QuestionCircleOutlinedIcon from "@ant-design/icons/QuestionCircleOutlined";
import SettingOutlinedIcon from "@ant-design/icons/SettingOutlined";
import MenuUnfoldOutlinedIcon from "@ant-design/icons/MenuUnfoldOutlined";
import MenuFoldOutlinedIcon from "@ant-design/icons/MenuFoldOutlined";
import VersionInfo from "./VersionInfo";
import "./DesktopNavbar.less";
function NavbarSection({ inlineCollapsed, children, ...props }) {
return (
<Menu
selectable={false}
mode={inlineCollapsed ? "inline" : "vertical"}
inlineCollapsed={inlineCollapsed}
theme="dark"
{...props}>
{children}
</Menu>
);
}
export default function DesktopNavbar() {
const [collapsed, setCollapsed] = useState(true);
const firstSettingsTab = first(settingsMenu.getAvailableItems());
const canCreateQuery = currentUser.hasPermission("create_query");
const canCreateDashboard = currentUser.hasPermission("create_dashboard");
const canCreateAlert = currentUser.hasPermission("list_alerts");
return (
<div className="desktop-navbar">
<NavbarSection inlineCollapsed={collapsed} className="desktop-navbar-logo">
<div>
<Link href="./">
<img src={logoUrl} alt="Redash" />
</Link>
</div>
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed}>
{currentUser.hasPermission("list_dashboards") && (
<Menu.Item key="dashboards">
<Link href="dashboards">
<DesktopOutlinedIcon />
<span>Dashboards</span>
</Link>
</Menu.Item>
)}
{currentUser.hasPermission("view_query") && (
<Menu.Item key="queries">
<Link href="queries">
<CodeOutlinedIcon />
<span>Queries</span>
</Link>
</Menu.Item>
)}
{currentUser.hasPermission("list_alerts") && (
<Menu.Item key="alerts">
<Link href="alerts">
<AlertOutlinedIcon />
<span>Alerts</span>
</Link>
</Menu.Item>
)}
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed} className="desktop-navbar-spacer">
{(canCreateQuery || canCreateDashboard || canCreateAlert) && <Menu.Divider />}
{(canCreateQuery || canCreateDashboard || canCreateAlert) && (
<Menu.SubMenu
key="create"
popupClassName="desktop-navbar-submenu"
title={
<React.Fragment>
<span data-test="CreateButton">
<PlusOutlinedIcon />
<span>Create</span>
</span>
</React.Fragment>
}>
{canCreateQuery && (
<Menu.Item key="new-query">
<Link href="queries/new" data-test="CreateQueryMenuItem">
New Query
</Link>
</Menu.Item>
)}
{canCreateDashboard && (
<Menu.Item key="new-dashboard">
<a data-test="CreateDashboardMenuItem" onMouseUp={() => CreateDashboardDialog.showModal()}>
New Dashboard
</a>
</Menu.Item>
)}
{canCreateAlert && (
<Menu.Item key="new-alert">
<Link data-test="CreateAlertMenuItem" href="alerts/new">
New Alert
</Link>
</Menu.Item>
)}
</Menu.SubMenu>
)}
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed}>
<Menu.Item key="help">
<HelpTrigger showTooltip={false} type="HOME">
<QuestionCircleOutlinedIcon />
<span>Help</span>
</HelpTrigger>
</Menu.Item>
{firstSettingsTab && (
<Menu.Item key="settings">
<Link href={firstSettingsTab.path} data-test="SettingsLink">
<SettingOutlinedIcon />
<span>Settings</span>
</Link>
</Menu.Item>
)}
<Menu.Divider />
</NavbarSection>
<NavbarSection inlineCollapsed={collapsed} className="desktop-navbar-profile-menu">
<Menu.SubMenu
key="profile"
popupClassName="desktop-navbar-submenu"
title={
<span data-test="ProfileDropdown" className="desktop-navbar-profile-menu-title">
<img className="profile__image_thumb" src={currentUser.profile_image_url} alt={currentUser.name} />
<span>{currentUser.name}</span>
</span>
}>
<Menu.Item key="profile">
<Link href="users/me">Profile</Link>
</Menu.Item>
{currentUser.hasPermission("super_admin") && (
<Menu.Item key="status">
<Link href="admin/status">System Status</Link>
</Menu.Item>
)}
<Menu.Divider />
<Menu.Item key="logout">
<a data-test="LogOutButton" onClick={() => Auth.logout()}>
Log out
</a>
</Menu.Item>
<Menu.Divider />
<Menu.Item key="version" disabled className="version-info">
<VersionInfo />
</Menu.Item>
</Menu.SubMenu>
</NavbarSection>
<Button onClick={() => setCollapsed(!collapsed)} className="desktop-navbar-collapse-button">
{collapsed ? <MenuUnfoldOutlinedIcon /> : <MenuFoldOutlinedIcon />}
</Button>
</div>
);
}

View File

@@ -0,0 +1,181 @@
@backgroundColor: #001529;
@dividerColor: rgba(255, 255, 255, 0.5);
@textColor: rgba(255, 255, 255, 0.75);
.desktop-navbar {
background: @backgroundColor;
display: flex;
flex-direction: column;
height: 100%;
&-spacer {
flex: 1 1 auto;
}
&-logo.ant-menu {
padding-top: 20px;
padding-bottom: 20px;
text-align: center;
img {
height: 40px;
transition: all 270ms;
}
&.ant-menu-inline-collapsed {
img {
height: 20px;
}
}
}
.help-trigger {
font: inherit;
}
.ant-menu {
&:not(.ant-menu-inline-collapsed) {
width: 170px;
}
&.ant-menu-inline-collapsed > .ant-menu-submenu-title span img + span,
&.ant-menu-inline-collapsed > .ant-menu-item i + span {
display: inline-block;
max-width: 0;
opacity: 0;
}
.ant-menu-item-divider {
background: @dividerColor;
}
.ant-menu-item,
.ant-menu-submenu {
font-weight: 500;
color: @textColor;
&.ant-menu-submenu-open,
&.ant-menu-submenu-active,
&:hover,
&:active {
color: #fff;
}
a,
span,
.anticon {
color: inherit;
}
}
.ant-menu-submenu-arrow {
display: none;
}
}
.ant-btn.desktop-navbar-collapse-button {
background-color: @backgroundColor;
border: 0;
border-radius: 0;
color: @textColor;
&:hover,
&:active {
color: #fff;
}
&:after {
animation: 0s !important;
}
}
.desktop-navbar-profile-menu {
.desktop-navbar-profile-menu-title {
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
.profile__image_thumb {
margin: 0;
vertical-align: middle;
}
.profile__image_thumb + span {
flex: 1 1 auto;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-left: 10px;
vertical-align: middle;
display: inline-block;
// styles from Antd
opacity: 1;
transition: opacity 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
margin-left 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
}
&.ant-menu-inline-collapsed {
.ant-menu-submenu-title {
padding-left: 16px !important;
padding-right: 16px !important;
}
.desktop-navbar-profile-menu-title {
.profile__image_thumb + span {
opacity: 0;
max-width: 0;
margin-left: 0;
}
}
}
}
}
.desktop-navbar-submenu {
.ant-menu {
.ant-menu-item-divider {
background: @dividerColor;
}
.ant-menu-item {
font-weight: 500;
color: @textColor;
&:hover,
&:active {
color: #fff;
}
a,
span,
.anticon {
color: inherit;
}
.zmdi,
.fa {
margin-right: 5px;
}
&.version-info {
height: auto;
line-height: normal;
padding-top: 12px;
padding-bottom: 12px;
a {
color: rgba(255, 255, 255, 0.8);
&:hover,
&:active {
color: rgba(255, 255, 255, 1);
}
}
}
}
}
}

View File

@@ -0,0 +1,88 @@
import { first } from "lodash";
import React from "react";
import PropTypes from "prop-types";
import Button from "antd/lib/button";
import MenuOutlinedIcon from "@ant-design/icons/MenuOutlined";
import Dropdown from "antd/lib/dropdown";
import Menu from "antd/lib/menu";
import Link from "@/components/Link";
import { Auth, currentUser } from "@/services/auth";
import settingsMenu from "@/services/settingsMenu";
import logoUrl from "@/assets/images/redash_icon_small.png";
import "./MobileNavbar.less";
export default function MobileNavbar({ getPopupContainer }) {
const firstSettingsTab = first(settingsMenu.getAvailableItems());
return (
<div className="mobile-navbar">
<div className="mobile-navbar-logo">
<Link href="./">
<img src={logoUrl} alt="Redash" />
</Link>
</div>
<div>
<Dropdown
overlayStyle={{ minWidth: 200 }}
trigger={["click"]}
getPopupContainer={getPopupContainer} // so the overlay menu stays with the fixed header when page scrolls
overlay={
<Menu mode="vertical" theme="dark" selectable={false} className="mobile-navbar-menu">
{currentUser.hasPermission("list_dashboards") && (
<Menu.Item key="dashboards">
<Link href="dashboards">Dashboards</Link>
</Menu.Item>
)}
{currentUser.hasPermission("view_query") && (
<Menu.Item key="queries">
<Link href="queries">Queries</Link>
</Menu.Item>
)}
{currentUser.hasPermission("list_alerts") && (
<Menu.Item key="alerts">
<Link href="alerts">Alerts</Link>
</Menu.Item>
)}
<Menu.Item key="profile">
<Link href="users/me">Edit Profile</Link>
</Menu.Item>
<Menu.Divider />
{firstSettingsTab && (
<Menu.Item key="settings">
<Link href={firstSettingsTab.path}>Settings</Link>
</Menu.Item>
)}
{currentUser.hasPermission("super_admin") && (
<Menu.Item key="status">
<Link href="admin/status">System Status</Link>
</Menu.Item>
)}
{currentUser.hasPermission("super_admin") && <Menu.Divider />}
<Menu.Item key="help">
{/* eslint-disable-next-line react/jsx-no-target-blank */}
<Link href="https://redash.io/help" target="_blank" rel="noopener">
Help
</Link>
</Menu.Item>
<Menu.Item key="logout" onClick={() => Auth.logout()}>
Log out
</Menu.Item>
</Menu>
}>
<Button className="mobile-navbar-toggle-button" ghost>
<MenuOutlinedIcon />
</Button>
</Dropdown>
</div>
</div>
);
}
MobileNavbar.propTypes = {
getPopupContainer: PropTypes.func,
};
MobileNavbar.defaultProps = {
getPopupContainer: null,
};

View File

@@ -0,0 +1,35 @@
@backgroundColor: #001529;
@dividerColor: rgba(255, 255, 255, 0.5);
@textColor: rgba(255, 255, 255, 0.75);
.mobile-navbar {
display: flex;
justify-content: space-between;
align-items: center;
background: @backgroundColor;
box-shadow: 0 4px 9px -3px rgba(102, 136, 153, 0.15);
padding: 0 15px;
height: 100%;
&-logo {
img {
height: 40px;
width: 40px;
}
}
.ant-btn.mobile-navbar-toggle-button {
padding: 0 10px;
}
}
.mobile-navbar-menu {
.ant-dropdown-menu-item {
font-weight: 500;
color: @textColor;
}
.ant-dropdown-menu-item-divider {
background: @dividerColor;
}
}

View File

@@ -0,0 +1,24 @@
import React from "react";
import Link from "@/components/Link";
import { clientConfig, currentUser } from "@/services/auth";
import frontendVersion from "@/version.json";
export default function VersionInfo() {
return (
<React.Fragment>
<div>
Version: {clientConfig.version}
{frontendVersion !== clientConfig.version && ` (${frontendVersion.substring(0, 8)})`}
</div>
{clientConfig.newVersionAvailable && currentUser.hasPermission("super_admin") && (
<div className="m-t-10">
{/* eslint-disable react/jsx-no-target-blank */}
<Link href="https://version.redash.io/" className="update-available" target="_blank" rel="noopener">
Update Available
<i className="fa fa-external-link m-l-5" />
</Link>
</div>
)}
</React.Fragment>
);
}

View File

@@ -0,0 +1,41 @@
import React, { useRef, useCallback } from "react";
import PropTypes from "prop-types";
import DynamicComponent from "@/components/DynamicComponent";
import DesktopNavbar from "./DesktopNavbar";
import MobileNavbar from "./MobileNavbar";
import "./index.less";
export default function ApplicationLayout({ children }) {
const mobileNavbarContainerRef = useRef();
const getMobileNavbarPopupContainer = useCallback(() => mobileNavbarContainerRef.current, []);
return (
<React.Fragment>
<DynamicComponent name="ApplicationWrapper">
<div className="application-layout-side-menu">
<DynamicComponent name="ApplicationDesktopNavbar">
<DesktopNavbar />
</DynamicComponent>
</div>
<div className="application-layout-content">
<nav className="application-layout-top-menu" ref={mobileNavbarContainerRef}>
<DynamicComponent name="ApplicationMobileNavbar" getPopupContainer={getMobileNavbarPopupContainer}>
<MobileNavbar getPopupContainer={getMobileNavbarPopupContainer} />
</DynamicComponent>
</nav>
{children}
</div>
</DynamicComponent>
</React.Fragment>
);
}
ApplicationLayout.propTypes = {
children: PropTypes.node,
};
ApplicationLayout.defaultProps = {
children: null,
};

View File

@@ -0,0 +1,81 @@
@mobileBreakpoint: ~"(max-width: 767px)";
body #application-root {
@topMenuHeight: 49px;
display: flex;
flex-direction: row;
justify-content: stretch;
padding-bottom: 0 !important;
height: 100vh;
.application-layout-side-menu {
height: 100vh;
position: relative;
@media @mobileBreakpoint {
display: none;
}
}
.application-layout-top-menu {
height: @topMenuHeight;
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
box-sizing: border-box;
z-index: 1000;
@media @mobileBreakpoint {
display: block;
}
}
.application-layout-content {
display: flex;
flex-direction: column;
overflow-y: auto;
flex: 1 1 auto;
padding-bottom: 15px;
@media @mobileBreakpoint {
margin-top: @topMenuHeight; // compensate for app header fixed position
}
}
}
body.fixed-layout #application-root {
.application-layout-content {
padding-bottom: 0;
}
}
body.headless #application-root {
.application-layout-side-menu,
.application-layout-top-menu {
display: none !important;
}
.application-layout-content {
margin-top: 0;
}
}
// Fixes for proper snapshots in Percy (move vertical scroll to body level
// to capture entire page, otherwise it wll be cut by viewport)
@media only percy {
body #application-root {
height: auto;
.application-layout-side-menu {
height: auto;
}
.application-layout-content {
overflow: visible;
}
}
}

View File

@@ -0,0 +1,69 @@
import { get, isObject } from "lodash";
import React from "react";
import PropTypes from "prop-types";
import "./ErrorMessage.less";
import DynamicComponent from "@/components/DynamicComponent";
import { ErrorMessageDetails } from "@/components/ApplicationArea/ErrorMessageDetails";
function getErrorMessageByStatus(status, defaultMessage) {
switch (status) {
case 404:
return "It seems like the page you're looking for cannot be found.";
case 401:
case 403:
return "It seems like you dont have permission to see this page.";
default:
return defaultMessage;
}
}
function getErrorMessage(error) {
const message = "It seems like we encountered an error. Try refreshing this page or contact your administrator.";
if (isObject(error)) {
// HTTP errors
if (error.isAxiosError && isObject(error.response)) {
return getErrorMessageByStatus(error.response.status, get(error, "response.data.message", message));
}
// Router errors
if (error.status) {
return getErrorMessageByStatus(error.status, message);
}
}
return message;
}
export default function ErrorMessage({ error, message }) {
if (!error) {
return null;
}
console.error(error);
const errorDetailsProps = {
error,
message: message || getErrorMessage(error),
};
return (
<div className="error-message-container" data-test="ErrorMessage" role="alert">
<div className="error-state bg-white tiled">
<div className="error-state__icon">
<i className="zmdi zmdi-alert-circle-o" />
</div>
<div className="error-state__details">
<DynamicComponent
name="ErrorMessageDetails"
fallback={<ErrorMessageDetails {...errorDetailsProps} />}
{...errorDetailsProps}
/>
</div>
</div>
</div>
);
}
ErrorMessage.propTypes = {
error: PropTypes.object.isRequired,
message: PropTypes.string,
};

View File

@@ -0,0 +1,17 @@
.error-message-container {
width: 100%;
padding: 0 15px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
.error-state {
max-width: 1200px;
width: 100%;
@media (min-width: 768px) {
width: 65%;
}
}
}

View File

@@ -0,0 +1,51 @@
import React from "react";
import { mount } from "enzyme";
import ErrorMessage from "./ErrorMessage";
const ErrorMessages = {
UNAUTHORIZED: "It seems like you dont have permission to see this page.",
NOT_FOUND: "It seems like the page you're looking for cannot be found.",
GENERIC: "It seems like we encountered an error. Try refreshing this page or contact your administrator.",
};
function mockAxiosError(status = 500, response = {}) {
const error = new Error(`Failed with code ${status}.`);
error.isAxiosError = true;
error.response = { status, ...response };
return error;
}
describe("Error Message", () => {
const spyError = jest.spyOn(console, "error");
beforeEach(() => {
spyError.mockReset();
});
function expectErrorMessageToBe(error, errorMessage) {
const component = mount(<ErrorMessage error={error} />);
expect(component.find(".error-state__details h4").text()).toBe(errorMessage);
expect(spyError).toHaveBeenCalledWith(error);
}
test("displays a generic message on adhoc errors", () => {
expectErrorMessageToBe(new Error("technical information"), ErrorMessages.GENERIC);
});
test("displays a not found message on axios errors with 404 code", () => {
expectErrorMessageToBe(mockAxiosError(404), ErrorMessages.NOT_FOUND);
});
test("displays a unauthorized message on axios errors with 401 code", () => {
expectErrorMessageToBe(mockAxiosError(401), ErrorMessages.UNAUTHORIZED);
});
test("displays a unauthorized message on axios errors with 403 code", () => {
expectErrorMessageToBe(mockAxiosError(403), ErrorMessages.UNAUTHORIZED);
});
test("displays a generic message on axios errors with 500 code", () => {
expectErrorMessageToBe(mockAxiosError(500), ErrorMessages.GENERIC);
});
});

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