From 2a941500975c6e4b2871d12c0fc5272ccc0a8286 Mon Sep 17 00:00:00 2001 From: Craig Rueda Date: Wed, 8 Jan 2020 10:04:05 -0800 Subject: [PATCH] Moving appbuilder.xxx out of view files and into app.py (#8912) * Moving appbuilder.xxx out of view files ands into app.py * Pulled url map converters out into their own file * Adding license blurb * Linting * Linting again... --- docker/docker-init.sh | 2 +- superset/app.py | 332 ++++++++++++++++++++++++++- superset/connectors/druid/views.py | 51 ---- superset/connectors/sqla/views.py | 18 -- superset/utils/url_map_converters.py | 35 +++ superset/views/annotations.py | 23 +- superset/views/api.py | 5 +- superset/views/core.py | 141 ++---------- superset/views/dashboard/api.py | 4 - superset/views/dashboard/views.py | 11 +- superset/views/database/api.py | 4 - superset/views/database/views.py | 35 +-- superset/views/datasource.py | 5 +- superset/views/log/api.py | 8 - superset/views/log/views.py | 16 -- superset/views/schedules.py | 30 +-- superset/views/sql_lab.py | 30 +-- superset/views/tags.py | 18 +- 18 files changed, 394 insertions(+), 374 deletions(-) create mode 100644 superset/utils/url_map_converters.py diff --git a/docker/docker-init.sh b/docker/docker-init.sh index 46bb5fce5..3a42b8ca9 100755 --- a/docker/docker-init.sh +++ b/docker/docker-init.sh @@ -34,7 +34,7 @@ EOF } # Create an admin user -echo_step "1" "Starting" "Setting up admin user" +echo_step "1" "Starting" "Setting up admin user ( admin / admin )" superset fab create-admin \ --username admin \ --firstname Superset \ diff --git a/superset/app.py b/superset/app.py index e69377c2c..9e8fd88bc 100644 --- a/superset/app.py +++ b/superset/app.py @@ -21,6 +21,7 @@ import os import wtforms_json from flask import Flask, redirect from flask_appbuilder import expose, IndexView +from flask_babel import gettext as __, lazy_gettext as _ from flask_compress import Compress from flask_wtf import CSRFProtect @@ -114,10 +115,321 @@ class SupersetAppInitializer: celery_app.Task = AppContextTask - @staticmethod - def init_views() -> None: - # TODO - This should iterate over all views and register them with FAB... - from superset import views # noqa pylint: disable=unused-variable + def init_views(self) -> None: + # + # We're doing local imports, as several of them import + # models which in turn try to import + # the global Flask app + # + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + from superset.connectors.druid.views import ( + DruidDatasourceModelView, + DruidClusterModelView, + DruidMetricInlineView, + DruidColumnInlineView, + Druid, + ) + from superset.connectors.sqla.views import ( + TableColumnInlineView, + SqlMetricInlineView, + TableModelView, + ) + from superset.views.annotations import ( + AnnotationLayerModelView, + AnnotationModelView, + ) + from superset.views.api import Api + from superset.views.core import ( + AccessRequestsModelView, + SliceModelView, + SliceAsync, + SliceAddView, + KV, + R, + Superset, + CssTemplateModelView, + CssTemplateAsyncModelView, + ) + from superset.views.dashboard.api import DashboardRestApi + from superset.views.dashboard.views import ( + DashboardModelView, + Dashboard, + DashboardAddView, + DashboardModelViewAsync, + ) + from superset.views.database.api import DatabaseRestApi + from superset.views.database.views import ( + DatabaseView, + DatabaseTablesAsync, + CsvToDatabaseView, + DatabaseAsync, + ) + from superset.views.datasource import Datasource + from superset.views.log.api import LogRestApi + from superset.views.log.views import LogModelView + from superset.views.schedules import ( + DashboardEmailScheduleView, + SliceEmailScheduleView, + ) + from superset.views.sql_lab import ( + QueryView, + SavedQueryViewApi, + SavedQueryView, + TabStateView, + TableSchemaView, + SqlLab, + ) + from superset.views.tags import TagView + + # + # Setup API views + # + appbuilder.add_api(DashboardRestApi) + appbuilder.add_api(DatabaseRestApi) + + # + # Setup regular views + # + appbuilder.add_view( + AnnotationLayerModelView, + "Annotation Layers", + label=__("Annotation Layers"), + icon="fa-comment", + category="Manage", + category_label=__("Manage"), + category_icon="", + ) + appbuilder.add_view( + AnnotationModelView, + "Annotations", + label=__("Annotations"), + icon="fa-comments", + category="Manage", + category_label=__("Manage"), + category_icon="", + ) + appbuilder.add_view( + SliceModelView, + "Charts", + label=__("Charts"), + icon="fa-bar-chart", + category="", + category_icon="", + ) + appbuilder.add_view( + DatabaseView, + "Databases", + label=__("Databases"), + icon="fa-database", + category="Sources", + category_label=__("Sources"), + category_icon="fa-database", + ) + appbuilder.add_view( + DashboardModelView, + "Dashboards", + label=__("Dashboards"), + icon="fa-dashboard", + category="", + category_icon="", + ) + appbuilder.add_view( + CssTemplateModelView, + "CSS Templates", + label=__("CSS Templates"), + icon="fa-css3", + category="Manage", + category_label=__("Manage"), + category_icon="", + ) + appbuilder.add_view( + QueryView, + "Queries", + label=__("Queries"), + category="Manage", + category_label=__("Manage"), + icon="fa-search", + ) + + # + # Setup views with no menu + # + appbuilder.add_view_no_menu(Api) + appbuilder.add_view_no_menu(CssTemplateAsyncModelView) + appbuilder.add_view_no_menu(CsvToDatabaseView) + appbuilder.add_view_no_menu(Dashboard) + appbuilder.add_view_no_menu(DashboardAddView) + appbuilder.add_view_no_menu(DashboardModelViewAsync) + appbuilder.add_view_no_menu(DatabaseAsync) + appbuilder.add_view_no_menu(DatabaseTablesAsync) + appbuilder.add_view_no_menu(Datasource) + appbuilder.add_view_no_menu(KV) + appbuilder.add_view_no_menu(R) + appbuilder.add_view_no_menu(SavedQueryView) + appbuilder.add_view_no_menu(SavedQueryViewApi) + appbuilder.add_view_no_menu(SliceAddView) + appbuilder.add_view_no_menu(SliceAsync) + appbuilder.add_view_no_menu(SqlLab) + appbuilder.add_view_no_menu(SqlMetricInlineView) + appbuilder.add_view_no_menu(Superset) + appbuilder.add_view_no_menu(TableColumnInlineView) + appbuilder.add_view_no_menu(TableModelView) + appbuilder.add_view_no_menu(TableSchemaView) + appbuilder.add_view_no_menu(TabStateView) + appbuilder.add_view_no_menu(TagView) + + # + # Add links + # + appbuilder.add_link( + __("Saved Queries"), + href="/sqllab/my_queries/", + icon="fa-save", + category="SQL Lab", + ) + appbuilder.add_link( + "Import Dashboards", + label=__("Import Dashboards"), + href="/superset/import_dashboards", + icon="fa-cloud-upload", + category="Manage", + category_label=__("Manage"), + category_icon="fa-wrench", + ) + appbuilder.add_link( + "SQL Editor", + label=_("SQL Editor"), + href="/superset/sqllab", + category_icon="fa-flask", + icon="fa-flask", + category="SQL Lab", + category_label=__("SQL Lab"), + ) + appbuilder.add_link( + "Query Search", + label=_("Query Search"), + href="/superset/sqllab#search", + icon="fa-search", + category_icon="fa-flask", + category="SQL Lab", + category_label=__("SQL Lab"), + ) + appbuilder.add_link( + "Upload a CSV", + label=__("Upload a CSV"), + href="/csvtodatabaseview/form", + icon="fa-upload", + category="Sources", + category_label=__("Sources"), + category_icon="fa-wrench", + ) + appbuilder.add_link( + "Tables", + label=__("Tables"), + href="/tablemodelview/list/?_flt_1_is_sqllab_view=y", + icon="fa-table", + category="Sources", + category_label=__("Sources"), + category_icon="fa-table", + ) + + # + # Conditionally setup log views + # + if ( + not self.config["FAB_ADD_SECURITY_VIEWS"] is False + or self.config["SUPERSET_LOG_VIEW"] is False + ): + appbuilder.add_api(LogRestApi) + appbuilder.add_view( + LogModelView, + "Action Log", + label=__("Action Log"), + category="Security", + category_label=__("Security"), + icon="fa-list-ol", + ) + + # + # Conditionally setup email views + # + if self.config["ENABLE_SCHEDULED_EMAIL_REPORTS"]: + appbuilder.add_separator("Manage") + appbuilder.add_view( + DashboardEmailScheduleView, + "Dashboard Email Schedules", + label=__("Dashboard Emails"), + category="Manage", + category_label=__("Manage"), + icon="fa-search", + ) + appbuilder.add_view( + SliceEmailScheduleView, + "Chart Emails", + label=__("Chart Email Schedules"), + category="Manage", + category_label=__("Manage"), + icon="fa-search", + ) + + # + # Conditionally add Access Request Model View + # + if self.config["ENABLE_ACCESS_REQUEST"]: + appbuilder.add_view( + AccessRequestsModelView, + "Access requests", + label=__("Access requests"), + category="Security", + category_label=__("Security"), + icon="fa-table", + ) + + # + # Conditionally setup Druid Views + # + if self.config["DRUID_IS_ACTIVE"]: + appbuilder.add_separator("Sources") + appbuilder.add_view( + DruidDatasourceModelView, + "Druid Datasources", + label=__("Druid Datasources"), + category="Sources", + category_label=__("Sources"), + icon="fa-cube", + ) + appbuilder.add_view( + DruidClusterModelView, + name="Druid Clusters", + label=__("Druid Clusters"), + icon="fa-cubes", + category="Sources", + category_label=__("Sources"), + category_icon="fa-database", + ) + appbuilder.add_view_no_menu(DruidMetricInlineView) + appbuilder.add_view_no_menu(DruidColumnInlineView) + appbuilder.add_view_no_menu(Druid) + appbuilder.add_link( + "Scan New Datasources", + label=__("Scan New Datasources"), + href="/druid/scan_new_datasources/", + category="Sources", + category_label=__("Sources"), + category_icon="fa-database", + icon="fa-refresh", + ) + appbuilder.add_link( + "Refresh Druid Metadata", + label=__("Refresh Druid Metadata"), + href="/druid/refresh_datasources/", + category="Sources", + category_label=__("Sources"), + category_icon="fa-database", + icon="fa-cog", + ) + appbuilder.add_separator("Sources") def init_app_in_ctx(self) -> None: """ @@ -125,6 +437,7 @@ class SupersetAppInitializer: """ self.configure_feature_flags() self.configure_fab() + self.configure_url_map_converters() self.configure_data_sources() # Hook that provides administrators a handle on the Flask APP @@ -203,6 +516,17 @@ class SupersetAppInitializer: appbuilder.update_perms = False appbuilder.init_app(self.flask_app, db.session) + def configure_url_map_converters(self): + # + # Doing local imports here as model importing causes a reference to + # app.config to be invoked and we need the current_app to have been setup + # + from superset.utils.url_map_converters import RegexConverter + from superset.utils.url_map_converters import ObjectTypeConverter + + self.flask_app.url_map.converters["regex"] = RegexConverter + self.flask_app.url_map.converters["object_type"] = ObjectTypeConverter + def configure_jinja_context(self): jinja_context_manager.init_app(self.flask_app) diff --git a/superset/connectors/druid/views.py b/superset/connectors/druid/views.py index 01a3c94fa..07f9c2ab5 100644 --- a/superset/connectors/druid/views.py +++ b/superset/connectors/druid/views.py @@ -406,54 +406,3 @@ class Druid(BaseSupersetView): datasources only and add them. """ return self.refresh_datasources(refresh_all=False) - - -if app.config["DRUID_IS_ACTIVE"]: - - appbuilder.add_separator("Sources") - - appbuilder.add_view( - DruidDatasourceModelView, - "Druid Datasources", - label=__("Druid Datasources"), - category="Sources", - category_label=__("Sources"), - icon="fa-cube", - ) - - appbuilder.add_view( - DruidClusterModelView, - name="Druid Clusters", - label=__("Druid Clusters"), - icon="fa-cubes", - category="Sources", - category_label=__("Sources"), - category_icon="fa-database", - ) - - appbuilder.add_view_no_menu(DruidMetricInlineView) - - appbuilder.add_view_no_menu(DruidColumnInlineView) - - appbuilder.add_view_no_menu(Druid) - - appbuilder.add_link( - "Scan New Datasources", - label=__("Scan New Datasources"), - href="/druid/scan_new_datasources/", - category="Sources", - category_label=__("Sources"), - category_icon="fa-database", - icon="fa-refresh", - ) - appbuilder.add_link( - "Refresh Druid Metadata", - label=__("Refresh Druid Metadata"), - href="/druid/refresh_datasources/", - category="Sources", - category_label=__("Sources"), - category_icon="fa-database", - icon="fa-cog", - ) - - appbuilder.add_separator("Sources") diff --git a/superset/connectors/sqla/views.py b/superset/connectors/sqla/views.py index b0e77aab6..c51057a46 100644 --- a/superset/connectors/sqla/views.py +++ b/superset/connectors/sqla/views.py @@ -162,9 +162,6 @@ class TableColumnInlineView(CompactCRUDMixin, SupersetModelView): edit_form_extra_fields = add_form_extra_fields -appbuilder.add_view_no_menu(TableColumnInlineView) - - class SqlMetricInlineView(CompactCRUDMixin, SupersetModelView): datamodel = SQLAInterface(models.SqlMetric) @@ -224,9 +221,6 @@ class SqlMetricInlineView(CompactCRUDMixin, SupersetModelView): edit_form_extra_fields = add_form_extra_fields -appbuilder.add_view_no_menu(SqlMetricInlineView) - - class TableModelView(DatasourceModelView, DeleteMixin, YamlExportMixin): datamodel = SQLAInterface(models.SqlaTable) @@ -426,15 +420,3 @@ class TableModelView(DatasourceModelView, DeleteMixin, YamlExportMixin): flash(failure_msg, "danger") return redirect("/tablemodelview/list/") - - -appbuilder.add_view_no_menu(TableModelView) -appbuilder.add_link( - "Tables", - label=__("Tables"), - href="/tablemodelview/list/?_flt_1_is_sqllab_view=y", - icon="fa-table", - category="Sources", - category_label=__("Sources"), - category_icon="fa-table", -) diff --git a/superset/utils/url_map_converters.py b/superset/utils/url_map_converters.py new file mode 100644 index 000000000..6697b7d42 --- /dev/null +++ b/superset/utils/url_map_converters.py @@ -0,0 +1,35 @@ +# 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. +from werkzeug.routing import BaseConverter + +from superset.models.tags import ObjectTypes + + +class RegexConverter(BaseConverter): + def __init__(self, url_map, *items): + super(RegexConverter, self).__init__(url_map) + self.regex = items[0] + + +class ObjectTypeConverter(BaseConverter): + """Validate that object_type is indeed an object type.""" + + def to_python(self, value): + return ObjectTypes[value] + + def to_url(self, value): + return value.name diff --git a/superset/views/annotations.py b/superset/views/annotations.py index 757e41284..33fdb3825 100644 --- a/superset/views/annotations.py +++ b/superset/views/annotations.py @@ -15,10 +15,9 @@ # specific language governing permissions and limitations # under the License. from flask_appbuilder.models.sqla.interface import SQLAInterface -from flask_babel import gettext as __, lazy_gettext as _ +from flask_babel import lazy_gettext as _ from wtforms.validators import StopValidation -from superset import appbuilder from superset.models.annotations import Annotation, AnnotationLayer from .base import DeleteMixin, SupersetModelView @@ -105,23 +104,3 @@ class AnnotationLayerModelView( add_columns = edit_columns label_columns = {"name": _("Name"), "descr": _("Description")} - - -appbuilder.add_view( - AnnotationLayerModelView, - "Annotation Layers", - label=__("Annotation Layers"), - icon="fa-comment", - category="Manage", - category_label=__("Manage"), - category_icon="", -) -appbuilder.add_view( - AnnotationModelView, - "Annotations", - label=__("Annotations"), - icon="fa-comments", - category="Manage", - category_label=__("Manage"), - category_icon="", -) diff --git a/superset/views/api.py b/superset/views/api.py index bfe70f0c1..556e816c7 100644 --- a/superset/views/api.py +++ b/superset/views/api.py @@ -20,7 +20,7 @@ from flask import request from flask_appbuilder import expose from flask_appbuilder.security.decorators import has_access_api -from superset import appbuilder, db, event_logger, security_manager +from superset import db, event_logger, security_manager from superset.common.query_context import QueryContext from superset.legacy import update_time_range from superset.models.slice import Slice @@ -70,6 +70,3 @@ class Api(BaseSupersetView): update_time_range(form_data) return json.dumps(form_data) - - -appbuilder.add_view_no_menu(Api) diff --git a/superset/views/core.py b/superset/views/core.py index d2262e37f..2742c6c21 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -106,9 +106,7 @@ from .base import ( json_success, SupersetModelView, ) -from .dashboard import views as dash_views from .dashboard.filters import DashboardFilter -from .database import views as in_views from .utils import ( apply_display_max_row_limit, bootstrap_user_data, @@ -260,36 +258,25 @@ class SliceFilter(BaseFilter): ) -if config["ENABLE_ACCESS_REQUEST"]: - - class AccessRequestsModelView(SupersetModelView, DeleteMixin): - datamodel = SQLAInterface(DAR) - list_columns = [ - "username", - "user_roles", - "datasource_link", - "roles_with_datasource", - "created_on", - ] - order_columns = ["created_on"] - base_order = ("changed_on", "desc") - label_columns = { - "username": _("User"), - "user_roles": _("User Roles"), - "database": _("Database URL"), - "datasource_link": _("Datasource"), - "roles_with_datasource": _("Roles to grant"), - "created_on": _("Created On"), - } - - appbuilder.add_view( - AccessRequestsModelView, - "Access requests", - label=__("Access requests"), - category="Security", - category_label=__("Security"), - icon="fa-table", - ) +class AccessRequestsModelView(SupersetModelView, DeleteMixin): + datamodel = SQLAInterface(DAR) + list_columns = [ + "username", + "user_roles", + "datasource_link", + "roles_with_datasource", + "created_on", + ] + order_columns = ["created_on"] + base_order = ("changed_on", "desc") + label_columns = { + "username": _("User"), + "user_roles": _("User Roles"), + "database": _("Database URL"), + "datasource_link": _("Datasource"), + "roles_with_datasource": _("Roles to grant"), + "created_on": _("Created On"), + } class SliceModelView(SupersetModelView, DeleteMixin): @@ -384,16 +371,6 @@ class SliceModelView(SupersetModelView, DeleteMixin): ) -appbuilder.add_view( - SliceModelView, - "Charts", - label=__("Charts"), - icon="fa-bar-chart", - category="", - category_icon="", -) - - class SliceAsync(SliceModelView): route_base = "/sliceasync" list_columns = [ @@ -409,9 +386,6 @@ class SliceAsync(SliceModelView): label_columns = {"icons": " ", "slice_link": _("Chart")} -appbuilder.add_view_no_menu(SliceAsync) - - class SliceAddView(SliceModelView): route_base = "/sliceaddview" list_columns = [ @@ -434,19 +408,6 @@ class SliceAddView(SliceModelView): ] -appbuilder.add_view_no_menu(SliceAddView) - - -appbuilder.add_view( - dash_views.DashboardModelView, - "Dashboards", - label=__("Dashboards"), - icon="fa-dashboard", - category="", - category_icon="", -) - - @talisman(force_https=False) @app.route("/health") def health(): @@ -495,9 +456,6 @@ class KV(BaseSupersetView): return Response(kv.value, status=200, content_type="text/plain") -appbuilder.add_view_no_menu(KV) - - class R(BaseSupersetView): """used for short urls""" @@ -533,9 +491,6 @@ class R(BaseSupersetView): ) -appbuilder.add_view_no_menu(R) - - class Superset(BaseSupersetView): """The base views for Superset!""" @@ -2997,9 +2952,6 @@ class Superset(BaseSupersetView): ) -appbuilder.add_view_no_menu(Superset) - - class CssTemplateModelView(SupersetModelView, DeleteMixin): datamodel = SQLAInterface(models.CssTemplate) @@ -3018,50 +2970,6 @@ class CssTemplateAsyncModelView(CssTemplateModelView): list_columns = ["template_name", "css"] -appbuilder.add_view( - CssTemplateModelView, - "CSS Templates", - label=__("CSS Templates"), - icon="fa-css3", - category="Manage", - category_label=__("Manage"), - category_icon="", -) - - -appbuilder.add_view_no_menu(CssTemplateAsyncModelView) - -appbuilder.add_link( - "SQL Editor", - label=_("SQL Editor"), - href="/superset/sqllab", - category_icon="fa-flask", - icon="fa-flask", - category="SQL Lab", - category_label=__("SQL Lab"), -) - -appbuilder.add_link( - "Query Search", - label=_("Query Search"), - href="/superset/sqllab#search", - icon="fa-search", - category_icon="fa-flask", - category="SQL Lab", - category_label=__("SQL Lab"), -) - -appbuilder.add_link( - "Upload a CSV", - label=__("Upload a CSV"), - href="/csvtodatabaseview/form", - icon="fa-upload", - category="Sources", - category_label=__("Sources"), - category_icon="fa-wrench", -) - - @app.after_request def apply_http_headers(response: Response): """Applies the configuration's http headers to all responses""" @@ -3077,17 +2985,6 @@ def apply_http_headers(response: Response): return response -# --------------------------------------------------------------------- -# Redirecting URL from previous names -class RegexConverter(BaseConverter): - def __init__(self, url_map, *items): - super(RegexConverter, self).__init__(url_map) - self.regex = items[0] - - -app.url_map.converters["regex"] = RegexConverter - - @app.route('/') def panoramix(url): return redirect(request.full_path.replace("panoramix", "superset")) diff --git a/superset/views/dashboard/api.py b/superset/views/dashboard/api.py index 5b6f53593..134506b2a 100644 --- a/superset/views/dashboard/api.py +++ b/superset/views/dashboard/api.py @@ -24,7 +24,6 @@ from marshmallow import fields, post_load, pre_load, Schema, ValidationError from marshmallow.validate import Length from sqlalchemy.exc import SQLAlchemyError -from superset import appbuilder from superset.exceptions import SupersetException from superset.models.dashboard import Dashboard from superset.utils import core as utils @@ -357,6 +356,3 @@ class DashboardRestApi(DashboardMixin, BaseSupersetModelRestApi): return self.response(200, message="OK") except SQLAlchemyError as e: return self.response_422(message=str(e)) - - -appbuilder.add_api(DashboardRestApi) diff --git a/superset/views/dashboard/views.py b/superset/views/dashboard/views.py index c5e891dbb..5adde76d5 100644 --- a/superset/views/dashboard/views.py +++ b/superset/views/dashboard/views.py @@ -24,7 +24,7 @@ from flask_appbuilder.security.decorators import has_access from flask_babel import gettext as __, lazy_gettext as _ import superset.models.core as models -from superset import appbuilder, db, event_logger +from superset import db, event_logger from superset.utils import core as utils from ..base import ( @@ -100,9 +100,6 @@ class Dashboard(BaseSupersetView): return redirect(f"/superset/dashboard/{new_dashboard.id}/?edit=true") -appbuilder.add_view_no_menu(Dashboard) - - class DashboardModelViewAsync(DashboardModelView): # pylint: disable=too-many-ancestors route_base = "/dashboardasync" list_columns = [ @@ -123,9 +120,6 @@ class DashboardModelViewAsync(DashboardModelView): # pylint: disable=too-many-a } -appbuilder.add_view_no_menu(DashboardModelViewAsync) - - class DashboardAddView(DashboardModelView): # pylint: disable=too-many-ancestors route_base = "/dashboardaddview" list_columns = [ @@ -139,6 +133,3 @@ class DashboardAddView(DashboardModelView): # pylint: disable=too-many-ancestor "changed_by_name", ] show_columns = list(set(DashboardModelView.edit_columns + list_columns)) - - -appbuilder.add_view_no_menu(DashboardAddView) diff --git a/superset/views/database/api.py b/superset/views/database/api.py index 8578e29a8..0c1b688a9 100644 --- a/superset/views/database/api.py +++ b/superset/views/database/api.py @@ -18,7 +18,6 @@ from flask_appbuilder import ModelRestApi from flask_appbuilder.models.sqla.interface import SQLAInterface import superset.models.core as models -from superset import appbuilder from .mixins import DatabaseFilter, DatabaseMixin from .validators import sqlalchemy_uri_validator @@ -58,6 +57,3 @@ class DatabaseRestApi(DatabaseMixin, ModelRestApi): # Removes the local limit for the page size max_page_size = -1 validators_columns = {"sqlalchemy_uri": sqlalchemy_uri_validator} - - -appbuilder.add_api(DatabaseRestApi) diff --git a/superset/views/database/views.py b/superset/views/database/views.py index 9cafe07d3..19620e1d1 100644 --- a/superset/views/database/views.py +++ b/superset/views/database/views.py @@ -19,13 +19,13 @@ import os from flask import flash, g, redirect from flask_appbuilder import SimpleFormView from flask_appbuilder.models.sqla.interface import SQLAInterface -from flask_babel import gettext as __, lazy_gettext as _ +from flask_babel import lazy_gettext as _ from werkzeug.utils import secure_filename from wtforms.fields import StringField from wtforms.validators import ValidationError import superset.models.core as models -from superset import app, appbuilder, db +from superset import app, db from superset.connectors.sqla.models import SqlaTable from superset.utils import core as utils from superset.views.base import DeleteMixin, SupersetModelView, YamlExportMixin @@ -60,28 +60,6 @@ class DatabaseView( DeleteMixin._delete(self, pk) -appbuilder.add_link( - "Import Dashboards", - label=__("Import Dashboards"), - href="/superset/import_dashboards", - icon="fa-cloud-upload", - category="Manage", - category_label=__("Manage"), - category_icon="fa-wrench", -) - - -appbuilder.add_view( - DatabaseView, - "Databases", - label=__("Databases"), - icon="fa-database", - category="Sources", - category_label=__("Sources"), - category_icon="fa-database", -) - - class CsvToDatabaseView(SimpleFormView): form = CsvToDatabaseForm form_template = "superset/form_view/csv_to_database_view/edit.html" @@ -181,16 +159,10 @@ class CsvToDatabaseView(SimpleFormView): return redirect("/tablemodelview/list/") -appbuilder.add_view_no_menu(CsvToDatabaseView) - - class DatabaseTablesAsync(DatabaseView): # pylint: disable=too-many-ancestors list_columns = ["id", "all_table_names_in_database", "all_schema_names"] -appbuilder.add_view_no_menu(DatabaseTablesAsync) - - class DatabaseAsync(DatabaseView): # pylint: disable=too-many-ancestors list_columns = [ "id", @@ -205,6 +177,3 @@ class DatabaseAsync(DatabaseView): # pylint: disable=too-many-ancestors "allows_subquery", "backend", ] - - -appbuilder.add_view_no_menu(DatabaseAsync) diff --git a/superset/views/datasource.py b/superset/views/datasource.py index 1f282389d..73e8e4be2 100644 --- a/superset/views/datasource.py +++ b/superset/views/datasource.py @@ -22,7 +22,7 @@ from flask_appbuilder import expose from flask_appbuilder.security.decorators import has_access_api from sqlalchemy.orm.exc import NoResultFound -from superset import appbuilder, db +from superset import db from superset.connectors.connector_registry import ConnectorRegistry from superset.models.core import Database @@ -114,6 +114,3 @@ class Datasource(BaseSupersetView): raise Exception(f"Unsupported datasource_type: {datasource_type}") external_metadata = datasource.external_metadata() return self.json_response(external_metadata) - - -appbuilder.add_view_no_menu(Datasource) diff --git a/superset/views/log/api.py b/superset/views/log/api.py index 02b3d1b9f..c26e0917d 100644 --- a/superset/views/log/api.py +++ b/superset/views/log/api.py @@ -18,7 +18,6 @@ from flask_appbuilder import ModelRestApi from flask_appbuilder.models.sqla.interface import SQLAInterface import superset.models.core as models -from superset import app, appbuilder from . import LogMixin @@ -39,10 +38,3 @@ class LogRestApi(LogMixin, ModelRestApi): allow_browser_login = True list_columns = ("user.username", "action", "dttm") show_columns = list_columns - - -if ( - not app.config["FAB_ADD_SECURITY_VIEWS"] is False - or app.config["SUPERSET_LOG_VIEW"] is False -): - appbuilder.add_api(LogRestApi) diff --git a/superset/views/log/views.py b/superset/views/log/views.py index 58e1e2978..a9f3bd016 100644 --- a/superset/views/log/views.py +++ b/superset/views/log/views.py @@ -15,10 +15,8 @@ # specific language governing permissions and limitations # under the License. from flask_appbuilder.models.sqla.interface import SQLAInterface -from flask_babel import gettext as __ import superset.models.core as models -from superset import app, appbuilder from superset.views.base import SupersetModelView from . import LogMixin @@ -26,17 +24,3 @@ from . import LogMixin class LogModelView(LogMixin, SupersetModelView): # pylint: disable=too-many-ancestors datamodel = SQLAInterface(models.Log) - - -if ( - not app.config["FAB_ADD_SECURITY_VIEWS"] is False - or app.config["SUPERSET_LOG_VIEW"] is False -): - appbuilder.add_view( - LogModelView, - "Action Log", - label=__("Action Log"), - category="Security", - category_label=__("Security"), - icon="fa-list-ol", - ) diff --git a/superset/views/schedules.py b/superset/views/schedules.py index ae6456d53..c1f690d81 100644 --- a/superset/views/schedules.py +++ b/superset/views/schedules.py @@ -23,10 +23,10 @@ from flask import flash, g from flask_appbuilder import expose from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_appbuilder.security.decorators import has_access -from flask_babel import gettext as __, lazy_gettext as _ +from flask_babel import lazy_gettext as _ from wtforms import BooleanField, StringField -from superset import app, appbuilder, db, security_manager +from superset import db, security_manager from superset.exceptions import SupersetException from superset.models.dashboard import Dashboard from superset.models.schedules import ( @@ -271,29 +271,3 @@ class SliceEmailScheduleView(EmailScheduleView): # pylint: disable=too-many-anc if item.slice is None: raise SupersetException("Slice is mandatory") super(SliceEmailScheduleView, self).pre_add(item) - - -def _register_schedule_menus(): - appbuilder.add_separator("Manage") - - appbuilder.add_view( - DashboardEmailScheduleView, - "Dashboard Email Schedules", - label=__("Dashboard Emails"), - category="Manage", - category_label=__("Manage"), - icon="fa-search", - ) - - appbuilder.add_view( - SliceEmailScheduleView, - "Chart Emails", - label=__("Chart Email Schedules"), - category="Manage", - category_label=__("Manage"), - icon="fa-search", - ) - - -if app.config["ENABLE_SCHEDULED_EMAIL_REPORTS"]: - _register_schedule_menus() diff --git a/superset/views/sql_lab.py b/superset/views/sql_lab.py index 0796f1688..e53141868 100644 --- a/superset/views/sql_lab.py +++ b/superset/views/sql_lab.py @@ -21,10 +21,10 @@ from flask import g, 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 gettext as __, lazy_gettext as _ +from flask_babel import lazy_gettext as _ from flask_sqlalchemy import BaseQuery -from superset import appbuilder, db, get_feature_flags, security_manager +from superset import db, get_feature_flags, security_manager from superset.models.sql_lab import Query, SavedQuery, TableSchema, TabState from superset.utils import core as utils @@ -71,16 +71,6 @@ class QueryView(SupersetModelView): } -appbuilder.add_view( - QueryView, - "Queries", - label=__("Queries"), - category="Manage", - category_label=__("Manage"), - icon="fa-search", -) - - class SavedQueryView( SupersetModelView, DeleteMixin ): # pylint: disable=too-many-ancestors @@ -173,10 +163,6 @@ class SavedQueryViewApi(SavedQueryView): # pylint: disable=too-many-ancestors return super().show(pk) -appbuilder.add_view_no_menu(SavedQueryViewApi) -appbuilder.add_view_no_menu(SavedQueryView) - - def _get_owner_id(tab_state_id): return db.session.query(TabState.user_id).filter_by(id=tab_state_id).scalar() @@ -332,15 +318,6 @@ class TableSchemaView(BaseSupersetView): return json_success(response) -appbuilder.add_view_no_menu(TabStateView) -appbuilder.add_view_no_menu(TableSchemaView) - - -appbuilder.add_link( - __("Saved Queries"), href="/sqllab/my_queries/", icon="fa-save", category="SQL Lab" -) - - class SqlLab(BaseSupersetView): """The base views for Superset!""" @@ -349,6 +326,3 @@ class SqlLab(BaseSupersetView): def my_queries(self): # pylint: disable=no-self-use """Assigns a list of found users to the given role.""" return redirect("/savedqueryview/list/?_flt_0_user={}".format(g.user.id)) - - -appbuilder.add_view_no_menu(SqlLab) diff --git a/superset/views/tags.py b/superset/views/tags.py index df664b1e0..decbdc2f6 100644 --- a/superset/views/tags.py +++ b/superset/views/tags.py @@ -22,9 +22,8 @@ from flask_appbuilder import expose from flask_appbuilder.security.decorators import has_access_api from jinja2.sandbox import SandboxedEnvironment from sqlalchemy import and_, func -from werkzeug.routing import BaseConverter -from superset import app, appbuilder, db, utils +from superset import db, utils from superset.jinja_context import current_user_id, current_username from superset.models.dashboard import Dashboard from superset.models.slice import Slice @@ -34,17 +33,6 @@ from superset.models.tags import ObjectTypes, Tag, TaggedObject, TagTypes from .base import BaseSupersetView, json_success -class ObjectTypeConverter(BaseConverter): - - """Validate that object_type is indeed an object type.""" - - def to_python(self, value): - return ObjectTypes[value] - - def to_url(self, value): - return value.name - - def process_template(content): env = SandboxedEnvironment() template = env.from_string(content) @@ -228,7 +216,3 @@ class TagView(BaseSupersetView): ) return json_success(json.dumps(results, default=utils.core.json_int_dttm_ser)) - - -app.url_map.converters["object_type"] = ObjectTypeConverter -appbuilder.add_view_no_menu(TagView)