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:49 UTC

[incubator-superset] 06/33: more updates

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 fbd15110d25c5c1b41ffee33ae3d307bf3ba2796
Author: Phillip Kelley-Dotson <pk...@yahoo.com>
AuthorDate: Thu Oct 1 19:52:23 2020 -0700

    more updates
---
 .../src/components/ListViewCard/index.tsx          |   2 +-
 superset-frontend/src/components/Menu/SubMenu.tsx  |   5 -
 .../src/views/CRUD/dashboard/DashboardCard.tsx     |   2 +-
 .../src/views/CRUD/welcome/ActivityTable.tsx       | 123 +++++++++++++++++++++
 .../src/views/CRUD/welcome/DashboardTable.tsx      |  29 +----
 .../src/views/CRUD/welcome/SavedQueries.tsx        |  33 +++---
 .../src/views/CRUD/welcome/Welcome.tsx             |  42 +++++--
 superset/views/api.py                              |   2 -
 8 files changed, 181 insertions(+), 57 deletions(-)

diff --git a/superset-frontend/src/components/ListViewCard/index.tsx b/superset-frontend/src/components/ListViewCard/index.tsx
index f07970c..fc62f7b 100644
--- a/superset-frontend/src/components/ListViewCard/index.tsx
+++ b/superset-frontend/src/components/ListViewCard/index.tsx
@@ -152,7 +152,7 @@ interface CardProps {
   coverLeft?: React.ReactNode;
   coverRight?: React.ReactNode;
   actions: React.ReactNode;
-  showImg: boolean;
+  showImg?: boolean;
   rows?: number | string;
 }
 
