Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/apache/superset into rm-t…
Browse files Browse the repository at this point in the history
…ime-range
  • Loading branch information
hughhhh committed Mar 30, 2022
2 parents a2159fe + 8e29ec5 commit 238dceb
Show file tree
Hide file tree
Showing 54 changed files with 1,444 additions and 172 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ specific language governing permissions and limitations
under the License.
-->
## Change Log

### 1.4.2 (Sat Mar 19 00:08:06 2022 +0200)
**Features**
- [#19248](https://github.com/apache/superset/pull/19248) feat: add support for comments in adhoc clauses (@villebro)
- [#18214](https://github.com/apache/superset/pull/18214) feat(docker-compose): add TAG option (@villebro)

**Fixes**
- [#17641](https://github.com/apache/superset/pull/17641) fix(sqla): make text clause escaping optional (@villebro)
- [#18566](https://github.com/apache/superset/pull/18566) fix(plugin-chart-echarts): area chart opacity bug (@villebro)

### 1.4.1
**Database Migrations**

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/contributing/contributing-page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ version: 1
## Contributing to Superset

Superset is an [Apache Software foundation](https://www.apache.org/theapacheway/index.html) project.
The core contributors (or committers) to Superset communicate primarily in the following channels (all of
which you can join):
The core contributors (or committers) to Superset communicate primarily in the following channels (
which can be joined by anyone):

- [Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org)
- [Apache Superset Slack community](https://join.slack.com/t/apache-superset/shared_invite/zt-16jvzmoi8-sI7jKWp~xc2zYRe~NqiY9Q)
Expand Down
5 changes: 4 additions & 1 deletion scripts/benchmark_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ def find_models(module: ModuleType) -> List[Type[Model]]:
while tables:
table = tables.pop()
seen.add(table)
model = getattr(Base.classes, table)
try:
model = getattr(Base.classes, table)
except AttributeError:
continue
model.__tablename__ = table
models.append(model)

Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
from setuptools import find_packages, setup

BASE_DIR = os.path.abspath(os.path.dirname(__file__))

PACKAGE_JSON = os.path.join(BASE_DIR, "superset-frontend", "package.json")

with open(PACKAGE_JSON, "r") as package_file:
version_string = json.load(package_file)["version"]

Expand Down Expand Up @@ -111,6 +111,7 @@ def get_git_sha() -> str:
"slackclient==2.5.0", # PINNED! slack changes file upload api in the future versions
"sqlalchemy>=1.3.16, <1.4, !=1.3.21",
"sqlalchemy-utils>=0.37.8, <0.38",
"sqloxide==0.1.15",
"sqlparse==0.3.0", # PINNED! see https://github.com/andialbrecht/sqlparse/issues/562
"tabulate==0.8.9",
# needed to support Literal (3.8) and TypeGuard (3.10)
Expand Down
2 changes: 1 addition & 1 deletion superset-embedded-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@superset-ui/embedded-sdk",
"version": "0.1.0-alpha.6",
"version": "0.1.0-alpha.7",
"description": "SDK for embedding resources from Superset into your own application",
"access": "public",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion superset-embedded-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export async function embedDashboard({
resolve(new Switchboard({ port: ourPort, name: 'superset-embedded-sdk', debug }));
});

iframe.src = `${supersetDomain}/dashboard/${id}/embedded${dashboardConfig}`;
iframe.src = `${supersetDomain}/embedded/${id}${dashboardConfig}`;
mountPoint.replaceChildren(iframe);
log('placed the iframe')
});
Expand Down
1 change: 1 addition & 0 deletions superset-frontend/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ module.exports = {
'fixtures.*',
'cypress-base/cypress/**/*',
'Stories.tsx',
'packages/superset-ui-core/src/style/index.tsx',
],
rules: {
'theme-colors/no-literal-colors': 0,
Expand Down
228 changes: 228 additions & 0 deletions superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/**
* 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, { useCallback, useEffect, useState } from 'react';
import { makeApi, styled, SupersetApiError, t } from '@superset-ui/core';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
import Modal from 'src/components/Modal';
import Loading from 'src/components/Loading';
import Button from 'src/components/Button';
import { Input } from 'src/components/Input';
import { useToasts } from 'src/components/MessageToasts/withToasts';
import { FormItem } from 'src/components/Form';
import { EmbeddedDashboard } from '../types';

type Props = {
dashboardId: string;
show: boolean;
onHide: () => void;
};

type EmbeddedApiPayload = { allowed_domains: string[] };

const stringToList = (stringyList: string): string[] =>
stringyList.split(/(?:\s|,)+/).filter(x => x);

const ButtonRow = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-end;
`;

export const DashboardEmbedControls = ({ dashboardId, onHide }: Props) => {
const { addInfoToast, addDangerToast } = useToasts();
const [ready, setReady] = useState(true); // whether we have initialized yet
const [loading, setLoading] = useState(false); // whether we are currently doing an async thing
const [embedded, setEmbedded] = useState<EmbeddedDashboard | null>(null); // the embedded dashboard config
const [allowedDomains, setAllowedDomains] = useState<string>('');

const endpoint = `/api/v1/dashboard/${dashboardId}/embedded`;
// whether saveable changes have been made to the config
const isDirty =
!embedded ||
stringToList(allowedDomains).join() !== embedded.allowed_domains.join();

const enableEmbedded = useCallback(() => {
setLoading(true);
makeApi<EmbeddedApiPayload, { result: EmbeddedDashboard }>({
method: 'POST',
endpoint,
})({
allowed_domains: stringToList(allowedDomains),
})
.then(
({ result }) => {
setEmbedded(result);
setAllowedDomains(result.allowed_domains.join(', '));
addInfoToast(t('Changes saved.'));
},
err => {
console.error(err);
addDangerToast(
t(
t('Sorry, something went wrong. The changes could not be saved.'),
),
);
},
)
.finally(() => {
setLoading(false);
});
}, [endpoint, allowedDomains]);

const disableEmbedded = useCallback(() => {
Modal.confirm({
title: t('Disable embedding?'),
content: t('This will remove your current embed configuration.'),
okType: 'danger',
onOk: () => {
setLoading(true);
makeApi<{}>({ method: 'DELETE', endpoint })({})
.then(
() => {
setEmbedded(null);
setAllowedDomains('');
addInfoToast(t('Embedding deactivated.'));
onHide();
},
err => {
console.error(err);
addDangerToast(
t(
'Sorry, something went wrong. Embedding could not be deactivated.',
),
);
},
)
.finally(() => {
setLoading(false);
});
},
});
}, [endpoint]);

useEffect(() => {
setReady(false);
makeApi<{}, { result: EmbeddedDashboard }>({
method: 'GET',
endpoint,
})({})
.catch(err => {
if ((err as SupersetApiError).status === 404) {
// 404 just means the dashboard isn't currently embedded
return { result: null };
}
throw err;
})
.then(({ result }) => {
setReady(true);
setEmbedded(result);
setAllowedDomains(result ? result.allowed_domains.join(', ') : '');
});
}, [dashboardId]);

if (!ready) {
return <Loading />;
}

return (
<>
<p>
{embedded ? (
<>
{t(
'This dashboard is ready to embed. In your application, pass the following id to the SDK:',
)}
<br />
<code>{embedded.uuid}</code>
</>
) : (
t(
'Configure this dashboard to embed it into an external web application.',
)
)}
</p>
<p>
{t('For further instructions, consult the')}{' '}
<a
href="https://www.npmjs.com/package/@superset-ui/embedded-sdk"
target="_blank"
rel="noreferrer"
>
{t('Superset Embedded SDK documentation.')}
</a>
</p>
<h3>Settings</h3>
<FormItem>
<label htmlFor="allowed-domains">
{t('Allowed Domains (comma separated)')}{' '}
<InfoTooltipWithTrigger
tooltip={t(
'A list of domain names that can embed this dashboard. Leaving this field empty will allow embedding from any domain.',
)}
/>
</label>
<Input
name="allowed-domains"
value={allowedDomains}
placeholder="superset.example.com"
onChange={event => setAllowedDomains(event.target.value)}
/>
</FormItem>
<ButtonRow>
{embedded ? (
<>
<Button
onClick={disableEmbedded}
buttonStyle="secondary"
loading={loading}
>
{t('Deactivate')}
</Button>
<Button
onClick={enableEmbedded}
buttonStyle="primary"
disabled={!isDirty}
loading={loading}
>
{t('Save changes')}
</Button>
</>
) : (
<Button
onClick={enableEmbedded}
buttonStyle="primary"
loading={loading}
>
{t('Enable embedding')}
</Button>
)}
</ButtonRow>
</>
);
};

export const DashboardEmbedModal = (props: Props) => {
const { show, onHide } = props;

return (
<Modal show={show} onHide={onHide} title={t('Embed')} hideFooter>
<DashboardEmbedControls {...props} />
</Modal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ const propTypes = {
userCanEdit: PropTypes.bool.isRequired,
userCanShare: PropTypes.bool.isRequired,
userCanSave: PropTypes.bool.isRequired,
userCanCurate: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired,
layout: PropTypes.object.isRequired,
expandedSlices: PropTypes.object.isRequired,
onSave: PropTypes.func.isRequired,
showPropertiesModal: PropTypes.func.isRequired,
manageEmbedded: PropTypes.func.isRequired,
refreshLimit: PropTypes.number,
refreshWarning: PropTypes.string,
lastModifiedTime: PropTypes.number.isRequired,
Expand All @@ -88,6 +90,7 @@ const MENU_KEYS = {
EDIT_CSS: 'edit-css',
DOWNLOAD_AS_IMAGE: 'download-as-image',
TOGGLE_FULLSCREEN: 'toggle-fullscreen',
MANAGE_EMBEDDED: 'manage-embedded',
};

const DropdownButton = styled.div`
Expand Down Expand Up @@ -182,6 +185,10 @@ class HeaderActionsDropdown extends React.PureComponent {
window.location.replace(url);
break;
}
case MENU_KEYS.MANAGE_EMBEDDED: {
this.props.manageEmbedded();
break;
}
default:
break;
}
Expand All @@ -204,6 +211,7 @@ class HeaderActionsDropdown extends React.PureComponent {
userCanEdit,
userCanShare,
userCanSave,
userCanCurate,
isLoading,
refreshLimit,
refreshWarning,
Expand Down Expand Up @@ -313,6 +321,12 @@ class HeaderActionsDropdown extends React.PureComponent {
</Menu.Item>
)}

{!editMode && userCanCurate && (
<Menu.Item key={MENU_KEYS.MANAGE_EMBEDDED}>
{t('Embed dashboard')}
</Menu.Item>
)}

{!editMode && (
<Menu.Item key={MENU_KEYS.DOWNLOAD_AS_IMAGE}>
{t('Download as image')}
Expand Down
Loading

0 comments on commit 238dceb

Please sign in to comment.