You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by yj...@apache.org on 2020/10/29 05:44:46 UTC
[incubator-superset] 03/33: more adding and slicing
This is an automated email from the ASF dual-hosted git repository.
yjc pushed a commit to branch home-screen-mvp
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
commit 5e2b9a4fbff63072a094338dad605098bd92d608
Author: Phillip Kelley-Dotson <pk...@yahoo.com>
AuthorDate: Wed Sep 23 13:27:37 2020 -0700
more adding and slicing
---
.../src/components/ListViewCard/index.tsx | 51 ++--
.../src/views/CRUD/dashboard/DashboardCard.tsx | 168 +++++++++++
.../src/views/CRUD/dashboard/DashboardList.tsx | 92 +-----
.../src/views/CRUD/welcome/ChartTable.tsx | 148 +++++++++
.../src/views/CRUD/welcome/DashboardTable.tsx | 329 +++++++--------------
.../src/views/CRUD/welcome/SavedQueries.tsx | 23 +-
.../src/views/CRUD/welcome/Welcome.tsx | 125 +++-----
superset/queries/api.py | 3 +
superset/views/api.py | 2 +
9 files changed, 531 insertions(+), 410 deletions(-)
diff --git a/superset-frontend/src/components/ListViewCard/index.tsx b/superset-frontend/src/components/ListViewCard/index.tsx
index 4a0cf53..f07970c 100644
--- a/superset-frontend/src/components/ListViewCard/index.tsx
+++ b/superset-frontend/src/components/ListViewCard/index.tsx
@@ -152,6 +152,8 @@ interface CardProps {
coverLeft?: React.ReactNode;
coverRight?: React.ReactNode;
actions: React.ReactNode;
+ showImg: boolean;
+ rows?: number | string;
}
function ListViewCard({
@@ -166,31 +168,40 @@ function ListViewCard({
actions,
loading,
imgPosition = 'top',
+ showImg = true,
+ rows,
}: CardProps) {
return (
<StyledCard
data-test="styled-card"
cover={
- <Cover>
- <a href={url}>
- <div className="gradient-container">
- <ImageLoader
- src={imgURL}
- fallback={imgFallbackURL}
- isLoading={loading}
- position={imgPosition}
- />
- </div>
- </a>
- <CoverFooter className="cover-footer">
- {!loading && coverLeft && (
- <CoverFooterLeft>{coverLeft}</CoverFooterLeft>
- )}
- {!loading && coverRight && (
- <CoverFooterRight>{coverRight}</CoverFooterRight>
- )}
- </CoverFooter>
- </Cover>
+ showImg ? (
+ <Cover>
+ <a href={url}>
+ <div className="gradient-container">
+ <ImageLoader
+ src={imgURL}
+ fallback={imgFallbackURL}
+ isLoading={loading}
+ position={imgPosition}
+ />
+ </div>
+ </a>
+ <CoverFooter className="cover-footer">
+ {!loading && coverLeft && (
+ <CoverFooterLeft>{coverLeft}</CoverFooterLeft>
+ )}
+ {!loading && coverRight && (
+ <CoverFooterRight>{coverRight}</CoverFooterRight>
+ )}
+ </CoverFooter>
+ </Cover>
+ ) : (
+ <>
+ <div>Rows</div>
+ <div>{rows}</div>
+ </>
+ )
}
>
{loading && (
diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx
new file mode 100644
index 0000000..46d3088
--- /dev/null
+++ b/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx
@@ -0,0 +1,168 @@
+import React from 'react';
+import { SupersetClient, t } from '@superset-ui/core';
+import rison from 'rison';
+import { Dropdown, Menu } from 'src/common/components';
+import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
+import ListViewCard from 'src/components/ListViewCard';
+import Icon from 'src/components/Icon';
+import Label from 'src/components/Label';
+import FacePile from 'src/components/FacePile';
+import FaveStar from 'src/components/FaveStar';
+import Owner from 'src/types/Owner';
+
+import { createErrorHandler } from 'src/views/CRUD/utils';
+import { useFavoriteStatus } from 'src/views/CRUD/hooks';
+
+const FAVESTAR_BASE_URL = '/superset/favstar/Dashboard';
+
+interface Dashboard {
+ changed_by_name: string;
+ changed_by_url: string;
+ changed_on_delta_humanized: string;
+ changed_by: string;
+ dashboard_title: string;
+ slice_name: string;
+ id: number;
+ published: boolean;
+ url: string;
+ thumbnail_url: string;
+ owners: Owner[];
+ loading: boolean;
+}
+
+interface DashboardCardProps {
+ isChart?: boolean;
+ dashboard: Dashboard;
+ hasPerm: (name: string) => boolean;
+ bulkSelectEnabled: boolean;
+ refreshData: () => void;
+ addDangerToast: (msg: string) => void;
+ addSuccessToast: (msg: string) => void;
+ openDashboardEditModal?: (d: Dashboard) => void;
+}
+
+function DashboardCard({
+ isChart,
+ dashboard,
+ hasPerm,
+ bulkSelectEnabled,
+ refreshData,
+ addDangerToast,
+ addSuccessToast,
+ openDashboardEditModal,
+}: DashboardCardProps) {
+ const canEdit = hasPerm('can_edit');
+ const canDelete = hasPerm('can_delete');
+ const canExport = hasPerm('can_mulexport');
+ const [favoriteStatusRef, fetchFaveStar, saveFaveStar] = useFavoriteStatus(
+ {},
+ FAVESTAR_BASE_URL,
+ addDangerToast,
+ );
+
+ function handleDashboardDelete({
+ id,
+ dashboard_title: dashboardTitle,
+ }: Dashboard) {
+ return SupersetClient.delete({
+ endpoint: `/api/v1/dashboard/${id}`,
+ }).then(
+ () => {
+ refreshData();
+ addSuccessToast(t('Deleted: %s', dashboardTitle));
+ },
+ createErrorHandler(errMsg =>
+ addDangerToast(
+ t('There was an issue deleting %s: %s', dashboardTitle, errMsg),
+ ),
+ ),
+ );
+ }
+
+ function handleBulkDashboardExport(dashboardsToExport: Dashboard[]) {
+ return window.location.assign(
+ `/api/v1/dashboard/export/?q=${rison.encode(
+ dashboardsToExport.map(({ id }) => id),
+ )}`,
+ );
+ }
+
+ const cardTitle = isChart ? dashboard.slice_name : dashboard.dashboard_title;
+
+ const menu = (
+ <Menu>
+ {canDelete && (
+ <Menu.Item>
+ <ConfirmStatusChange
+ title={t('Please Confirm')}
+ description={
+ <>
+ {t('Are you sure you want to delete')} <b>{cardTitle}</b>?
+ </>
+ }
+ onConfirm={() => handleDashboardDelete(dashboard)}
+ >
+ {confirmDelete => (
+ <div
+ role="button"
+ tabIndex={0}
+ className="action-button"
+ onClick={confirmDelete}
+ >
+ <ListViewCard.MenuIcon name="trash" /> Delete
+ </div>
+ )}
+ </ConfirmStatusChange>
+ </Menu.Item>
+ )}
+ {canExport && (
+ <Menu.Item
+ role="button"
+ tabIndex={0}
+ onClick={() => handleBulkDashboardExport([dashboard])}
+ >
+ <ListViewCard.MenuIcon name="share" /> Export
+ </Menu.Item>
+ )}
+ {canEdit && openDashboardEditModal && (
+ <Menu.Item
+ role="button"
+ tabIndex={0}
+ onClick={() =>
+ openDashboardEditModal && openDashboardEditModal(dashboard)
+ }
+ >
+ <ListViewCard.MenuIcon name="pencil" /> Edit
+ </Menu.Item>
+ )}
+ </Menu>
+ );
+ return (
+ <ListViewCard
+ loading={dashboard.loading}
+ title={dashboard.dashboard_title}
+ titleRight={<Label>{dashboard.published ? 'published' : 'draft'}</Label>}
+ url={bulkSelectEnabled ? undefined : dashboard.url}
+ imgURL={dashboard.thumbnail_url}
+ imgFallbackURL="/static/assets/images/dashboard-card-fallback.png"
+ description={t('Last modified %s', dashboard.changed_on_delta_humanized)}
+ coverLeft={<FacePile users={dashboard.owners || []} />}
+ actions={
+ <ListViewCard.Actions>
+ <FaveStar
+ itemId={dashboard.id}
+ fetchFaveStar={fetchFaveStar}
+ saveFaveStar={saveFaveStar}
+ isStarred={!!favoriteStatusRef.current[dashboard.id]}
+ />
+ <Dropdown overlay={menu}>
+ <Icon name="more-horiz" />
+ </Dropdown>
+ </ListViewCard.Actions>
+ }
+ showImg
+ />
+ );
+}
+
+export default DashboardCard;
diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
index ac4d747..1fe8427 100644
--- a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
+++ b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
@@ -24,17 +24,15 @@ import { createFetchRelated, createErrorHandler } from 'src/views/CRUD/utils';
import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
import SubMenu, { SubMenuProps } from 'src/components/Menu/SubMenu';
-import FacePile from 'src/components/FacePile';
import ListView, { ListViewProps, Filters } from 'src/components/ListView';
import Owner from 'src/types/Owner';
import withToasts from 'src/messageToasts/enhancers/withToasts';
+import FacePile from 'src/components/FacePile';
import Icon from 'src/components/Icon';
-import Label from 'src/components/Label';
import FaveStar from 'src/components/FaveStar';
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
-import ListViewCard from 'src/components/ListViewCard';
-import { Dropdown, Menu } from 'src/common/components';
import TooltipWrapper from 'src/components/TooltipWrapper';
+import DashboardCard from './DashboardCard';
const PAGE_SIZE = 25;
const FAVESTAR_BASE_URL = '/superset/favstar/Dashboard';
@@ -81,7 +79,6 @@ function DashboardList(props: DashboardListProps) {
FAVESTAR_BASE_URL,
props.addDangerToast,
);
-
const [dashboardToEdit, setDashboardToEdit] = useState<Dashboard | null>(
null,
);
@@ -419,82 +416,17 @@ function DashboardList(props: DashboardListProps) {
];
function renderCard(dashboard: Dashboard & { loading: boolean }) {
- const menu = (
- <Menu>
- {canDelete && (
- <Menu.Item>
- <ConfirmStatusChange
- title={t('Please Confirm')}
- description={
- <>
- {t('Are you sure you want to delete')}{' '}
- <b>{dashboard.dashboard_title}</b>?
- </>
- }
- onConfirm={() => handleDashboardDelete(dashboard)}
- >
- {confirmDelete => (
- <div
- role="button"
- tabIndex={0}
- className="action-button"
- onClick={confirmDelete}
- >
- <ListViewCard.MenuIcon
- data-test="dashboard-list-view-card-trash-icon"
- name="trash"
- />{' '}
- Delete
- </div>
- )}
- </ConfirmStatusChange>
- </Menu.Item>
- )}
- {canExport && (
- <Menu.Item
- role="button"
- tabIndex={0}
- onClick={() => handleBulkDashboardExport([dashboard])}
- >
- <ListViewCard.MenuIcon name="share" /> Export
- </Menu.Item>
- )}
- {canEdit && (
- <Menu.Item
- data-test="dashboard-list-edit-option"
- role="button"
- tabIndex={0}
- onClick={() => openDashboardEditModal(dashboard)}
- >
- <ListViewCard.MenuIcon name="edit-alt" /> Edit
- </Menu.Item>
- )}
- </Menu>
- );
-
return (
- <ListViewCard
- loading={dashboard.loading}
- title={dashboard.dashboard_title}
- titleRight={
- <Label>{dashboard.published ? 'published' : 'draft'}</Label>
- }
- url={bulkSelectEnabled ? undefined : dashboard.url}
- imgURL={dashboard.thumbnail_url}
- imgFallbackURL="/static/assets/images/dashboard-card-fallback.png"
- description={t(
- 'Last modified %s',
- dashboard.changed_on_delta_humanized,
- )}
- coverLeft={<FacePile users={dashboard.owners || []} />}
- actions={
- <ListViewCard.Actions>
- {renderFaveStar(dashboard.id)}
- <Dropdown overlay={menu}>
- <Icon name="more-horiz" />
- </Dropdown>
- </ListViewCard.Actions>
- }
+ <DashboardCard
+ {...{
+ dashboard,
+ hasPerm,
+ bulkSelectEnabled,
+ refreshData,
+ addDangerToast: props.addDangerToast,
+ addSuccessToast: props.addSuccessToast,
+ openDashboardEditModal,
+ }}
/>
);
}
diff --git a/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx
new file mode 100644
index 0000000..9b8529e
--- /dev/null
+++ b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx
@@ -0,0 +1,148 @@
+/**
+ * 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, { useEffect } from 'react';
+import { t } from '@superset-ui/core';
+import { debounce } from 'lodash';
+import ListView, { FetchDataConfig } from 'src/components/ListView';
+import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
+import withToasts from 'src/messageToasts/enhancers/withToasts';
+import { User } from 'src/types/bootstrapTypes';
+import ListViewCard from 'src/components/ListViewCard';
+import { Dropdown, Menu } from 'src/common/components';
+import Icon from 'src/components/Icon';
+import Label from 'src/components/Label';
+import Owner from 'src/types/Owner';
+import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
+import DashboardCard from '../dashboard/DashboardCard';
+const PAGE_SIZE = 3;
+
+interface ChartTableProps {
+ addDangerToast: (message: string) => void;
+ addSuccessToast: (message: string) => void;
+ search: string;
+ chartFilter?: string;
+ user?: User;
+}
+
+interface Dashboard {
+ changed_by_name: string;
+ changed_by_url: string;
+ changed_on_delta_humanized: string;
+ changed_by: string;
+ dashboard_title: string;
+ slice_name: string;
+ id: number;
+ published: boolean;
+ url: string;
+ thumbnail_url: string;
+ owners: Owner[];
+ loading: boolean;
+}
+
+interface ChartTableState {
+ charts: Dashboard[];
+ chart_count: number;
+ loading: boolean;
+}
+
+export interface FilterValue {
+ col: string;
+ operator: string;
+ value: string | boolean | number | null | undefined;
+}
+
+export interface FetchDataConfig {
+ filters: FilterValue[];
+}
+
+function ChartTable({
+ chartFilter,
+ user,
+ addDangerToast,
+ addSuccessToast,
+}: ChartTableProps) {
+ const {
+ state: { loading, resourceCollection: charts, bulkSelectEnabled },
+ hasPerm,
+ refreshData,
+ fetchData,
+ } = useListViewResource<Dashboard>('chart', t('chart'), addDangerToast);
+ console.log('dashboardFilter', chartFilter);
+ const getFilters = () => {
+ const filters = [];
+
+ if (chartFilter === 'Mine') {
+ filters.push({
+ id: 'owners',
+ operator: 'rel_m_m',
+ value: `${user?.userId}`,
+ });
+ } else {
+ filters.push({
+ id: 'favorite', // API currently can't filter by favorite
+ operator: 'eq',
+ value: true,
+ });
+ }
+ // Do we need search?
+ /* filters.concat([
+ {
+ id: 'dashboard_title',
+ operator: 'ct',
+ value: search,
+ },
+ ]);
+ */
+ return filters;
+ };
+
+ useEffect(() => {
+ fetchData({
+ pageIndex: 0,
+ pageSize: PAGE_SIZE,
+ sortBy: [
+ {
+ id: 'changed_on_delta_humanized',
+ desc: true,
+ },
+ ],
+ filters: getFilters(),
+ });
+ }, [chartFilter]);
+ console.log("----charts: ", charts);
+ return (
+ <div>
+ {charts.map(e => (
+ <DashboardCard
+ {...{
+ dashboard: e,
+ hasPerm,
+ bulkSelectEnabled,
+ refreshData,
+ addDangerToast,
+ addSuccessToast,
+ }}
+ isChart
+ />
+ ))}
+ </div>
+ );
+}
+
+export default withToasts(ChartTable);
diff --git a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx
index f0560e4..39c5503 100644
--- a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx
+++ b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx
@@ -16,27 +16,46 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React from 'react';
-import { t, SupersetClient } from '@superset-ui/core';
+import React, { useEffect } from 'react';
+import { t } from '@superset-ui/core';
import { debounce } from 'lodash';
import ListView, { FetchDataConfig } from 'src/components/ListView';
+import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
import withToasts from 'src/messageToasts/enhancers/withToasts';
+import { User } from 'src/types/bootstrapTypes';
import ListViewCard from 'src/components/ListViewCard';
-import { Dashboard } from 'src/types/bootstrapTypes';
import { Dropdown, Menu } from 'src/common/components';
import Icon from 'src/components/Icon';
import Label from 'src/components/Label';
+import Owner from 'src/types/Owner';
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
-
+import DashboardCard from '../dashboard/DashboardCard';
const PAGE_SIZE = 3;
-//const canEdit = hasPerm('can_edit');
-//const canDelete = hasPerm('can_delete');
-//const canExport = hasPerm('can_mulexport');
+// const canEdit = hasPerm('can_edit');
+// const canDelete = hasPerm('can_delete');
+// const canExport = hasPerm('can_mulexport');
interface DashboardTableProps {
addDangerToast: (message: string) => void;
- search?: string;
+ addSuccessToast: (message: string) => void;
+ search: string;
+ dashboardFilter?: string;
+ user?: User;
+}
+
+interface Dashboard {
+ changed_by_name: string;
+ changed_by_url: string;
+ changed_on_delta_humanized: string;
+ changed_by: string;
+ dashboard_title: string;
+ id: number;
+ published: boolean;
+ url: string;
+ thumbnail_url: string;
+ owners: Owner[];
+ loading: boolean;
}
interface DashboardTableState {
@@ -45,232 +64,90 @@ interface DashboardTableState {
loading: boolean;
}
-class DashboardTable extends React.PureComponent<
- DashboardTableProps,
- DashboardTableState
-> {
- columns = [
- {
- accessor: 'dashboard_title',
- Header: 'Dashboard',
- Cell: ({
- row: {
- original: { url, dashboard_title: dashboardTitle },
- },
- }: {
- row: {
- original: {
- url: string;
- dashboard_title: string;
- };
- };
- }) => <a href={url}>{dashboardTitle}</a>,
- },
- {
- accessor: 'changed_by.first_name',
- Header: 'Modified By',
- Cell: ({
- row: {
- original: { changed_by_name: changedByName, changedByUrl },
- },
- }: {
- row: {
- original: {
- changed_by_name: string;
- changedByUrl: string;
- };
- };
- }) => <a href={changedByUrl}>{changedByName}</a>,
- },
- {
- accessor: 'changed_on_delta_humanized',
- Header: 'Modified',
- Cell: ({
- row: {
- original: { changed_on_delta_humanized: changedOn },
- },
- }: {
- row: {
- original: {
- changed_on_delta_humanized: string;
- };
- };
- }) => <span className="no-wrap">{changedOn}</span>,
- },
- ];
-
- initialSort = [{ id: 'changed_on_delta_humanized', desc: true }];
+export interface FilterValue {
+ col: string;
+ operator: string;
+ value: string | boolean | number | null | undefined;
+}
- constructor(props: DashboardTableProps) {
- super(props);
- this.state = {
- dashboards: [],
- dashboard_count: 0,
- loading: false,
- };
- }
+export interface FetchDataConfig {
+ filters: FilterValue[];
+}
- componentDidMount() {
- console.log('component did mount!!!');
- this.fetchDataDebounced({
- pageSize: PAGE_SIZE,
- pageIndex: 0,
- sortBy: this.initialSort,
- filters: [],
- });
- }
+function DashboardTable({
+ dashboardFilter,
+ user,
+ addDangerToast,
+ addSuccessToast,
+ search,
+}: DashboardTableProps) {
+ const {
+ state: { loading, resourceCollection: dashboards, bulkSelectEnabled },
+ hasPerm,
+ refreshData,
+ fetchData,
+ } = useListViewResource<Dashboard>(
+ 'dashboard',
+ t('dashboard'),
+ addDangerToast,
+ );
+ console.log('dashboardFilter', dashboardFilter);
+ const getFilters = () => {
+ const filters = [];
- componentDidUpdate(prevProps: DashboardTableProps) {
- if (prevProps.search !== this.props.search) {
- this.fetchDataDebounced({
- pageSize: PAGE_SIZE,
- pageIndex: 0,
- sortBy: this.initialSort,
- filters: [],
+ if (dashboardFilter === 'Mine') {
+ filters.push({
+ id: 'owners',
+ operator: 'rel_m_m',
+ value: `${user?.userId}`,
+ });
+ } else {
+ filters.push({
+ id: 'favorite', // API currently can't filter by favorite
+ operator: 'eq',
+ value: true,
});
}
- }
-
- fetchData = ({ pageIndex, pageSize, sortBy, filters }: FetchDataConfig) => {
- this.setState({ loading: true });
- const filterExps = Object.keys(filters)
- .map(fk => ({
- col: fk,
- opr: filters[fk].filterId,
- value: filters[fk].filterValue,
- }))
- .concat(
- this.props.search
- ? [
- {
- col: 'dashboard_title',
- opr: 'ct',
- value: this.props.search,
- },
- ]
- : [],
- );
-
- /*const { dashboardFilter, user} = this.props;
- const filters = [];
+ filters.concat([
+ {
+ id: 'dashboard_title',
+ operator: 'ct',
+ value: search,
+ },
+ ]);
+ return filters;
+ };
- if (dashboardFilter === "Mine") {
- filters.push[{
- {
- col: "owners.id", // API does not allow filter by owner id
- opr: "eq",
- value: user.id
- }
- }];
- } else {
- filter.push[{
+ useEffect(() => {
+ fetchData({
+ pageIndex: 0,
+ pageSize: PAGE_SIZE,
+ sortBy: [
{
- col: "favorite", // API currently can't filter by favorite
- opr: "eq",
- value: true
- }
- }];
- }*/
-
- /*const menu = (
- <Menu>
- {canDelete && (
- <Menu.Item>
- <ConfirmStatusChange
- title={t('Please Confirm')}
- description={
- <>
- {t('Are you sure you want to delete')}{' '}
- </>
- }
- onConfirm={() => handleDashboardDelete(dashboard)}
- >
- {confirmDelete => (
- <div
- role="button"
- tabIndex={0}
- className="action-button"
- onClick={confirmDelete}
- >
- <ListViewCard.MenuIcon name="trash" /> Delete
- </div>
- )}
- </ConfirmStatusChange>
- </Menu.Item>
- )}
- {canExport && (
- <Menu.Item
- role="button"
- tabIndex={0}
- onClick={() => handleBulkDashboardExport([dashboard])}
- >
- <ListViewCard.MenuIcon name="share" /> Export
- </Menu.Item>
- )}
- {canEdit && (
- <Menu.Item
- role="button"
- tabIndex={0}
- onClick={() => openDashboardEditModal(dashboard)}
- >
- <ListViewCard.MenuIcon name="pencil" /> Edit
- </Menu.Item>
- )}
- </Menu>
- ); */
-
- console.log('sortBy', sortBy);
- const queryParams = JSON.stringify({
- order_column: sortBy[0].id,
- order_direction: sortBy[0].desc ? 'desc' : 'asc',
- page: pageIndex,
- page_size: pageSize,
- //filters,
- ...(filterExps.length ? { filters: filterExps } : {}),
+ id: 'changed_on_delta_humanized',
+ desc: true,
+ },
+ ],
+ filters: getFilters(),
});
- console.log('hello!!!');
- return SupersetClient.get({
- endpoint: `/api/v1/dashboard/?q=${queryParams}`,
- })
- .then(({ json }) => {
- console.log('json', json);
- this.setState({ dashboards: json.result, dashboard_count: json.count });
- console.log('this.state', this.state);
- })
- .catch(response => {
- if (response.status === 401) {
- this.props.addDangerToast(
- t(
- "You don't have the necessary permissions to load dashboards. Please contact your administrator.",
- ),
- );
- } else {
- this.props.addDangerToast(
- t('An error occurred while fetching Dashboards'),
- );
- }
- })
- .finally(() => this.setState({ loading: false }));
- };
-
- // sort-comp disabled because of conflict with no-use-before-define rule
- // eslint-disable-next-line react/sort-comp
- fetchDataDebounced = debounce(this.fetchData, 200);
-
- render() {
- return (
- <div>
- {this.state.dashboards.map(e => (
- <ListViewCard
- title={e.dashboard_title}
- loading={this.state.loading}
- titleRight={<Label>{e.published ? 'published' : 'draft'}</Label>}
- description={t('Last modified %s', e.changed_on_delta_humanized)}
- />
- ))}
- </div>
- );
- }
+ }, [dashboardFilter]);
+
+ return (
+ <div>
+ {dashboards.map(e => (
+ <DashboardCard
+ {...{
+ dashboard: e,
+ hasPerm,
+ bulkSelectEnabled,
+ refreshData,
+ addDangerToast,
+ addSuccessToast,
+ }}
+ />
+ ))}
+ </div>
+ );
}
export default withToasts(DashboardTable);
diff --git a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
index 62e9e0e..7f261cc 100644
--- a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
+++ b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
@@ -29,32 +29,43 @@ class SavedQueries extends React.PureComponent {
queries: [],
};
}
- componentDidMount(){
+ componentDidMount() {
this.fetchData();
}
- fetchData = () => {
+ fetchData = async () => {
try {
- const { json } = SupersetClient.get({
+ const ids = [];
+ const { json } = await SupersetClient.get({
endpoint: `/api/v1/query/`,
});
+ /*(json.ids.forEach(id => {
+ const { json } = SupersetClient.get({
+ endpoint: `/api/v1/query/${id}`,
+ });
+ console.log('data', json);
+ });*/
+ console.log('json.result', json);
this.setState({ queries: json.result });
} catch (e) {
return console.log(e);
}
};
render() {
+ console.log('q', this.state.queries)
return (
<div>
{this.state.queries.map(q => (
<ListViewCard
- title={q.database_name}
+ title={q.database.database_name}
+ rows={q.rows}
loading={false}
description={t('Last run ', q.end_time)}
+ showImg={false}
/>
))}
</div>
- )
+ );
}
}
-export default SavedQueries;
\ No newline at end of file
+export default SavedQueries;
diff --git a/superset-frontend/src/views/CRUD/welcome/Welcome.tsx b/superset-frontend/src/views/CRUD/welcome/Welcome.tsx
index 5e311dd..337b4e1 100644
--- a/superset-frontend/src/views/CRUD/welcome/Welcome.tsx
+++ b/superset-frontend/src/views/CRUD/welcome/Welcome.tsx
@@ -31,6 +31,7 @@ import { useQueryParam, StringParam, QueryParamConfig } from 'use-query-params';
import { User } from 'src/types/bootstrapTypes';
import RecentActivity from 'src/profile/components/RecentActivity';
import Favorites from 'src/profile/components/Favorites';
+import ChartTable from './ChartTable';
import SavedQueries from './SavedQueries';
import DashboardTable from './DashboardTable';
@@ -60,7 +61,7 @@ function useSyncQueryState(
}
function ding(e: any) {
- console.log('event',e);
+ console.log('event', e);
}
export default function Welcome({ user }: WelcomeProps) {
@@ -70,24 +71,13 @@ export default function Welcome({ user }: WelcomeProps) {
'all',
);
const [dashboardFilter, setDashboardFilter] = useState('Favorite');
+ const [chartFilter, setChartFilter] = useState('Favorite');
const [searchQuery, setSearchQuery] = useSyncQueryState(
'search',
StringParam,
'',
);
-
- const onFormControlChange = useCallback(
- (e: React.FormEvent<FormControl & FormControlProps>) => {
- const { value } = e.currentTarget;
- setSearchQuery((value as string) ?? '');
- },
- [],
- );
-
- const onTabsSelect = useCallback((e: any) => {
- setActiveTab(e as string);
- }, []);
-
+ console.log('user', user);
return (
<Collapse defaultActiveKey={['1']}>
<Panel header={t('Recents')} key="1">
@@ -117,7 +107,7 @@ export default function Welcome({ user }: WelcomeProps) {
</Panel>
<Panel header={t('Dashboards')} key="2">
- <SubMenu
+ <SubMenu
activeChild={dashboardFilter}
name=""
// eslint-disable-next-line react/no-children-prop
@@ -142,74 +132,53 @@ export default function Welcome({ user }: WelcomeProps) {
// @ts-ignore React bootstrap types aren't quite right here
onChange={e => setSearchQuery(e.currentTarget.value)}
/>
- <DashboardTable search={searchQuery} filter={dashboardFilter} />
+ <DashboardTable
+ search={searchQuery}
+ dashboardFilter={dashboardFilter}
+ user={user}
+ />
</Panel>
- <Panel header={t('Saved Queries')} key="3" >
+ <Panel header={t('Saved Queries')} key="3">
+ <SubMenu
+ activeChild={dashboardFilter}
+ name=""
+ // eslint-disable-next-line react/no-children-prop
+ children={[
+ {
+ name: 'Favorite',
+ label: t('Favorite'),
+ onClick: () => setChartFilter('Favorite'),
+ },
+ {
+ name: 'Mine',
+ label: t('Mine'),
+ onClick: () => setChartFilter('Mine'),
+ },
+ ]}
+ />
<SavedQueries />
</Panel>
- <Panel header={t('Charts')} key="4" >
- Stuff here!
+ <Panel header={t('Charts')} key="4">
+ <SubMenu
+ activeChild={chartFilter}
+ name=""
+ // eslint-disable-next-line react/no-children-prop
+ children={[
+ {
+ name: 'Favorite',
+ label: t('Favorite'),
+ onClick: () => setChartFilter('Favorite'),
+ },
+ {
+ name: 'Mine',
+ label: t('Mine'),
+ onClick: () => setChartFilter('Mine'),
+ },
+ ]}
+ />
+ <ChartTable chartFilter={chartFilter} user={user} />
</Panel>
</Collapse>
- /*
- <div className="container welcome">
- <Tabs
- activeKey={activeTab}
- onSelect={onTabsSelect}
- id="uncontrolled-tab-example"
- >
- <Tab eventKey="all" title={t('Dashboards')}>
- <Panel>
- <Panel.Body>
- <Row>
- <Col md={8}>
- <h2>{t('Dashboards')}</h2>
- </Col>
- <Col md={4}>
- <FormControl
- type="text"
- bsSize="sm"
- style={{ marginTop: '25px' }}
- placeholder="Search"
- value={searchQuery}
- onChange={onFormControlChange}
- />
- </Col>
- </Row>
- <hr />
- <DashboardTable search={searchQuery} />
- </Panel.Body>
- </Panel>
- </Tab>
- <Tab eventKey="recent" title={t('Recently Viewed')}>
- <Panel>
- <Panel.Body>
- <Row>
- <Col md={8}>
- <h2>{t('Recently Viewed')}</h2>
- </Col>
- </Row>
- <hr />
- <RecentActivity user={user} />
- </Panel.Body>
- </Panel>
- </Tab>
- <Tab eventKey="favorites" title={t('Favorites')}>
- <Panel>
- <Panel.Body>
- <Row>
- <Col md={8}>
- <h2>{t('Favorites')}</h2>
- </Col>
- </Row>
- <hr />
- <Favorites user={user} />
- </Panel.Body>
- </Panel>
- </Tab>
- </Tabs>
- </div>
- */
);
}
diff --git a/superset/queries/api.py b/superset/queries/api.py
index 0f368d3..ce4fca5 100644
--- a/superset/queries/api.py
+++ b/superset/queries/api.py
@@ -42,6 +42,9 @@ class QueryRestApi(BaseSupersetModelRestApi):
"status",
"start_time",
"end_time",
+ "rows",
+ "tmp_table_name",
+ "tracking_url",
]
show_columns = [
"client_id",
diff --git a/superset/views/api.py b/superset/views/api.py
index a5090b3..19686a6 100644
--- a/superset/views/api.py
+++ b/superset/views/api.py
@@ -42,9 +42,11 @@ class Api(BaseSupersetView):
raises SupersetSecurityException: If the user cannot access the resource
"""
+ print("hello")
query_context = QueryContext(**json.loads(request.form["query_context"]))
query_context.raise_for_access()
payload_json = query_context.get_payload()
+ print("playload", payload_json)
return json.dumps(
payload_json, default=utils.json_int_dttm_ser, ignore_nan=True
)