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
         )