mirror of https://github.com/apache/superset.git
chore: add typing to profile (#10282)
This commit is contained in:
parent
11ae48062f
commit
80902bca50
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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(
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
export type Slice = {
|
||||
dttm: number;
|
||||
id: number;
|
||||
url: string;
|
||||
title: string;
|
||||
creator?: string;
|
||||
creator_url?: string;
|
||||
viz_type: string;
|
||||
};
|
||||
|
||||
export type Dashboard = {
|
||||
dttm: number;
|
||||
id: number;
|
||||
url: string;
|
||||
title: string;
|
||||
creator?: string;
|
||||
creator_url?: string;
|
||||
};
|
||||
|
||||
export type Activity = {
|
||||
action: string;
|
||||
item_title: string;
|
||||
item_url: string;
|
||||
time: number;
|
||||
};
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue