diff --git a/superset-frontend/src/showSavedQuery/index.jsx b/superset-frontend/src/showSavedQuery/index.jsx
deleted file mode 100644
index 10c09703f7206..0000000000000
--- a/superset-frontend/src/showSavedQuery/index.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import React from 'react';
-import ReactDom from 'react-dom';
-import Form from 'react-jsonschema-form';
-import { interpolate } from 'src/showSavedQuery/utils';
-import { styled } from '@superset-ui/core';
-import getBootstrapData from 'src/utils/getBootstrapData';
-
-const scheduleInfoContainer = document.getElementById('schedule-info');
-const bootstrapData = getBootstrapData();
-const config = bootstrapData.common.conf.SCHEDULED_QUERIES;
-const { query } = bootstrapData.common;
-const scheduleInfo = query.extra_json.schedule_info;
-const linkback = config.linkback ? interpolate(config.linkback, query) : null;
-
-const StyledSavedQueryContainer = styled.div`
- .btn-add {
- display: none;
- }
-`;
-
-const StyledLinkBack = styled.div`
- ${({ theme }) => `
- padding-top: 0;
- padding-right: ${theme.gridUnit * 2 + 2}px;
- padding-bottom: ${theme.gridUnit * 5}px;
- padding-left: ${theme.gridUnit / 2}px;
-`}
-`;
-
-if (scheduleInfo && config) {
- // hide instructions when showing schedule info
- config.JSONSCHEMA.description = '';
-
- ReactDom.render(
-
-
- {linkback && (
-
-
-
- Pipeline status
-
-
- )}
- ,
- scheduleInfoContainer,
- );
-}
diff --git a/superset-frontend/src/showSavedQuery/utils.js b/superset-frontend/src/showSavedQuery/utils.js
deleted file mode 100644
index 9cd712bc893f3..0000000000000
--- a/superset-frontend/src/showSavedQuery/utils.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-export function getNestedValue(obj, id, separator = '.') {
- /*
- * Given a nested object and an id, return the nested value.
- *
- * > getNestedValue({a:{b:1}}, 'a.b')
- * < 1
- */
- const index = id.indexOf(separator);
- if (index === -1) {
- return obj[id];
- }
- const name = id.slice(0, index);
- const rest = id.slice(index + separator.length);
- return getNestedValue(obj[name], rest, separator);
-}
-
-export function interpolate(str, obj) {
- /*
- * Programmatic template string for interpolation.
- *
- * > interpolate('foo ${a.b}', {a:{b:1}})
- * < "foo 1"
- */
- return str.replace(/\$\{(.+?)\}/g, (match, id) => getNestedValue(obj, id));
-}
diff --git a/superset-frontend/src/showSavedQuery/utils.test.jsx b/superset-frontend/src/showSavedQuery/utils.test.jsx
deleted file mode 100644
index 8d999824812a8..0000000000000
--- a/superset-frontend/src/showSavedQuery/utils.test.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import { getNestedValue, interpolate } from 'src/showSavedQuery/utils';
-
-describe('getNestedValue', () => {
- it('is a function', () => {
- expect(typeof getNestedValue).toBe('function');
- });
-
- it('works with simple ids', () => {
- const obj = { a: '1' };
- const id = 'a';
- expect(getNestedValue(obj, id)).toEqual('1');
- });
-
- it('works with complex ids', () => {
- const obj = { a: { b: '1' } };
- const id = 'a.b';
- expect(getNestedValue(obj, id)).toEqual('1');
- });
-
- it('works with other separators', () => {
- const obj = { a: { b: { c: '1' } } };
- const id = 'a__b__c';
- const separator = '__';
- expect(getNestedValue(obj, id, separator)).toEqual('1');
- });
-});
-
-describe('interpolate', () => {
- it('is a function', () => {
- expect(typeof interpolate).toBe('function');
- });
-
- it('works with simple ids', () => {
- const obj = { a: '1' };
- // eslint-disable-next-line no-template-curly-in-string
- const str = 'value: ${a}';
- expect(interpolate(str, obj)).toEqual('value: 1');
- });
-
- it('works with complex ids', () => {
- const obj = { a: { b: '1' } };
- // eslint-disable-next-line no-template-curly-in-string
- const str = 'value: ${a.b}';
- expect(interpolate(str, obj)).toEqual('value: 1');
- });
-});
diff --git a/superset-frontend/webpack.config.js b/superset-frontend/webpack.config.js
index a47670d9d4023..7bad2ea875393 100644
--- a/superset-frontend/webpack.config.js
+++ b/superset-frontend/webpack.config.js
@@ -212,7 +212,6 @@ const config = {
spa: addPreamble('/src/views/index.tsx'),
embedded: addPreamble('/src/embedded/index.tsx'),
sqllab: addPreamble('/src/SqlLab/index.tsx'),
- showSavedQuery: [path.join(APP_DIR, '/src/showSavedQuery/index.jsx')],
},
output,
stats: 'minimal',
diff --git a/superset/initialization/__init__.py b/superset/initialization/__init__.py
index c390a6f779ec4..f5473ba25e84c 100644
--- a/superset/initialization/__init__.py
+++ b/superset/initialization/__init__.py
@@ -186,7 +186,6 @@ def init_views(self) -> None:
from superset.views.redirects import R
from superset.views.sql_lab.views import (
SavedQueryView,
- SavedQueryViewApi,
SqlLab,
TableSchemaView,
TabStateView,
@@ -312,7 +311,6 @@ def init_views(self) -> None:
appbuilder.add_view_no_menu(R)
appbuilder.add_view_no_menu(ProfileView)
appbuilder.add_view_no_menu(SavedQueryView)
- appbuilder.add_view_no_menu(SavedQueryViewApi)
appbuilder.add_view_no_menu(SliceAsync)
appbuilder.add_view_no_menu(SqlLab)
appbuilder.add_view_no_menu(SqlMetricInlineView)
diff --git a/superset/views/sql_lab/views.py b/superset/views/sql_lab/views.py
index 0da95612de2e0..62558f5ab524f 100644
--- a/superset/views/sql_lab/views.py
+++ b/superset/views/sql_lab/views.py
@@ -17,120 +17,31 @@
import logging
import simplejson as json
-from flask import g, redirect, request, Response
+from flask import redirect, request, Response
from flask_appbuilder import expose
-from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_appbuilder.security.decorators import has_access, has_access_api
from flask_babel import lazy_gettext as _
from sqlalchemy import and_
from superset import db
-from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod
-from superset.models.sql_lab import Query, SavedQuery, TableSchema, TabState
+from superset.models.sql_lab import Query, TableSchema, TabState
from superset.superset_typing import FlaskResponse
from superset.utils import core as utils
from superset.utils.core import get_user_id
-from superset.views.base import (
- BaseSupersetView,
- DeleteMixin,
- json_success,
- SupersetModelView,
-)
+from superset.views.base import BaseSupersetView, json_success
logger = logging.getLogger(__name__)
-class SavedQueryView( # pylint: disable=too-many-ancestors
- SupersetModelView,
- DeleteMixin,
-):
- datamodel = SQLAInterface(SavedQuery)
- include_route_methods = RouteMethod.CRUD_SET
-
+class SavedQueryView(BaseSupersetView):
+ route_base = "/savedqueryview"
class_permission_name = "SavedQuery"
- method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP
- list_title = _("List Saved Query")
- show_title = _("Show Saved Query")
- add_title = _("Add Saved Query")
- edit_title = _("Edit Saved Query")
-
- list_columns = [
- "label",
- "user",
- "database",
- "schema",
- "description",
- "modified",
- "pop_tab_link",
- ]
- order_columns = ["label", "schema", "description", "modified"]
- show_columns = [
- "id",
- "label",
- "user",
- "database",
- "description",
- "sql",
- "pop_tab_link",
- ]
- search_columns = ("label", "user", "database", "schema", "changed_on")
- add_columns = ["label", "database", "description", "sql"]
- edit_columns = add_columns
- base_order = ("changed_on", "desc")
- label_columns = {
- "label": _("Label"),
- "user": _("User"),
- "database": _("Database"),
- "description": _("Description"),
- "modified": _("Modified"),
- "end_time": _("End Time"),
- "pop_tab_link": _("Pop Tab Link"),
- "changed_on": _("Changed on"),
- }
@expose("/list/")
@has_access
def list(self) -> FlaskResponse:
return super().render_app_template()
- def pre_add(self, item: "SavedQueryView") -> None:
- item.user = g.user
-
- def pre_update(self, item: "SavedQueryView") -> None:
- self.pre_add(item)
-
-
-class SavedQueryViewApi(SavedQueryView): # pylint: disable=too-many-ancestors
- include_route_methods = {
- RouteMethod.API_READ,
- RouteMethod.API_CREATE,
- RouteMethod.API_UPDATE,
- RouteMethod.API_GET,
- }
-
- class_permission_name = "SavedQuery"
- method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP
-
- list_columns = [
- "id",
- "label",
- "sqlalchemy_uri",
- "user_email",
- "schema",
- "description",
- "sql",
- "extra_json",
- "extra",
- ]
- add_columns = ["label", "db_id", "schema", "description", "sql", "extra_json"]
- edit_columns = add_columns
- show_columns = add_columns + ["id"]
-
- @has_access_api
- @expose("show/")
- def show(self, pk: int) -> FlaskResponse:
- return super().show(pk)
-
def _get_owner_id(tab_state_id: int) -> int:
return db.session.query(TabState.user_id).filter_by(id=tab_state_id).scalar()