This is an automated email from the ASF dual-hosted git repository. villebro pushed a commit to branch 0.37 in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
commit 2631b3882e58e56f2f4b163b351d2ec5f5043ce1 Author: Erik Ritter <erik.rit...@airbnb.com> AuthorDate: Tue Jul 14 16:39:37 2020 -0700 chore: add typing to profile (#10282) --- superset-frontend/package-lock.json | 82 ++++++++++++---------- superset-frontend/package.json | 9 ++- .../profile/{App_spec.jsx => App_spec.tsx} | 0 ...tedContent_spec.jsx => CreatedContent_spec.tsx} | 0 ...itableTitle_spec.jsx => EditableTitle_spec.tsx} | 0 .../{Favorites_spec.jsx => Favorites_spec.tsx} | 0 ...ntActivity_spec.jsx => RecentActivity_spec.tsx} | 0 .../{Security_spec.jsx => Security_spec.tsx} | 0 .../{UserInfo_spec.jsx => UserInfo_spec.tsx} | 0 .../profile/{fixtures.jsx => fixtures.tsx} | 0 .../src/SqlLab/components/ResultSet.tsx | 2 + .../src/messageToasts/enhancers/withToasts.tsx | 4 +- superset-frontend/src/profile/{App.jsx => App.tsx} | 2 +- .../src/profile/components/{App.jsx => App.tsx} | 21 +++--- .../{CreatedContent.jsx => CreatedContent.tsx} | 24 ++----- .../components/{Favorites.jsx => Favorites.tsx} | 24 ++----- .../{RecentActivity.jsx => RecentActivity.tsx} | 56 +++++++-------- .../components/{Security.jsx => Security.tsx} | 12 ++-- .../src/profile/components/UserInfo.jsx | 75 -------------------- .../src/profile/components/UserInfo.tsx | 76 ++++++++++++++++++++ .../src/profile/{index.jsx => index.tsx} | 0 .../profile/types.ts} | 56 ++++++++++----- superset-frontend/webpack.config.js | 2 +- 23 files changed, 225 insertions(+), 220 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index b5c4dad..135f6b4 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -7678,22 +7678,6 @@ "@types/node": "*" } }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "dev": true, - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - }, - "dependencies": { - "react-is": { - "version": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", - "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" - } - } - }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -7818,6 +7802,14 @@ "@types/react": "*" } }, + "@types/react-gravatar": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/@types/react-gravatar/-/react-gravatar-2.6.8.tgz", + "integrity": "sha512-VMk0bF0w72l+opBm+EqLs0JqUG+hPowMBWCVGrbTwUWm/oDncvwNrf7P/ImwYwkTCKiLnU8Rc+/lyhehaIE/Rw==", + "requires": { + "@types/react": "*" + } + }, "@types/react-json-tree": { "version": "0.6.11", "resolved": "https://registry.npmjs.org/@types/react-json-tree/-/react-json-tree-0.6.11.tgz", @@ -7836,31 +7828,13 @@ } }, "@types/react-redux": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.7.tgz", - "integrity": "sha512-U+WrzeFfI83+evZE2dkZ/oF/1vjIYgqrb5dGgedkqVV8HEfDFujNgWCwHL89TDuWKb47U0nTBT6PLGq4IIogWg==", + "version": "5.0.21", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-5.0.21.tgz", + "integrity": "sha512-ewkOW4GjnyXq5L++T31utI8yRmwj8iCIahZohYi1Ef7Xkrw0V/q92ao7x20rm38FKgImDaCCsaRGWfCJmF/Ukg==", "dev": true, "requires": { - "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - }, - "dependencies": { - "react-is": { - "version": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", - "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" - }, - "redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - } + "redux": "^3.6.0" } }, "@types/react-select": { @@ -7923,6 +7897,25 @@ "redux": "^3.6.0" } }, + "@types/redux-mock-store": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/redux-mock-store/-/redux-mock-store-1.0.2.tgz", + "integrity": "sha512-6LBtAQBN34i7SI5X+Qs4zpTEZO1tTDZ6sZ9fzFjYwTl3nLQXaBtwYdoV44CzNnyKu438xJ1lSIYyw0YMvunESw==", + "requires": { + "redux": "^4.0.5" + }, + "dependencies": { + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + } + } + }, "@types/rison": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@types/rison/-/rison-0.0.6.tgz", @@ -7933,6 +7926,19 @@ "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", "integrity": "sha1-gJPuBBam4r8qpjOBCRFLP7/6Dps=" }, + "@types/sinon": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.4.tgz", + "integrity": "sha512-sJmb32asJZY6Z2u09bl0G2wglSxDlROlAejCjsnor+LzBMz17gu8IU7vKC/vWDnv9zEq2wqADHVXFjf4eE8Gdw==", + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz", + "integrity": "sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==" + }, "@types/sizzle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 9631bf8..17fab51 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -85,13 +85,13 @@ "@superset-ui/legacy-plugin-chart-sankey": "^0.14.9", "@superset-ui/legacy-plugin-chart-sankey-loop": "^0.14.9", "@superset-ui/legacy-plugin-chart-sunburst": "^0.14.9", - "@superset-ui/plugin-chart-table": "^0.14.9", "@superset-ui/legacy-plugin-chart-treemap": "^0.14.9", "@superset-ui/legacy-plugin-chart-world-map": "^0.14.9", "@superset-ui/legacy-preset-chart-big-number": "^0.14.9", "@superset-ui/legacy-preset-chart-deckgl": "^0.2.4", "@superset-ui/legacy-preset-chart-nvd3": "^0.14.9", "@superset-ui/number-format": "^0.14.9", + "@superset-ui/plugin-chart-table": "^0.14.9", "@superset-ui/plugin-chart-word-cloud": "^0.14.9", "@superset-ui/preset-chart-xy": "^0.14.9", "@superset-ui/query": "^0.14.9", @@ -103,14 +103,16 @@ "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.5", "@types/react-bootstrap": "^0.32.21", + "@types/react-gravatar": "^2.6.8", "@types/react-json-tree": "^0.6.11", "@types/react-select": "^3.0.12", "@types/react-virtualized": "^9.21.10", "@types/react-window": "^1.8.2", "@types/redux-localstorage": "^1.0.8", + "@types/redux-mock-store": "^1.0.2", "@types/rison": "0.0.6", + "@types/sinon": "^9.0.4", "@vx/responsive": "^0.0.195", - "memoize-one": "^5.1.1", "abortcontroller-polyfill": "^1.1.9", "aphrodite": "^2.3.1", "array-move": "^2.2.1", @@ -134,6 +136,7 @@ "lodash": "^4.17.15", "lodash-es": "^4.17.14", "mathjs": "^3.20.2", + "memoize-one": "^5.1.1", "moment": "^2.20.1", "mousetrap": "^1.6.1", "mustache": "^2.2.1", @@ -208,7 +211,7 @@ "@types/react": "^16.9.38", "@types/react-dom": "^16.9.8", "@types/react-json-tree": "^0.6.11", - "@types/react-redux": "^7.1.7", + "@types/react-redux": "^5.0.2", "@types/react-table": "^7.0.19", "@types/react-ultimate-pagination": "^1.2.0", "@types/yargs": "12 - 15", diff --git a/superset-frontend/spec/javascripts/profile/App_spec.jsx b/superset-frontend/spec/javascripts/profile/App_spec.tsx similarity index 100% rename from superset-frontend/spec/javascripts/profile/App_spec.jsx rename to superset-frontend/spec/javascripts/profile/App_spec.tsx diff --git a/superset-frontend/spec/javascripts/profile/CreatedContent_spec.jsx b/superset-frontend/spec/javascripts/profile/CreatedContent_spec.tsx similarity index 100% rename from superset-frontend/spec/javascripts/profile/CreatedContent_spec.jsx rename to superset-frontend/spec/javascripts/profile/CreatedContent_spec.tsx diff --git a/superset-frontend/spec/javascripts/profile/EditableTitle_spec.jsx b/superset-frontend/spec/javascripts/profile/EditableTitle_spec.tsx similarity index 100% rename from superset-frontend/spec/javascripts/profile/EditableTitle_spec.jsx rename to superset-frontend/spec/javascripts/profile/EditableTitle_spec.tsx diff --git a/superset-frontend/spec/javascripts/profile/Favorites_spec.jsx b/superset-frontend/spec/javascripts/profile/Favorites_spec.tsx similarity index 100% rename from superset-frontend/spec/javascripts/profile/Favorites_spec.jsx rename to superset-frontend/spec/javascripts/profile/Favorites_spec.tsx diff --git a/superset-frontend/spec/javascripts/profile/RecentActivity_spec.jsx b/superset-frontend/spec/javascripts/profile/RecentActivity_spec.tsx similarity index 100% copy from superset-frontend/spec/javascripts/profile/RecentActivity_spec.jsx copy to superset-frontend/spec/javascripts/profile/RecentActivity_spec.tsx diff --git a/superset-frontend/spec/javascripts/profile/Security_spec.jsx b/superset-frontend/spec/javascripts/profile/Security_spec.tsx similarity index 100% rename from superset-frontend/spec/javascripts/profile/Security_spec.jsx rename to superset-frontend/spec/javascripts/profile/Security_spec.tsx diff --git a/superset-frontend/spec/javascripts/profile/UserInfo_spec.jsx b/superset-frontend/spec/javascripts/profile/UserInfo_spec.tsx similarity index 100% rename from superset-frontend/spec/javascripts/profile/UserInfo_spec.jsx rename to superset-frontend/spec/javascripts/profile/UserInfo_spec.tsx diff --git a/superset-frontend/spec/javascripts/profile/fixtures.jsx b/superset-frontend/spec/javascripts/profile/fixtures.tsx similarity index 100% rename from superset-frontend/spec/javascripts/profile/fixtures.jsx rename to superset-frontend/spec/javascripts/profile/fixtures.tsx diff --git a/superset-frontend/src/SqlLab/components/ResultSet.tsx b/superset-frontend/src/SqlLab/components/ResultSet.tsx index b074872..7de1175 100644 --- a/superset-frontend/src/SqlLab/components/ResultSet.tsx +++ b/superset-frontend/src/SqlLab/components/ResultSet.tsx @@ -158,6 +158,7 @@ export default class ResultSet extends React.PureComponent< this.props.database && this.props.database.allows_virtual_table_explore && ( <ExploreResultsButton + // @ts-ignore Redux types are difficult to work with, ignoring for now query={this.props.query} database={this.props.database} actions={this.props.actions} @@ -246,6 +247,7 @@ export default class ResultSet extends React.PureComponent< {t('Query in a new tab')} </Button> <ExploreCtasResultsButton + // @ts-ignore Redux types are difficult to work with, ignoring for now table={tempTable} schema={tempSchema} dbId={exploreDBId} diff --git a/superset-frontend/src/messageToasts/enhancers/withToasts.tsx b/superset-frontend/src/messageToasts/enhancers/withToasts.tsx index 5e41152..0a23134 100644 --- a/superset-frontend/src/messageToasts/enhancers/withToasts.tsx +++ b/superset-frontend/src/messageToasts/enhancers/withToasts.tsx @@ -29,7 +29,7 @@ import { } from '../actions'; // To work properly the redux state must have a `messageToasts` subtree -export default function withToasts(BaseComponent: ComponentType) { +export default function withToasts(BaseComponent: ComponentType<any>) { return connect(null, dispatch => bindActionCreators( { @@ -41,6 +41,6 @@ export default function withToasts(BaseComponent: ComponentType) { dispatch, ), )(BaseComponent) as any; - // Rsedux has some confusing typings that cause problems for consumers of this function. + // Redux has some confusing typings that cause problems for consumers of this function. // If someone can fix the types, great, but for now it's just any. } diff --git a/superset-frontend/src/profile/App.jsx b/superset-frontend/src/profile/App.tsx similarity index 96% rename from superset-frontend/src/profile/App.jsx rename to superset-frontend/src/profile/App.tsx index 3e870c9..ea9932b 100644 --- a/superset-frontend/src/profile/App.jsx +++ b/superset-frontend/src/profile/App.tsx @@ -33,7 +33,7 @@ setupApp(); const profileViewContainer = document.getElementById('app'); const bootstrap = JSON.parse( - profileViewContainer.getAttribute('data-bootstrap'), + profileViewContainer?.getAttribute('data-bootstrap') ?? '{}', ); const store = createStore( diff --git a/superset-frontend/src/profile/components/App.jsx b/superset-frontend/src/profile/components/App.tsx similarity index 86% rename from superset-frontend/src/profile/components/App.jsx rename to superset-frontend/src/profile/components/App.tsx index 457a46e..bde67ac 100644 --- a/superset-frontend/src/profile/components/App.jsx +++ b/superset-frontend/src/profile/components/App.tsx @@ -17,7 +17,6 @@ * under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { Col, Row, Tabs, Tab, Panel } from 'react-bootstrap'; import { t } from '@superset-ui/translation'; @@ -26,17 +25,18 @@ import UserInfo from './UserInfo'; import Security from './Security'; import RecentActivity from './RecentActivity'; import CreatedContent from './CreatedContent'; +import { User } from '../types'; -const propTypes = { - user: PropTypes.object.isRequired, -}; +interface AppProps { + user: User; +} -export default function App(props) { +export default function App({ user }: AppProps) { return ( <div className="container app"> <Row> <Col md={3}> - <UserInfo user={props.user} /> + <UserInfo user={user} /> </Col> <Col md={9}> <Tabs id="options"> @@ -50,7 +50,7 @@ export default function App(props) { > <Panel> <Panel.Body> - <Favorites user={props.user} /> + <Favorites user={user} /> </Panel.Body> </Panel> </Tab> @@ -64,7 +64,7 @@ export default function App(props) { > <Panel> <Panel.Body> - <CreatedContent user={props.user} /> + <CreatedContent user={user} /> </Panel.Body> </Panel> </Tab> @@ -78,7 +78,7 @@ export default function App(props) { > <Panel> <Panel.Body> - <RecentActivity user={props.user} /> + <RecentActivity user={user} /> </Panel.Body> </Panel> </Tab> @@ -92,7 +92,7 @@ export default function App(props) { > <Panel> <Panel.Body> - <Security user={props.user} /> + <Security user={user} /> </Panel.Body> </Panel> </Tab> @@ -102,4 +102,3 @@ export default function App(props) { </div> ); } -App.propTypes = propTypes; diff --git a/superset-frontend/src/profile/components/CreatedContent.jsx b/superset-frontend/src/profile/components/CreatedContent.tsx similarity index 84% rename from superset-frontend/src/profile/components/CreatedContent.jsx rename to superset-frontend/src/profile/components/CreatedContent.tsx index 34cfdd2..9831e4d 100644 --- a/superset-frontend/src/profile/components/CreatedContent.jsx +++ b/superset-frontend/src/profile/components/CreatedContent.tsx @@ -17,28 +17,19 @@ * under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import moment from 'moment'; import { t } from '@superset-ui/translation'; import TableLoader from '../../components/TableLoader'; +import { User, Dashboard, Slice } from '../types'; -const propTypes = { - user: PropTypes.object.isRequired, -}; +interface CreatedContentProps { + user: User; +} -class CreatedContent extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - dashboardsLoading: true, - slicesLoading: true, - dashboards: [], - slices: [], - }; - } +class CreatedContent extends React.PureComponent<CreatedContentProps> { renderSliceTable() { - const mutator = data => + const mutator = (data: Slice[]) => data.map(slice => ({ slice: <a href={slice.url}>{slice.title}</a>, favorited: moment.utc(slice.dttm).fromNow(), @@ -56,7 +47,7 @@ class CreatedContent extends React.PureComponent { ); } renderDashboardTable() { - const mutator = data => + const mutator = (data: Dashboard[]) => data.map(dash => ({ dashboard: <a href={dash.url}>{dash.title}</a>, favorited: moment.utc(dash.dttm).fromNow(), @@ -85,6 +76,5 @@ class CreatedContent extends React.PureComponent { ); } } -CreatedContent.propTypes = propTypes; export default CreatedContent; diff --git a/superset-frontend/src/profile/components/Favorites.jsx b/superset-frontend/src/profile/components/Favorites.tsx similarity index 85% rename from superset-frontend/src/profile/components/Favorites.jsx rename to superset-frontend/src/profile/components/Favorites.tsx index 578e763..89b4cc4 100644 --- a/superset-frontend/src/profile/components/Favorites.jsx +++ b/superset-frontend/src/profile/components/Favorites.tsx @@ -17,28 +17,19 @@ * under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import moment from 'moment'; import { t } from '@superset-ui/translation'; import TableLoader from '../../components/TableLoader'; +import { User, Dashboard, Slice } from '../types'; -const propTypes = { - user: PropTypes.object.isRequired, -}; +interface FavoritesProps { + user: User; +} -export default class Favorites extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - dashboardsLoading: true, - slicesLoading: true, - dashboards: [], - slices: [], - }; - } +export default class Favorites extends React.PureComponent<FavoritesProps> { renderSliceTable() { - const mutator = data => + const mutator = (data: Slice[]) => data.map(slice => ({ slice: <a href={slice.url}>{slice.title}</a>, creator: <a href={slice.creator_url}>{slice.creator}</a>, @@ -57,7 +48,7 @@ export default class Favorites extends React.PureComponent { ); } renderDashboardTable() { - const mutator = data => + const mutator = (data: Dashboard[]) => data.map(dash => ({ dashboard: <a href={dash.url}>{dash.title}</a>, creator: <a href={dash.creator_url}>{dash.creator}</a>, @@ -86,4 +77,3 @@ export default class Favorites extends React.PureComponent { ); } } -Favorites.propTypes = propTypes; diff --git a/superset-frontend/src/profile/components/RecentActivity.jsx b/superset-frontend/src/profile/components/RecentActivity.tsx similarity index 52% rename from superset-frontend/src/profile/components/RecentActivity.jsx rename to superset-frontend/src/profile/components/RecentActivity.tsx index e58fb13..34f419c 100644 --- a/superset-frontend/src/profile/components/RecentActivity.jsx +++ b/superset-frontend/src/profile/components/RecentActivity.tsx @@ -17,39 +17,35 @@ * under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import moment from 'moment'; import TableLoader from '../../components/TableLoader'; +import { User, Activity } from '../types'; -const propTypes = { - user: PropTypes.object, -}; - -export default class RecentActivity extends React.PureComponent { - render() { - const rowLimit = 50; - const mutator = function (data) { - return data - .filter(row => row.action === 'dashboard' || row.action === 'explore') - .map(row => ({ - name: <a href={row.item_url}>{row.item_title}</a>, - type: row.action, - time: moment.utc(row.time).fromNow(), - _time: row.time, - })); - }; - return ( - <div> - <TableLoader - className="table table-condensed" - mutator={mutator} - sortable - dataEndpoint={`/superset/recent_activity/${this.props.user.userId}/?limit=${rowLimit}`} - /> - </div> - ); - } +interface RecentActivityProps { + user: User; } -RecentActivity.propTypes = propTypes; +export default function RecentActivity({ user }: RecentActivityProps) { + const rowLimit = 50; + const mutator = function (data: Activity[]) { + return data + .filter(row => row.action === 'dashboard' || row.action === 'explore') + .map(row => ({ + name: <a href={row.item_url}>{row.item_title}</a>, + type: row.action, + time: moment.utc(row.time).fromNow(), + _time: row.time, + })); + }; + return ( + <div> + <TableLoader + className="table table-condensed" + mutator={mutator} + sortable + dataEndpoint={`/superset/recent_activity/${user.userId}/?limit=${rowLimit}`} + /> + </div> + ); +} diff --git a/superset-frontend/src/profile/components/Security.jsx b/superset-frontend/src/profile/components/Security.tsx similarity index 92% rename from superset-frontend/src/profile/components/Security.jsx rename to superset-frontend/src/profile/components/Security.tsx index 5f3d03a..91b0284 100644 --- a/superset-frontend/src/profile/components/Security.jsx +++ b/superset-frontend/src/profile/components/Security.tsx @@ -17,14 +17,15 @@ * under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { Badge, Label } from 'react-bootstrap'; import { t } from '@superset-ui/translation'; +import { User } from '../types'; -const propTypes = { - user: PropTypes.object.isRequired, -}; -export default function Security({ user }) { +interface SecurityProps { + user: User; +} + +export default function Security({ user }: SecurityProps) { return ( <div> <div className="roles"> @@ -66,4 +67,3 @@ export default function Security({ user }) { </div> ); } -Security.propTypes = propTypes; diff --git a/superset-frontend/src/profile/components/UserInfo.jsx b/superset-frontend/src/profile/components/UserInfo.jsx deleted file mode 100644 index 1c6adca..0000000 --- a/superset-frontend/src/profile/components/UserInfo.jsx +++ /dev/null @@ -1,75 +0,0 @@ -/** - * 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 from 'react'; -import PropTypes from 'prop-types'; -import Gravatar from 'react-gravatar'; -import moment from 'moment'; -import { Panel } from 'react-bootstrap'; -import { t } from '@superset-ui/translation'; - -const propTypes = { - user: PropTypes.object.isRequired, -}; -const UserInfo = ({ user }) => ( - <div> - <a href="https://en.gravatar.com/"> - <Gravatar - email={user.email} - width="100%" - height="" - size={220} - alt={t('Profile picture provided by Gravatar')} - className="img-rounded" - style={{ borderRadius: 15 }} - /> - </a> - <hr /> - <Panel> - <Panel.Body> - <h3> - <strong> - {user.firstName} {user.lastName} - </strong> - </h3> - <h4 className="username"> - <i className="fa fa-user-o" /> {user.username} - </h4> - <hr /> - <p> - <i className="fa fa-clock-o" /> {t('joined')}{' '} - {moment(user.createdOn, 'YYYYMMDD').fromNow()} - </p> - <p className="email"> - <i className="fa fa-envelope-o" /> {user.email} - </p> - <p className="roles"> - <i className="fa fa-lock" /> {Object.keys(user.roles).join(', ')} - </p> - <p> - <i className="fa fa-key" /> - - <span className="text-muted">{t('id:')}</span> - <span className="user-id">{user.userId}</span> - </p> - </Panel.Body> - </Panel> - </div> -); -UserInfo.propTypes = propTypes; -export default UserInfo; diff --git a/superset-frontend/src/profile/components/UserInfo.tsx b/superset-frontend/src/profile/components/UserInfo.tsx new file mode 100644 index 0000000..ccc1c89 --- /dev/null +++ b/superset-frontend/src/profile/components/UserInfo.tsx @@ -0,0 +1,76 @@ +/** + * 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 from 'react'; +import Gravatar from 'react-gravatar'; +import moment from 'moment'; +import { Panel } from 'react-bootstrap'; +import { t } from '@superset-ui/translation'; +import { User } from '../types'; + +interface UserInfoProps { + user: User; +} + +export default function UserInfo({ user }: UserInfoProps) { + return ( + <div> + <a href="https://en.gravatar.com/"> + <Gravatar + email={user.email} + width="100%" + height="" + size={220} + alt={t('Profile picture provided by Gravatar')} + className="img-rounded" + style={{ borderRadius: 15 }} + /> + </a> + <hr /> + <Panel> + <Panel.Body> + <h3> + <strong> + {user.firstName} {user.lastName} + </strong> + </h3> + <h4 className="username"> + <i className="fa fa-user-o" /> {user.username} + </h4> + <hr /> + <p> + <i className="fa fa-clock-o" /> {t('joined')}{' '} + {moment(user.createdOn, 'YYYYMMDD').fromNow()} + </p> + <p className="email"> + <i className="fa fa-envelope-o" /> {user.email} + </p> + <p className="roles"> + <i className="fa fa-lock" /> {Object.keys(user.roles).join(', ')} + </p> + <p> + <i className="fa fa-key" /> + + <span className="text-muted">{t('id:')}</span> + <span className="user-id">{user.userId}</span> + </p> + </Panel.Body> + </Panel> + </div> + ); +} diff --git a/superset-frontend/src/profile/index.jsx b/superset-frontend/src/profile/index.tsx similarity index 100% rename from superset-frontend/src/profile/index.jsx rename to superset-frontend/src/profile/index.tsx diff --git a/superset-frontend/spec/javascripts/profile/RecentActivity_spec.jsx b/superset-frontend/src/profile/types.ts similarity index 55% rename from superset-frontend/spec/javascripts/profile/RecentActivity_spec.jsx rename to superset-frontend/src/profile/types.ts index 3399436..4e5a7eb 100644 --- a/superset-frontend/spec/javascripts/profile/RecentActivity_spec.jsx +++ b/superset-frontend/src/profile/types.ts @@ -16,25 +16,43 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; -import { shallow } from 'enzyme'; -import RecentActivity from 'src/profile/components/RecentActivity'; -import TableLoader from 'src/components/TableLoader'; +export type User = { + createdOn: string; + email: string; + firstName: string; + isActive: boolean; + lastName: string; + permissions: { + database_access?: string[]; + datasource_access?: string[]; + }; + roles: Record<string, any>; + userId: number; + username: string; +}; -import { user } from './fixtures'; +export type Slice = { + dttm: number; + id: number; + url: string; + title: string; + creator?: string; + creator_url?: string; + viz_type: string; +}; -describe('RecentActivity', () => { - const mockedProps = { - user, - }; - it('is valid', () => { - expect(React.isValidElement(<RecentActivity {...mockedProps} />)).toBe( - true, - ); - }); +export type Dashboard = { + dttm: number; + id: number; + url: string; + title: string; + creator?: string; + creator_url?: string; +}; - it('renders a TableLoader', () => { - const wrapper = shallow(<RecentActivity {...mockedProps} />); - expect(wrapper.find(TableLoader)).toHaveLength(1); - }); -}); +export type Activity = { + action: string; + item_title: string; + item_url: string; + time: number; +}; diff --git a/superset-frontend/webpack.config.js b/superset-frontend/webpack.config.js index f0c95ea..d436a3a 100644 --- a/superset-frontend/webpack.config.js +++ b/superset-frontend/webpack.config.js @@ -182,7 +182,7 @@ const config = { dashboard: addPreamble('/src/dashboard/index.jsx'), sqllab: addPreamble('/src/SqlLab/index.jsx'), welcome: addPreamble('/src/welcome/index.jsx'), - profile: addPreamble('/src/profile/index.jsx'), + profile: addPreamble('/src/profile/index.tsx'), showSavedQuery: [path.join(APP_DIR, '/src/showSavedQuery/index.jsx')], }, output,