Skip to content

Commit

Permalink
refactor: [migration] convert iframe chart into dashboard markdown co…
Browse files Browse the repository at this point in the history
…mponent
  • Loading branch information
Grace committed Aug 12, 2020
1 parent bd88e12 commit eb04aa4
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 6 deletions.
4 changes: 3 additions & 1 deletion superset-frontend/src/dashboard/reducers/getInitialState.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ export default function (bootstrapData) {
const sliceIds = new Set();
dashboard.slices.forEach(slice => {
const key = slice.slice_id;
if (['separator', 'markup'].indexOf(slice.form_data.viz_type) === -1) {
if (
['separator', 'markup', 'iframe'].indexOf(slice.form_data.viz_type) === -1
) {
const form_data = {
...slice.form_data,
url_params: {
Expand Down
6 changes: 5 additions & 1 deletion superset-frontend/src/explore/components/SaveModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class SaveModal extends React.Component {
this.setState({ alert: null });
}
render() {
// do not add iframe/markdown/separator chart to dashboard
const canNotSaveToDash =
EXPLORE_ONLY_VIZ_TYPE.indexOf(this.state.vizType) > -1;
return (
Expand Down Expand Up @@ -239,7 +240,10 @@ class SaveModal extends React.Component {
bsSize="sm"
bsStyle="primary"
onClick={this.saveOrOverwrite.bind(this, false)}
disabled={!this.state.newSliceName}
disabled={
!this.state.newSliceName ||
(canNotSaveToDash && this.state.newDashboardName)
}
>
{t('Save')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ const DEFAULT_ORDER = [
'line_multi',
'treemap',
'box_plot',
'separator',
'sunburst',
'sankey',
'word_cloud',
Expand All @@ -85,7 +84,6 @@ const DEFAULT_ORDER = [
'bubble',
'deck_geojson',
'horizon',
'markup',
'deck_multi',
'compare',
'partition',
Expand All @@ -95,7 +93,6 @@ const DEFAULT_ORDER = [
'world_map',
'paired_ttest',
'para',
'iframe',
'country_map',
];

Expand Down
2 changes: 1 addition & 1 deletion superset-frontend/src/explore/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const sqlaAutoGeneratedMetricNameRegex = /^(sum|min|max|avg|count|count_d
export const sqlaAutoGeneratedMetricRegex = /^(LONG|DOUBLE|FLOAT)?(SUM|AVG|MAX|MIN|COUNT)\([A-Z0-9_."]*\)$/i;
export const druidAutoGeneratedMetricRegex = /^(LONG|DOUBLE|FLOAT)?(SUM|MAX|MIN|COUNT)\([A-Z0-9_."]*\)$/i;

export const EXPLORE_ONLY_VIZ_TYPE = ['separator', 'markup'];
export const EXPLORE_ONLY_VIZ_TYPE = ['separator', 'markup', 'iframe'];

export const TIME_FILTER_LABELS = {
time_range: t('Time Range'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# 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.
"""Migrate iframe in dashboard to markdown component
Revision ID: 978245563a02
Revises: f2672aa8350a
Create Date: 2020-08-12 00:24:39.617899
"""
import collections
import json
import logging
import uuid
from collections import defaultdict

from alembic import op
from sqlalchemy import and_, Column, ForeignKey, Integer, String, Table, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

from superset import db

# revision identifiers, used by Alembic.
revision = "978245563a02"
down_revision = "f2672aa8350a"

Base = declarative_base()


class Slice(Base):
"""Declarative class to do query in upgrade"""

__tablename__ = "slices"
id = Column(Integer, primary_key=True)
params = Column(Text)
viz_type = Column(String(250))


dashboard_slices = Table(
"dashboard_slices",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("dashboard_id", Integer, ForeignKey("dashboards.id")),
Column("slice_id", Integer, ForeignKey("slices.id")),
)


class Dashboard(Base):
__tablename__ = "dashboards"
id = Column(Integer, primary_key=True)
position_json = Column(Text)
slices = relationship("Slice", secondary=dashboard_slices, backref="dashboards")


def create_new_markdown_component(chart_position, url):
return {
"type": "MARKDOWN",
"id": "MARKDOWN-{}".format(uuid.uuid4().hex[:8]),
"children": [],
"parents": chart_position["parents"],
"meta": {
"width": chart_position["meta"]["width"],
"height": chart_position["meta"]["height"],
"code": f'<iframe src="{url}" width="100%" height="100%"></iframe>',
},
}


def upgrade():
bind = op.get_bind()
session = db.Session(bind=bind)

dash_to_migrate = defaultdict(list)
iframe_urls = defaultdict(list)

try:
# find iframe viz_type and its url
iframes = session.query(Slice).filter_by(viz_type="iframe").all()
iframe_ids = [slc.id for slc in iframes]

for iframe in iframes:
iframe_params = json.loads(iframe.params or "{}")
url = iframe_params.get("url")
iframe_urls[iframe.id] = url

# find iframe viz_type that used in dashboard
dash_slc = (
session.query(dashboard_slices)
.filter(dashboard_slices.c.slice_id.in_(iframe_ids))
.all()
)
for entry in dash_slc:
dash_to_migrate[entry.dashboard_id].append(entry.slice_id)
dashboard_ids = list(dash_to_migrate.keys())

# replace iframe in dashboard metadata
dashboards = (
session.query(Dashboard).filter(Dashboard.id.in_(dashboard_ids)).all()
)
for i, dashboard in enumerate(dashboards):
print(
f"scanning dashboard ({i + 1}/{len(dashboards)}) dashboard: {dashboard.id} >>>>"
)

# remove iframe slices from dashboard
dashboard.slices = [
slc for slc in dashboard.slices if slc.id not in iframe_ids
]

# find iframe chart position in metadata
# and replace it with markdown component
position_dict = json.loads(dashboard.position_json or "{}")
for key, value in position_dict.items():
if (
value
and isinstance(value, dict)
and value["type"] == "CHART"
and value["meta"]
and value["meta"]["chartId"] in iframe_ids
):
iframe_id = value["meta"]["chartId"]
# make new markdown component
markdown = create_new_markdown_component(
value, iframe_urls[iframe_id]
)
position_dict.pop(key)
position_dict[markdown["id"]] = markdown

# add markdown to layout tree
parent_id = markdown["parents"][-1]
children = position_dict[parent_id]["children"]
children.remove(key)
children.append(markdown["id"])

dashboard.position_json = json.dumps(
position_dict,
indent=None,
separators=(",", ":"),
sort_keys=True,
)
session.merge(dashboard)
except Exception as ex:
logging.exception(f"dashboard {dashboard.id} has error: {ex}")

session.commit()
session.close()


def downgrade():
pass

0 comments on commit eb04aa4

Please sign in to comment.