diff --git a/superset-frontend/src/components/Menu/SubMenu.tsx b/superset-frontend/src/components/Menu/SubMenu.tsx
index 381ac2e..df7e501 100644
--- a/superset-frontend/src/components/Menu/SubMenu.tsx
+++ b/superset-frontend/src/components/Menu/SubMenu.tsx
@@ -66,13 +66,8 @@ type MenuClickHandler = React.MouseEventHandler<MenuItem>;
 type MenuChild = {
   label: string;
   name: string;
-<<<<<<< HEAD
   url: string;
   usesRouter?: boolean;
-=======
-  url?: string;
-  onClick?: any;
->>>>>>> step 1: broken stuff!
 };
 
 export interface ButtonProps {
diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx
index 46d3088..f42de20 100644
--- a/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx
+++ b/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx
@@ -21,7 +21,7 @@ interface Dashboard {
   changed_on_delta_humanized: string;
   changed_by: string;
   dashboard_title: string;
-  slice_name: string;
+  slice_name?: string;
   id: number;
   published: boolean;
   url: string;
diff --git a/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx
new file mode 100644
index 0000000..9203848
--- /dev/null
+++ b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx
@@ -0,0 +1,123 @@
+/**
+ * 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, useState } from 'react';
+import { styled, SupersetClient, t } from '@superset-ui/core';
+import rison from 'rison';
+import moment from 'moment';
+import { addDangerToast } from 'src/messageToasts/actions';
+import { createBatchMethod, createErrorHandler } from '../utils';
+
+interface MapProps {
+  item_title: string;
+  slice_name: string;
+  time: string;
+  changed_on_utc: string;
+  user: {
+    userId: string | number;
+  };
+  activityFilter: string;
+  item_url: string;
+}
+
+const Cards = styled.div`
+  width: 200px;
+  padding: 15px;
+  border: 1px solid #f0f0f0;
+`;
+
+const filters = {
+  // Chart and dashbaord uses same filters
+  // for edited and created
+  edited: [
+    {
+      col: 'changed_by',
+      opr: 'rel_o_m',
+      value: 1,
+    },
+  ],
+  created: [
+    {
+      col: 'owners',
+      opr: 'rel_m_m',
+      value: 1,
+    },
+  ],
+};
+
+export default function ActivityTable({ user, activityFilter }: MapProps) {
+  const [active, setActiveState] = useState([]);
+  const recent = `/superset/recent_activity/${user.userId}/?limit=10`;
+  const setData = (endpoint: string) => {
+    SupersetClient.get(endpoint)
+      .then(({ json }) => {
+        setActiveState(json);
+      })
+      .catch(e => {
+        createErrorHandler(err =>
+          addDangerToast(t('There was an issue fetching your resource')),
+        );
+      });
+  };
+
+  const setBatchData = (q: string) => {
+    createBatchMethod(q).then((res: Array<object>) => {
+      setActiveState(res);
+    });
+  };
+
+  const getData = () => {
+    const queryParams = rison.encode({
+      order_column: 'changed_on_delta_humanized',
+      order_direction: 'desc',
+      page: 0,
+      page_size: 0,
+      filters: activityFilter !== 'Created' ? filters.edited : filters.created,
+    });
+    if (activityFilter === 'Viewed') {
+      setData({ endpoint: recent });
+    }
+    if (activityFilter === 'Edited') {
+      setBatchData(queryParams);
+    }
+    if (activityFilter === 'Created') {
+      setBatchData(queryParams);
+    }
+  };
+
+  useEffect(() => {
+    getData();
+  }, [activityFilter]);
+
+  const renderActivity = () => {
+    return active.map((e: MapProps) => (
+      <a href={e.item_url}>
+        <Cards>
+          <div>{activityFilter === 'Viewed' ? e.item_title : e.slice_name}</div>
+          <div>
+            {moment
+              .utc(activityFilter === 'Viewd' ? e.time : e.changed_on_utc)
+              .fromNow()}
+          </div>
+        </Cards>
+      </a>
+    ));
+  };
+
+  return <> {renderActivity()} </>;
+}
diff --git a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx
index 39c5503..ca3f584 100644
--- a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx
+++ b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx
@@ -17,24 +17,14 @@
  * 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 { t, styled } from '@superset-ui/core';
 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;
 
-// const canEdit = hasPerm('can_edit');
-// const canDelete = hasPerm('can_delete');
-// const canExport = hasPerm('can_mulexport');
+const PAGE_SIZE = 3;
 
 interface DashboardTableProps {
   addDangerToast: (message: string) => void;
@@ -58,22 +48,12 @@ interface Dashboard {
   loading: boolean;
 }
 
-interface DashboardTableState {
-  dashboards: Dashboard[];
-  dashboard_count: number;
-  loading: boolean;
-}
-
 export interface FilterValue {
   col: string;
   operator: string;
   value: string | boolean | number | null | undefined;
 }
 
-export interface FetchDataConfig {
-  filters: FilterValue[];
-}
-
 function DashboardTable({
   dashboardFilter,
   user,
@@ -91,7 +71,6 @@ function DashboardTable({
     t('dashboard'),
     addDangerToast,
   );
-  console.log('dashboardFilter', dashboardFilter);
   const getFilters = () => {
     const filters = [];
 
@@ -133,7 +112,7 @@ function DashboardTable({
   }, [dashboardFilter]);
 
   return (
-    <div>
+    <>
       {dashboards.map(e => (
         <DashboardCard
           {...{
@@ -146,7 +125,7 @@ function DashboardTable({
           }}
         />
       ))}
-    </div>
+    </>
   );
 }
 
diff --git a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
index 7f261cc..116cf91 100644
--- a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
+++ b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
@@ -18,12 +18,18 @@
  */
 import React from 'react';
 import { t, SupersetClient } from '@superset-ui/core';
-import { debounce } from 'lodash';
-import withToasts from 'src/messageToasts/enhancers/withToasts';
+// import withToasts from 'src/messageToasts/enhancers/withToasts';
+import { Dropdown } from 'src/common/components';
 import ListViewCard from 'src/components/ListViewCard';
+// import FaveStar from 'src/components/FaveStar';
+import Icon from 'src/components/Icon';
+
+interface StateProps {
+  queries: Array<object>;
+}
 
 class SavedQueries extends React.PureComponent {
-  constructor(props: Readonly<{}>) {
+  constructor(props: StateProps) {
     super(props);
     this.state = {
       queries: [],
@@ -32,28 +38,20 @@ class SavedQueries extends React.PureComponent {
   componentDidMount() {
     this.fetchData();
   }
+  // eslint-disable-next-line consistent-return
   fetchData = async () => {
     try {
-      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.database_name}
@@ -61,9 +59,16 @@ class SavedQueries extends React.PureComponent {
             loading={false}
             description={t('Last run ', q.end_time)}
             showImg={false}
+            actions={
+              <ListViewCard.Actions>
+                <Dropdown>
+                  <Icon name="more" />
+                </Dropdown>
+              </ListViewCard.Actions>
+            }
           />
         ))}
-      </div>
+      </>
     );
   }
 }
diff --git a/superset-frontend/src/views/CRUD/welcome/Welcome.tsx b/superset-frontend/src/views/CRUD/welcome/Welcome.tsx
index a610d43..5b05075 100644
--- a/superset-frontend/src/views/CRUD/welcome/Welcome.tsx
+++ b/superset-frontend/src/views/CRUD/welcome/Welcome.tsx
@@ -19,8 +19,8 @@
 import React, { useState } from 'react';
 import { FormControl } from 'react-bootstrap';
 import SubMenu from 'src/components/Menu/SubMenu';
+import { styled, t } from '@superset-ui/core';
 import { Collapse } from 'src/common/components';
-import { t } from '@superset-ui/core';
 import { useQueryParam, StringParam, QueryParamConfig } from 'use-query-params';
 import { User } from 'src/types/bootstrapTypes';
 import RecentActivity from 'src/profile/components/RecentActivity';
@@ -34,6 +34,24 @@ interface WelcomeProps {
   user: User;
 }
 
+const ActivityContainer = styled.div`
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(300px, max-content));
+  grid-gap: ${({ theme }) => theme.gridUnit * 8}px;
+  justify-content: center;
+  padding: ${({ theme }) => theme.gridUnit * 2}px
+    ${({ theme }) => theme.gridUnit * 4}px;
+`;
+
+export const CardContainer = styled.div`
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(459px, max-content));
+  grid-gap: ${({ theme }) => theme.gridUnit * 8}px;
+  justify-content: center;
+  padding: ${({ theme }) => theme.gridUnit * 2}px
+    ${({ theme }) => theme.gridUnit * 4}px;
+`;
+
 function useSyncQueryState(
   queryParam: string,
   queryParamType: QueryParamConfig<
@@ -75,7 +93,7 @@ export default function Welcome({ user }: WelcomeProps) {
     <Collapse defaultActiveKey={['1']}>
       <Panel header={t('Recents')} key="1">
         <SubMenu
-          activeChild="Viewed"
+          activeChild={activtyFilter}
           name=""
           // eslint-disable-next-line react/no-children-prop
           children={[
@@ -96,7 +114,9 @@ export default function Welcome({ user }: WelcomeProps) {
             },
           ]}
         />
-        <RecentActivity user={user} />
+        <ActivityContainer>
+          <ActivityTable user={user} activityFilter={activtyFilter} />
+        </ActivityContainer>
       </Panel>
 
       <Panel header={t('Dashboards')} key="2">
@@ -125,11 +145,13 @@ 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}
-          dashboardFilter={dashboardFilter}
-          user={user}
-        />
+        <CardContainer>
+          <DashboardTable
+            search={searchQuery}
+            dashboardFilter={dashboardFilter}
+            user={user}
+          />
+        </CardContainer>
       </Panel>
 
       <Panel header={t('Saved Queries')} key="3">
@@ -150,7 +172,9 @@ export default function Welcome({ user }: WelcomeProps) {
             },
           ]}
         />
-        <SavedQueries />
+        <CardContainer>
+          <SavedQueries />
+        </CardContainer>
       </Panel>
       <Panel header={t('Charts')} key="4">
         <SubMenu
diff --git a/superset/views/api.py b/superset/views/api.py
index 19686a6..a5090b3 100644
--- a/superset/views/api.py
+++ b/superset/views/api.py
@@ -42,11 +42,9 @@ 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
         )