Migrate Home to React (#4379)

This commit is contained in:
Gabriel Dutra 2019-11-24 13:59:56 -03:00 committed by GitHub
parent e72d7a8cca
commit 0563ecf648
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 194 additions and 157 deletions

View File

@ -85,7 +85,7 @@ strong {
// Fixed width layout for specific pages // Fixed width layout for specific pages
@media (min-width: 768px) { @media (min-width: 768px) {
.settings-screen, home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container { .settings-screen, .home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container {
.container { .container {
width: 750px; width: 750px;
} }
@ -93,7 +93,7 @@ strong {
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.settings-screen, home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container { .settings-screen, .home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container {
.container { .container {
width: 970px; width: 970px;
} }
@ -101,7 +101,7 @@ strong {
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
.settings-screen, home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container { .settings-screen, .home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container {
.container { .container {
width: 1170px; width: 1170px;
} }

View File

@ -1,5 +1,4 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { react2angular } from 'react2angular';
import Card from 'antd/lib/card'; import Card from 'antd/lib/card';
import Button from 'antd/lib/button'; import Button from 'antd/lib/button';
import Typography from 'antd/lib/typography'; import Typography from 'antd/lib/typography';
@ -10,7 +9,7 @@ import OrgSettings from '@/services/organizationSettings';
const Text = Typography.Text; const Text = Typography.Text;
export function BeaconConsent() { function BeaconConsent() {
const [hide, setHide] = useState(false); const [hide, setHide] = useState(false);
if (!clientConfig.showBeaconConsentMessage || hide) { if (!clientConfig.showBeaconConsentMessage || hide) {
@ -76,8 +75,4 @@ export function BeaconConsent() {
); );
} }
export default function init(ngModule) { export default BeaconConsent;
ngModule.component('beaconConsent', react2angular(BeaconConsent));
}
init.init = true;

View File

@ -1,7 +1,6 @@
import { keys, some } from 'lodash'; import { keys, some } from 'lodash';
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';
import classNames from 'classnames'; import classNames from 'classnames';
import CreateDashboardDialog from '@/components/dashboards/CreateDashboardDialog'; import CreateDashboardDialog from '@/components/dashboards/CreateDashboardDialog';
import { currentUser } from '@/services/auth'; import { currentUser } from '@/services/auth';
@ -38,7 +37,7 @@ Step.defaultProps = {
onClick: null, onClick: null,
}; };
export function EmptyState({ function EmptyState({
icon, icon,
header, header,
description, description,
@ -169,8 +168,4 @@ EmptyState.defaultProps = {
showInviteStep: false, showInviteStep: false,
}; };
export default function init(ngModule) { export default EmptyState;
ngModule.component('emptyState', react2angular(EmptyState));
}
init.init = true;

View File

@ -4,7 +4,7 @@ import { react2angular } from 'react2angular';
import { toUpper } from 'lodash'; import { toUpper } from 'lodash';
import { PageHeader } from '@/components/PageHeader'; import { PageHeader } from '@/components/PageHeader';
import { Paginator } from '@/components/Paginator'; import { Paginator } from '@/components/Paginator';
import { EmptyState } from '@/components/empty-state/EmptyState'; import EmptyState from '@/components/empty-state/EmptyState';
import { wrap as liveItemsList, ControllerType } from '@/components/items-list/ItemsList'; import { wrap as liveItemsList, ControllerType } from '@/components/items-list/ItemsList';
import { ResourceItemsSource } from '@/components/items-list/classes/ItemsSource'; import { ResourceItemsSource } from '@/components/items-list/classes/ItemsSource';

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { BigMessage } from '@/components/BigMessage'; import { BigMessage } from '@/components/BigMessage';
import { NoTaggedObjectsFound } from '@/components/NoTaggedObjectsFound'; import { NoTaggedObjectsFound } from '@/components/NoTaggedObjectsFound';
import { EmptyState } from '@/components/empty-state/EmptyState'; import EmptyState from '@/components/empty-state/EmptyState';
export default function DashboardListEmptyState({ page, searchTerm, selectedTags }) { export default function DashboardListEmptyState({ page, searchTerm, selectedTags }) {
if (searchTerm !== '') { if (searchTerm !== '') {

View File

@ -0,0 +1,184 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { includes, isEmpty } from 'lodash';
import { react2angular } from 'react2angular';
import Alert from 'antd/lib/alert';
import Icon from 'antd/lib/icon';
import EmptyState from '@/components/empty-state/EmptyState';
import DynamicComponent from '@/components/DynamicComponent';
import BeaconConsent from '@/components/BeaconConsent';
import recordEvent from '@/services/recordEvent';
import { messages } from '@/services/auth';
import { $http } from '@/services/ng';
import notification from '@/services/notification';
import { Dashboard } from '@/services/dashboard';
import { Query } from '@/services/query';
function DeprecatedEmbedFeatureAlert() {
return (
<Alert
className="m-b-15"
type="warning"
message={(
<>
You have enabled <code>ALLOW_PARAMETERS_IN_EMBEDS</code>. This setting is
now deprecated and should be turned off. Parameters in embeds are supported
by default.{' '}
<a
href="https://discuss.redash.io/t/support-for-parameters-in-embedded-visualizations/3337"
target="_blank"
rel="noopener noreferrer"
>
Read more
</a>.
</>
)}
/>
);
}
function EmailNotVerifiedAlert() {
const verifyEmail = () => {
$http.post('verification_email').then(({ data }) => {
notification.success(data.message);
});
};
return (
<Alert
className="m-b-15"
type="warning"
message={(
<>
We have sent an email with a confirmation link to your email address. Please
follow the link to verify your email address.{' '}
<a className="clickable" onClick={verifyEmail}>Resend email</a>.
</>
)}
/>
);
}
function FavoriteList({ title, resource, itemUrl, emptyState }) {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
resource.favorites().$promise
.then(({ results }) => setItems(results))
.finally(() => setLoading(false));
}, []);
return (
<>
<div className="d-flex align-items-center m-b-20">
<p className="flex-fill f-500 c-black m-0">{title}</p>
{loading && <Icon type="loading" />}
</div>
{!isEmpty(items) && (
<div className="list-group">
{items.map(item => (
<a key={itemUrl(item)} className="list-group-item" href={itemUrl(item)}>
<span className="btn-favourite m-r-5">
<i className="fa fa-star" aria-hidden="true" />
</span>
{item.name}
{item.is_draft && <span className="label label-default m-l-5">Unpublished</span>}
</a>
))}
</div>
)}
{(isEmpty(items) && !loading) && emptyState}
</>
);
}
FavoriteList.propTypes = {
title: PropTypes.string.isRequired,
resource: PropTypes.func.isRequired, // eslint-disable-line react/forbid-prop-types
itemUrl: PropTypes.func.isRequired,
emptyState: PropTypes.node,
};
FavoriteList.defaultProps = { emptyState: null };
function DashboardAndQueryFavoritesList() {
return (
<div className="tile">
<div className="t-body tb-padding">
<div className="row">
<div className="col-sm-6">
<FavoriteList
title="Favorite Dashboards"
resource={Dashboard}
itemUrl={dashboard => `dashboard/${dashboard.slug}`}
emptyState={(
<p>
<span className="btn-favourite m-r-5">
<i className="fa fa-star" aria-hidden="true" />
</span>
Favorite <a href="dashboards">Dashboards</a> will appear here
</p>
)}
/>
</div>
<div className="col-sm-6">
<FavoriteList
title="Favorite Queries"
resource={Query}
itemUrl={query => `queries/${query.id}`}
emptyState={(
<p>
<span className="btn-favourite m-r-5">
<i className="fa fa-star" aria-hidden="true" />
</span>
Favorite <a href="queries">Queries</a> will appear here
</p>
)}
/>
</div>
</div>
</div>
</div>
);
}
function Home() {
useEffect(() => {
recordEvent('view', 'page', 'personal_homepage');
}, []);
return (
<div className="home-page">
<div className="container">
{includes(messages, 'using-deprecated-embed-feature') && <DeprecatedEmbedFeatureAlert />}
{includes(messages, 'email-not-verified') && <EmailNotVerifiedAlert />}
<EmptyState
header="Welcome to Redash 👋"
description="Connect to any data source, easily visualize and share your data"
illustration="dashboard"
helpLink="https://redash.io/help/user-guide/getting-started"
showDashboardStep
showInviteStep
onboardingMode
/>
<DynamicComponent name="HomeExtra" />
<DashboardAndQueryFavoritesList />
<BeaconConsent />
</div>
</div>
);
}
export default function init(ngModule) {
ngModule.component('homePage', react2angular(Home));
return {
'/': {
template: '<home-page></home-page>',
title: 'Redash',
},
};
}
init.init = true;

View File

@ -1,95 +0,0 @@
<div class="container">
<div
ng-if="$ctrl.messages.includes('using-deprecated-embed-feature')"
class="alert alert-warning"
>
You have enabled <code>ALLOW_PARAMETERS_IN_EMBEDS</code>. This setting is
now deprecated and should be turned off. Parameters in embeds are supported
by default.
<a
href="https://discuss.redash.io/t/support-for-parameters-in-embedded-visualizations/3337"
target="_blank"
>Read more</a
>.
</div>
<div
ng-if="$ctrl.messages.includes('email-not-verified')"
class="alert alert-warning"
>
We have sent an email with a confirmation link to your email address. Please
follow the link to verify your email address.
<a ng-click="$ctrl.verifyEmail()">Resend email</a>.
</div>
<empty-state
header="'Welcome to Redash 👋'"
description="'Connect to any data source, easily visualize and share your data'"
illustration="'dashboard'"
help-link="'https://redash.io/help/user-guide/getting-started'"
show-dashboard-step="true"
show-invite-step="true"
onboarding-mode="true"
></empty-state>
<home-extra></home-extra>
<div class="tile">
<div class="t-body tb-padding">
<div class="row">
<div class="col-sm-6">
<p class="f-500 m-b-20 c-black">Favorite Dashboards</p>
<p ng-if="$ctrl.noDashboards">
<span class="btn-favourite">
<i class="fa fa-star" aria-hidden="true"></i>
</span>
Favorite <a href="dashboards">Dashboards</a> will appear here
</p>
<div class="list-group">
<a
ng-href="dashboard/{{ dashboard.slug }}"
class="list-group-item"
ng-repeat="dashboard in $ctrl.favoriteDashboards"
ng-if="dashboard.is_favorite"
>
<span class="btn-favourite">
<i class="fa fa-star" aria-hidden="true"></i>
</span>
{{ dashboard.name }}
<span class="label label-default" ng-if="dashboard.is_draft"
>Unpublished</span
>
</a>
</div>
</div>
<div class="col-sm-6">
<p class="f-500 m-b-20 c-black">Favorite Queries</p>
<p ng-if="$ctrl.noQueries">
<span class="btn-favourite">
<i class="fa fa-star" aria-hidden="true"></i>
</span>
Favorite <a href="queries">Queries</a> will appear here
</p>
<div class="list-group">
<a
ng-href="queries/{{ query.id }}"
class="list-group-item"
ng-repeat="query in $ctrl.favoriteQueries"
ng-if="query.is_favorite"
>
<span class="btn-favourite">
<i class="fa fa-star" aria-hidden="true"></i>
</span>
{{ query.name }}
<span class="label label-default" ng-if="query.is_draft"
>Unpublished</span
>
</a>
</div>
</div>
</div>
</div>
</div>
<beacon-consent></beacon-consent>
</div>

View File

@ -1,42 +0,0 @@
import template from './home.html';
import notification from '@/services/notification';
function HomeCtrl(Events, Dashboard, Query, $http, messages) {
Events.record('view', 'page', 'personal_homepage');
this.noDashboards = false;
this.noQueries = false;
this.messages = messages;
Dashboard.favorites().$promise.then((data) => {
this.favoriteDashboards = data.results;
this.noDashboards = data.results.length === 0;
});
Query.favorites().$promise.then((data) => {
this.favoriteQueries = data.results;
this.noQueries = data.results.length === 0;
});
this.verifyEmail = () => {
$http.post('verification_email/').success(({ message }) => {
notification.success(message);
});
};
}
export default function init(ngModule) {
ngModule.component('homePage', {
template,
controller: HomeCtrl,
});
return {
'/': {
template: '<home-page></home-page>',
title: 'Redash',
},
};
}
init.init = true;

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { BigMessage } from '@/components/BigMessage'; import { BigMessage } from '@/components/BigMessage';
import { NoTaggedObjectsFound } from '@/components/NoTaggedObjectsFound'; import { NoTaggedObjectsFound } from '@/components/NoTaggedObjectsFound';
import { EmptyState } from '@/components/empty-state/EmptyState'; import EmptyState from '@/components/empty-state/EmptyState';
export default function QueriesListEmptyState({ page, searchTerm, selectedTags }) { export default function QueriesListEmptyState({ page, searchTerm, selectedTags }) {
if (searchTerm !== '') { if (searchTerm !== '') {