diff --git a/docs/docs/installation/sql-templating.mdx b/docs/docs/installation/sql-templating.mdx index 8a093e643a075..72c2c0a9adb75 100644 --- a/docs/docs/installation/sql-templating.mdx +++ b/docs/docs/installation/sql-templating.mdx @@ -298,7 +298,7 @@ Here's a concrete example: It's possible to query physical and virtual datasets using the `dataset` macro. This is useful if you've defined computed columns and metrics on your datasets, and want to reuse the definition in adhoc SQL Lab queries. -To use the macro, first you need to find the ID of the dataset. This can be done by going to the view showing all the datasets, hovering over the dataset you're interested in, and looking at its URL. For example, if the URL for a dataset is https://superset.example.org/superset/explore/table/42/ its ID is 42. +To use the macro, first you need to find the ID of the dataset. This can be done by going to the view showing all the datasets, hovering over the dataset you're interested in, and looking at its URL. For example, if the URL for a dataset is https://superset.example.org/explore/?dataset_type=table&dataset_id=42 its ID is 42. Once you have the ID you can query it as if it were a table: diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js index 5714eb5da1052..cf1d691ff916f 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js @@ -23,7 +23,7 @@ const MAX_URL_LENGTH = 8000; export function getURIDirectory(formData, endpointType = 'base') { // Building the directory part of the URI - let directory = '/superset/explore/'; + let directory = '/explore/'; if (['json', 'csv', 'query', 'results', 'samples'].includes(endpointType)) { directory = '/superset/explore_json/'; } diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js index cb2561efb8667..c4c9c3264ec0d 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js @@ -24,7 +24,7 @@ const MAX_URL_LENGTH = 8000; export function getURIDirectory(formData, endpointType = 'base') { // Building the directory part of the URI - let directory = '/superset/explore/'; + let directory = '/explore/'; if (['json', 'csv', 'query', 'results', 'samples'].includes(endpointType)) { directory = '/superset/explore_json/'; } diff --git a/superset-frontend/spec/fixtures/mockSliceEntities.js b/superset-frontend/spec/fixtures/mockSliceEntities.js index 69570c5c8f874..cb6d84ea347ad 100644 --- a/superset-frontend/spec/fixtures/mockSliceEntities.js +++ b/superset-frontend/spec/fixtures/mockSliceEntities.js @@ -26,7 +26,7 @@ export const sliceEntitiesForChart = { slices: { [sliceId]: { slice_id: sliceId, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%2018%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%2018%7D', slice_name: 'Genders', form_data: { slice_id: sliceId, @@ -62,7 +62,7 @@ export const sliceEntitiesForDashboard = { slices: { [filterId]: { slice_id: filterId, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20127%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20127%7D', slice_name: 'Region Filter', form_data: { instant_filtering: true, @@ -86,7 +86,7 @@ export const sliceEntitiesForDashboard = { }, 128: { slice_id: 128, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20128%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20128%7D', slice_name: "World's Population", form_data: {}, viz_type: 'big_number', @@ -98,7 +98,7 @@ export const sliceEntitiesForDashboard = { }, 129: { slice_id: 129, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20129%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20129%7D', slice_name: 'Most Populated Countries', form_data: {}, viz_type: 'table', @@ -110,7 +110,7 @@ export const sliceEntitiesForDashboard = { }, 130: { slice_id: 130, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20130%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20130%7D', slice_name: 'Growth Rate', form_data: {}, viz_type: 'line', @@ -122,7 +122,7 @@ export const sliceEntitiesForDashboard = { }, 131: { slice_id: 131, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20131%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20131%7D', slice_name: '% Rural', form_data: {}, viz_type: 'world_map', @@ -134,7 +134,7 @@ export const sliceEntitiesForDashboard = { }, 132: { slice_id: 132, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20132%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20132%7D', slice_name: 'Life Expectancy VS Rural %', form_data: {}, viz_type: 'bubble', @@ -146,7 +146,7 @@ export const sliceEntitiesForDashboard = { }, 133: { slice_id: 133, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20133%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20133%7D', slice_name: 'Rural Breakdown', form_data: {}, viz_type: 'sunburst', @@ -158,7 +158,7 @@ export const sliceEntitiesForDashboard = { }, 134: { slice_id: 134, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20134%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20134%7D', slice_name: "World's Pop Growth", form_data: {}, viz_type: 'area', @@ -170,7 +170,7 @@ export const sliceEntitiesForDashboard = { }, 135: { slice_id: 135, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20135%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20135%7D', slice_name: 'Box plot', form_data: {}, viz_type: 'box_plot', @@ -182,7 +182,7 @@ export const sliceEntitiesForDashboard = { }, 136: { slice_id: 136, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20136%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20136%7D', slice_name: 'Treemap', form_data: {}, viz_type: 'treemap', diff --git a/superset-frontend/src/utils/urlUtils.ts b/superset-frontend/src/utils/urlUtils.ts index 0ca104ef024f6..2aac5f3e281a7 100644 --- a/superset-frontend/src/utils/urlUtils.ts +++ b/superset-frontend/src/utils/urlUtils.ts @@ -52,10 +52,10 @@ export function getUrlParam({ name, type }: UrlParam): unknown { if (!urlParam) { return null; } - if (urlParam === 'true') { + if (urlParam.toLowerCase() === 'true') { return 1; } - if (urlParam === 'false') { + if (urlParam.toLowerCase() === 'false') { return 0; } if (!Number.isNaN(Number(urlParam))) { @@ -71,7 +71,7 @@ export function getUrlParam({ name, type }: UrlParam): unknown { if (!urlParam) { return null; } - return urlParam !== 'false' && urlParam !== '0'; + return urlParam.toLowerCase() !== 'false' && urlParam !== '0'; case 'rison': if (!urlParam) { return null; diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.jsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.jsx index 948c22fa4070a..2f23f45573311 100644 --- a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.jsx +++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.jsx @@ -51,7 +51,7 @@ const mockdatasets = [...new Array(3)].map((_, i) => ({ changed_by: 'user', changed_on: new Date().toISOString(), database_name: `db ${i}`, - explore_url: `/explore/table/${i}`, + explore_url: `/explore/?dataset_type=table&dataset_id=${i}`, id: i, schema: `schema ${i}`, table_name: `coolest table ${i}`, diff --git a/superset/connectors/sqla/views.py b/superset/connectors/sqla/views.py index 18533905ee837..cee0a07b54bb7 100644 --- a/superset/connectors/sqla/views.py +++ b/superset/connectors/sqla/views.py @@ -535,7 +535,7 @@ def edit(self, pk: str) -> FlaskResponse: resp = super().edit(pk) if isinstance(resp, str): return resp - return redirect("/superset/explore/table/{}/".format(pk)) + return redirect("/explore/?dataset_type=table&dataset_id={}".format(pk)) @expose("/list/") @has_access diff --git a/superset/models/core.py b/superset/models/core.py index d21ac56dad5ad..0f783104f1a67 100755 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -386,7 +386,7 @@ def get_sqla_engine( if not source and request and request.referrer: if "/superset/dashboard/" in request.referrer: source = utils.QuerySource.DASHBOARD - elif "/superset/explore/" in request.referrer: + elif "/explore/" in request.referrer: source = utils.QuerySource.CHART elif "/superset/sqllab/" in request.referrer: source = utils.QuerySource.SQL_LAB diff --git a/superset/reports/commands/execute.py b/superset/reports/commands/execute.py index ad1b1edcd2a76..03b9efce45dbf 100644 --- a/superset/reports/commands/execute.py +++ b/superset/reports/commands/execute.py @@ -167,7 +167,7 @@ def _get_url( force=force, ) return get_url_path( - "Superset.explore", + "ExploreView.root", user_friendly=user_friendly, form_data=json.dumps({"slice_id": self._report_schedule.chart_id}), standalone="true", diff --git a/superset/templates/email/role_extended.txt b/superset/templates/email/role_extended.txt index 89ba1b0f722b2..463fb32c9c46e 100644 --- a/superset/templates/email/role_extended.txt +++ b/superset/templates/email/role_extended.txt @@ -20,7 +20,7 @@ Dear {{ user.username }},
{{ granter.username }} has extended the role {{ role.name }} to include - + {{datasource.full_name}} and granted you access to it.

diff --git a/superset/templates/email/role_granted.txt b/superset/templates/email/role_granted.txt index 8027f41ac489c..312a04947387d 100644 --- a/superset/templates/email/role_granted.txt +++ b/superset/templates/email/role_granted.txt @@ -21,7 +21,7 @@ Dear {{ user.username }}, {{ granter.username }} has granted you the role {{ role.name }} that gives access to the - + {{datasource.full_name}}

diff --git a/superset/views/core.py b/superset/views/core.py index 0598c72446832..e1a4f21bd9ce5 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -427,13 +427,13 @@ def slice(self, slice_id: int) -> FlaskResponse: # pylint: disable=no-self-use _, slc = get_form_data(slice_id, use_slice_data=True) if not slc: abort(404) - endpoint = "/superset/explore/?form_data={}".format( + endpoint = "/explore/?form_data={}".format( parse.quote(json.dumps({"slice_id": slice_id})) ) is_standalone_mode = ReservedUrlParameters.is_standalone_mode() if is_standalone_mode: - endpoint += f"&{ReservedUrlParameters.STANDALONE}={is_standalone_mode}" + endpoint += f"&{ReservedUrlParameters.STANDALONE}=true" return redirect(endpoint) def get_query_string_response(self, viz_obj: BaseViz) -> FlaskResponse: diff --git a/superset/views/redirects.py b/superset/views/redirects.py index 831fc978b9473..93a4339403109 100644 --- a/superset/views/redirects.py +++ b/superset/views/redirects.py @@ -34,25 +34,40 @@ class R(BaseSupersetView): # pylint: disable=invalid-name """used for short urls""" @staticmethod - def _validate_url(url: Optional[str] = None) -> bool: - if url and ( - url.startswith("//superset/dashboard/") - or url.startswith("//superset/explore/") - ): - return True - return False + def _validate_explore_url(url: str) -> Optional[str]: + if url.startswith("//superset/explore/p/"): + return url + + if url.startswith("//superset/explore"): + return "/" + url[10:] # Remove /superset from old Explore URLs + + if url.startswith("//explore"): + return url + + return None + + @staticmethod + def _validate_dashboard_url(url: str) -> Optional[str]: + if url.startswith("//superset/dashboard/"): + return url + + return None @event_logger.log_this @expose("/") def index(self, url_id: int) -> FlaskResponse: url = db.session.query(models.Url).get(url_id) if url and url.url: - explore_url = "//superset/explore/?" - if url.url.startswith(explore_url): - explore_url += f"r={url_id}" + explore_url = self._validate_explore_url(url.url) + if explore_url: + if explore_url.startswith("//explore/?"): + explore_url = f"//explore/?r={url_id}" return redirect(explore_url[1:]) - if self._validate_url(url.url): - return redirect(url.url[1:]) + + dashboard_url = self._validate_dashboard_url(url.url) + if dashboard_url: + return redirect(dashboard_url[1:]) + return redirect("/") flash("URL to nowhere...", "danger") diff --git a/tests/integration_tests/core_tests.py b/tests/integration_tests/core_tests.py index 86f6df7b15f90..48dcd071820ae 100644 --- a/tests/integration_tests/core_tests.py +++ b/tests/integration_tests/core_tests.py @@ -123,15 +123,6 @@ def test_dashboard_endpoint(self): @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_slice_endpoint(self): self.login(username="admin") - slc = self.get_slice("Girls", db.session) - resp = self.get_resp("/superset/slice/{}/".format(slc.id)) - assert "Original value" in resp - assert "List Roles" in resp - - # Testing overrides - resp = self.get_resp("/superset/slice/{}/?standalone=true".format(slc.id)) - assert '