mirror of
https://github.com/valitydev/redash.git
synced 2024-11-07 01:25:16 +00:00
Migrate Home to React (#4379)
This commit is contained in:
parent
e72d7a8cca
commit
0563ecf648
@ -85,7 +85,7 @@ strong {
|
||||
|
||||
// Fixed width layout for specific pages
|
||||
@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 {
|
||||
width: 750px;
|
||||
}
|
||||
@ -93,7 +93,7 @@ strong {
|
||||
}
|
||||
|
||||
@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 {
|
||||
width: 970px;
|
||||
}
|
||||
@ -101,7 +101,7 @@ strong {
|
||||
}
|
||||
|
||||
@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 {
|
||||
width: 1170px;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import { react2angular } from 'react2angular';
|
||||
import Card from 'antd/lib/card';
|
||||
import Button from 'antd/lib/button';
|
||||
import Typography from 'antd/lib/typography';
|
||||
@ -10,7 +9,7 @@ import OrgSettings from '@/services/organizationSettings';
|
||||
|
||||
const Text = Typography.Text;
|
||||
|
||||
export function BeaconConsent() {
|
||||
function BeaconConsent() {
|
||||
const [hide, setHide] = useState(false);
|
||||
|
||||
if (!clientConfig.showBeaconConsentMessage || hide) {
|
||||
@ -76,8 +75,4 @@ export function BeaconConsent() {
|
||||
);
|
||||
}
|
||||
|
||||
export default function init(ngModule) {
|
||||
ngModule.component('beaconConsent', react2angular(BeaconConsent));
|
||||
}
|
||||
|
||||
init.init = true;
|
||||
export default BeaconConsent;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { keys, some } from 'lodash';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { react2angular } from 'react2angular';
|
||||
import classNames from 'classnames';
|
||||
import CreateDashboardDialog from '@/components/dashboards/CreateDashboardDialog';
|
||||
import { currentUser } from '@/services/auth';
|
||||
@ -38,7 +37,7 @@ Step.defaultProps = {
|
||||
onClick: null,
|
||||
};
|
||||
|
||||
export function EmptyState({
|
||||
function EmptyState({
|
||||
icon,
|
||||
header,
|
||||
description,
|
||||
@ -169,8 +168,4 @@ EmptyState.defaultProps = {
|
||||
showInviteStep: false,
|
||||
};
|
||||
|
||||
export default function init(ngModule) {
|
||||
ngModule.component('emptyState', react2angular(EmptyState));
|
||||
}
|
||||
|
||||
init.init = true;
|
||||
export default EmptyState;
|
||||
|
@ -4,7 +4,7 @@ import { react2angular } from 'react2angular';
|
||||
import { toUpper } from 'lodash';
|
||||
import { PageHeader } from '@/components/PageHeader';
|
||||
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 { ResourceItemsSource } from '@/components/items-list/classes/ItemsSource';
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BigMessage } from '@/components/BigMessage';
|
||||
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 }) {
|
||||
if (searchTerm !== '') {
|
||||
|
184
client/app/pages/home/Home.jsx
Normal file
184
client/app/pages/home/Home.jsx
Normal 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;
|
@ -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>
|
@ -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;
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BigMessage } from '@/components/BigMessage';
|
||||
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 }) {
|
||||
if (searchTerm !== '') {
|
||||
|
Loading…
Reference in New Issue
Block a user