From c33a3cc67c409900857741bae34a1d4c17850a09 Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Wed, 22 Jan 2020 20:34:57 +0200 Subject: [PATCH 1/5] Refine routes definitions --- .../AuthenticatedPageWrapper.jsx | 59 -------- .../ApplicationArea/SignedOutPageWrapper.jsx | 41 ------ .../ApplicationArea/withApiKeySession.jsx | 42 ++++++ .../ApplicationArea/withUserSession.jsx | 67 +++++++++ client/app/pages/admin/Jobs.jsx | 13 +- client/app/pages/admin/OutdatedQueries.jsx | 63 ++++----- client/app/pages/admin/SystemStatus.jsx | 13 +- client/app/pages/alert/Alert.jsx | 31 +--- client/app/pages/alerts/AlertsList.jsx | 47 +++---- client/app/pages/dashboards/DashboardList.jsx | 67 ++++----- client/app/pages/dashboards/DashboardPage.jsx | 13 +- .../pages/dashboards/PublicDashboardPage.jsx | 15 +- .../pages/data-sources/DataSourcesList.jsx | 37 ++--- .../app/pages/data-sources/EditDataSource.jsx | 13 +- .../pages/destinations/DestinationsList.jsx | 37 ++--- .../pages/destinations/EditDestination.jsx | 13 +- client/app/pages/groups/GroupDataSources.jsx | 51 +++---- client/app/pages/groups/GroupMembers.jsx | 51 +++---- client/app/pages/groups/GroupsList.jsx | 61 ++++---- client/app/pages/home/Home.jsx | 10 +- client/app/pages/queries-list/QueriesList.jsx | 103 ++++++-------- client/app/pages/queries/QuerySource.jsx | 17 +-- client/app/pages/queries/QueryView.jsx | 13 +- .../app/pages/queries/VisualizationEmbed.jsx | 13 +- .../query-snippets/QuerySnippetsList.jsx | 77 +++++----- .../pages/settings/OrganizationSettings.jsx | 29 ++-- client/app/pages/users/UserProfile.jsx | 35 ++--- client/app/pages/users/UsersList.jsx | 133 ++++++++---------- 28 files changed, 489 insertions(+), 675 deletions(-) delete mode 100644 client/app/components/ApplicationArea/AuthenticatedPageWrapper.jsx delete mode 100644 client/app/components/ApplicationArea/SignedOutPageWrapper.jsx create mode 100644 client/app/components/ApplicationArea/withApiKeySession.jsx create mode 100644 client/app/components/ApplicationArea/withUserSession.jsx diff --git a/client/app/components/ApplicationArea/AuthenticatedPageWrapper.jsx b/client/app/components/ApplicationArea/AuthenticatedPageWrapper.jsx deleted file mode 100644 index 1b7c483bd7..0000000000 --- a/client/app/components/ApplicationArea/AuthenticatedPageWrapper.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import React, { useEffect, useState } from "react"; -import PropTypes from "prop-types"; -import ErrorBoundary from "@/components/ErrorBoundary"; -import { Auth } from "@/services/auth"; -import organizationStatus from "@/services/organizationStatus"; -import ApplicationHeader from "./ApplicationHeader"; -import ErrorMessage from "./ErrorMessage"; - -export default function AuthenticatedPageWrapper({ bodyClass, children }) { - const [isAuthenticated, setIsAuthenticated] = useState(!!Auth.isAuthenticated()); - - useEffect(() => { - let isCancelled = false; - Promise.all([Auth.requireSession(), organizationStatus.refresh()]) - .then(() => { - if (!isCancelled) { - setIsAuthenticated(!!Auth.isAuthenticated()); - } - }) - .catch(() => { - if (!isCancelled) { - setIsAuthenticated(false); - } - }); - return () => { - isCancelled = true; - }; - }, []); - - useEffect(() => { - if (bodyClass) { - document.body.classList.toggle(bodyClass, true); - return () => { - document.body.classList.toggle(bodyClass, false); - }; - } - }, [bodyClass]); - - if (!isAuthenticated) { - return null; - } - - return ( - <> - - }>{children} - - ); -} - -AuthenticatedPageWrapper.propTypes = { - bodyClass: PropTypes.string, - children: PropTypes.node, -}; - -AuthenticatedPageWrapper.defaultProps = { - bodyClass: null, - children: null, -}; diff --git a/client/app/components/ApplicationArea/SignedOutPageWrapper.jsx b/client/app/components/ApplicationArea/SignedOutPageWrapper.jsx deleted file mode 100644 index 62a5a69a9f..0000000000 --- a/client/app/components/ApplicationArea/SignedOutPageWrapper.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useEffect, useState } from "react"; -import PropTypes from "prop-types"; -import { Auth } from "@/services/auth"; - -export default function SignedOutPageWrapper({ apiKey, children }) { - const [isAuthenticated, setIsAuthenticated] = useState(false); - - useEffect(() => { - let isCancelled = false; - Auth.setApiKey(apiKey); - Auth.loadConfig() - .then(() => { - if (!isCancelled) { - setIsAuthenticated(true); - } - }) - .catch(() => { - if (!isCancelled) { - setIsAuthenticated(false); - } - }); - return () => { - isCancelled = true; - }; - }, [apiKey]); - - if (!isAuthenticated) { - return null; - } - - return children; -} - -SignedOutPageWrapper.propTypes = { - apiKey: PropTypes.string.isRequired, - children: PropTypes.node, -}; - -SignedOutPageWrapper.defaultProps = { - children: null, -}; diff --git a/client/app/components/ApplicationArea/withApiKeySession.jsx b/client/app/components/ApplicationArea/withApiKeySession.jsx new file mode 100644 index 0000000000..3c37f5d0fb --- /dev/null +++ b/client/app/components/ApplicationArea/withApiKeySession.jsx @@ -0,0 +1,42 @@ +import React, { useEffect, useState, useContext } from "react"; +import PropTypes from "prop-types"; +import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; +import { Auth } from "@/services/auth"; + +export default function withApiKeySession(WrappedComponent) { + function ApiKeySessionWrapper({ apiKey, ...props }) { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const { handleError } = useContext(ErrorBoundaryContext); + + useEffect(() => { + let isCancelled = false; + Auth.setApiKey(apiKey); + Auth.loadConfig() + .then(() => { + if (!isCancelled) { + setIsAuthenticated(true); + } + }) + .catch(() => { + if (!isCancelled) { + setIsAuthenticated(false); + } + }); + return () => { + isCancelled = true; + }; + }, [apiKey]); + + if (!isAuthenticated) { + return null; + } + + return ; + } + + ApiKeySessionWrapper.propTypes = { + apiKey: PropTypes.string.isRequired, + }; + + return ApiKeySessionWrapper; +} diff --git a/client/app/components/ApplicationArea/withUserSession.jsx b/client/app/components/ApplicationArea/withUserSession.jsx new file mode 100644 index 0000000000..be52928de2 --- /dev/null +++ b/client/app/components/ApplicationArea/withUserSession.jsx @@ -0,0 +1,67 @@ +import React, { useEffect, useState } from "react"; +import PropTypes from "prop-types"; +import ErrorBoundary, { ErrorBoundaryContext } from "@/components/ErrorBoundary"; +import { Auth } from "@/services/auth"; +import organizationStatus from "@/services/organizationStatus"; +import ApplicationHeader from "./ApplicationHeader"; +import ErrorMessage from "./ErrorMessage"; + +export default function withUserSession(WrappedComponent) { + function UserSessionWrapper({ bodyClass, ...props }) { + const [isAuthenticated, setIsAuthenticated] = useState(!!Auth.isAuthenticated()); + + useEffect(() => { + let isCancelled = false; + Promise.all([Auth.requireSession(), organizationStatus.refresh()]) + .then(() => { + if (!isCancelled) { + setIsAuthenticated(!!Auth.isAuthenticated()); + } + }) + .catch(() => { + if (!isCancelled) { + setIsAuthenticated(false); + } + }); + return () => { + isCancelled = true; + }; + }, []); + + useEffect(() => { + if (bodyClass) { + document.body.classList.toggle(bodyClass, true); + return () => { + document.body.classList.toggle(bodyClass, false); + }; + } + }, [bodyClass]); + + if (!isAuthenticated) { + return null; + } + + return ( + <> + + }> + + {({ handleError }) => } + + + + ); + } + + UserSessionWrapper.propTypes = { + bodyClass: PropTypes.string, + children: PropTypes.node, + }; + + UserSessionWrapper.defaultProps = { + bodyClass: null, + children: null, + }; + + return UserSessionWrapper; +} diff --git a/client/app/pages/admin/Jobs.jsx b/client/app/pages/admin/Jobs.jsx index fa6e0a31c3..5a1bb0ca86 100644 --- a/client/app/pages/admin/Jobs.jsx +++ b/client/app/pages/admin/Jobs.jsx @@ -5,9 +5,8 @@ import { axios } from "@/services/axios"; import Alert from "antd/lib/alert"; import Tabs from "antd/lib/tabs"; import * as Grid from "antd/lib/grid"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import Layout from "@/components/admin/Layout"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { CounterCard, WorkersTable, QueuesTable, OtherJobsTable } from "@/components/admin/RQStatus"; import location from "@/services/location"; @@ -121,14 +120,10 @@ class Jobs extends React.Component { } } +const JobsPage = withUserSession(Jobs); + export default { path: "/admin/queries/jobs", title: "RQ Status", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }; diff --git a/client/app/pages/admin/OutdatedQueries.jsx b/client/app/pages/admin/OutdatedQueries.jsx index a955700e46..c8a58b4e28 100644 --- a/client/app/pages/admin/OutdatedQueries.jsx +++ b/client/app/pages/admin/OutdatedQueries.jsx @@ -4,13 +4,12 @@ import { axios } from "@/services/axios"; import Switch from "antd/lib/switch"; import * as Grid from "antd/lib/grid"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import Paginator from "@/components/Paginator"; import { QueryTagsControl } from "@/components/tags-control/TagsControl"; import SchedulePhrase from "@/components/queries/SchedulePhrase"; import TimeAgo from "@/components/TimeAgo"; import Layout from "@/components/admin/Layout"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ItemsSource } from "@/components/items-list/classes/ItemsSource"; @@ -147,43 +146,39 @@ class OutdatedQueries extends React.Component { } } -const OutdatedQueriesPage = itemsList( - OutdatedQueries, - () => - new ItemsSource({ - doRequest(request, context) { - return ( - axios - .get("/api/admin/queries/outdated") - // eslint-disable-next-line camelcase - .then(({ queries, updated_at }) => { - context.setCustomParams({ lastUpdatedAt: parseFloat(updated_at) }); - return queries; - }) - ); - }, - processResults(items) { - return map(items, item => new Query(item)); - }, - isPlainList: true, - }), - () => new StateStorage({ orderByField: "created_at", orderByReverse: true }) +const OutdatedQueriesPage = withUserSession( + itemsList( + OutdatedQueries, + () => + new ItemsSource({ + doRequest(request, context) { + return ( + axios + .get("/api/admin/queries/outdated") + // eslint-disable-next-line camelcase + .then(({ queries, updated_at }) => { + context.setCustomParams({ lastUpdatedAt: parseFloat(updated_at) }); + return queries; + }) + ); + }, + processResults(items) { + return map(items, item => new Query(item)); + }, + isPlainList: true, + }), + () => new StateStorage({ orderByField: "created_at", orderByReverse: true }) + ) ); export default { path: "/admin/queries/outdated", title: "Outdated Queries", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }; diff --git a/client/app/pages/admin/SystemStatus.jsx b/client/app/pages/admin/SystemStatus.jsx index b1d37b354e..bb8d31febf 100644 --- a/client/app/pages/admin/SystemStatus.jsx +++ b/client/app/pages/admin/SystemStatus.jsx @@ -3,9 +3,8 @@ import React from "react"; import { axios } from "@/services/axios"; import PropTypes from "prop-types"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import Layout from "@/components/admin/Layout"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import * as StatusBlock from "@/components/admin/StatusBlock"; import recordEvent from "@/services/recordEvent"; @@ -81,14 +80,10 @@ class SystemStatus extends React.Component { } } +const SystemStatusPage = withUserSession(SystemStatus); + export default { path: "/admin/status", title: "System Status", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }; diff --git a/client/app/pages/alert/Alert.jsx b/client/app/pages/alert/Alert.jsx index 68edbb4a66..1918c7d389 100644 --- a/client/app/pages/alert/Alert.jsx +++ b/client/app/pages/alert/Alert.jsx @@ -3,9 +3,8 @@ import React from "react"; import PropTypes from "prop-types"; import { currentUser } from "@/services/auth"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import notification from "@/services/notification"; import AlertService from "@/services/alert"; import { Query as QueryService } from "@/services/query"; @@ -31,7 +30,7 @@ export function getDefaultName(alert) { return defaultNameBuilder(alert); } -class AlertPage extends React.Component { +class Alert extends React.Component { static propTypes = { mode: PropTypes.oneOf(values(MODES)), alertId: PropTypes.string, @@ -252,38 +251,22 @@ class AlertPage extends React.Component { } } +const AlertPage = withUserSession(Alert); + export default [ { path: "/alerts/new", title: "New Alert", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }, { path: "/alerts/:alertId([0-9]+)", title: "Alert", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }, { path: "/alerts/:alertId([0-9]+)/edit", title: "Alert", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }, ]; diff --git a/client/app/pages/alerts/AlertsList.jsx b/client/app/pages/alerts/AlertsList.jsx index 620a2aa3ea..2f60cbbddf 100644 --- a/client/app/pages/alerts/AlertsList.jsx +++ b/client/app/pages/alerts/AlertsList.jsx @@ -1,10 +1,9 @@ import { toUpper } from "lodash"; import React from "react"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import PageHeader from "@/components/PageHeader"; import Paginator from "@/components/Paginator"; import EmptyState from "@/components/empty-state/EmptyState"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { wrap as liveItemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource"; import { StateStorage } from "@/components/items-list/classes/StateStorage"; @@ -106,35 +105,31 @@ class AlertsList extends React.Component { } } -const AlertsListPage = liveItemsList( - AlertsList, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest() { - return {}; - }, - getResource() { - return Alert.query.bind(Alert); - }, - }), - () => new StateStorage({ orderByField: "created_at", orderByReverse: true, itemsPerPage: 20 }) +const AlertsListPage = withUserSession( + liveItemsList( + AlertsList, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest() { + return {}; + }, + getResource() { + return Alert.query.bind(Alert); + }, + }), + () => new StateStorage({ orderByField: "created_at", orderByReverse: true, itemsPerPage: 20 }) + ) ); export default { path: "/alerts", title: "Alerts", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }; diff --git a/client/app/pages/dashboards/DashboardList.jsx b/client/app/pages/dashboards/DashboardList.jsx index 5c84d7f593..7c5f7651a2 100644 --- a/client/app/pages/dashboards/DashboardList.jsx +++ b/client/app/pages/dashboards/DashboardList.jsx @@ -1,6 +1,6 @@ import React from "react"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import PageHeader from "@/components/PageHeader"; import Paginator from "@/components/Paginator"; import { DashboardTagsControl } from "@/components/tags-control/TagsControl"; @@ -8,7 +8,6 @@ import { DashboardTagsControl } from "@/components/tags-control/TagsControl"; import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource"; import { UrlStateStorage } from "@/components/items-list/classes/StateStorage"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import LoadingState from "@/components/items-list/components/LoadingState"; import * as Sidebar from "@/components/items-list/components/Sidebar"; import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTable"; @@ -131,21 +130,23 @@ class DashboardList extends React.Component { } } -const DashboardListPage = itemsList( - DashboardList, - () => - new ResourceItemsSource({ - getResource({ params: { currentPage } }) { - return { - all: Dashboard.query.bind(Dashboard), - favorites: Dashboard.favorites.bind(Dashboard), - }[currentPage]; - }, - getItemProcessor() { - return item => new Dashboard(item); - }, - }), - () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) +const DashboardListPage = withUserSession( + itemsList( + DashboardList, + () => + new ResourceItemsSource({ + getResource({ params: { currentPage } }) { + return { + all: Dashboard.query.bind(Dashboard), + favorites: Dashboard.favorites.bind(Dashboard), + }[currentPage]; + }, + getItemProcessor() { + return item => new Dashboard(item); + }, + }), + () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) + ) ); export default [ @@ -153,34 +154,22 @@ export default [ path: "/dashboards", title: "Dashboards", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/dashboards/favorites", title: "Favorite Dashboards", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, ]; diff --git a/client/app/pages/dashboards/DashboardPage.jsx b/client/app/pages/dashboards/DashboardPage.jsx index e6f9640d44..e7a80fafb1 100644 --- a/client/app/pages/dashboards/DashboardPage.jsx +++ b/client/app/pages/dashboards/DashboardPage.jsx @@ -9,14 +9,13 @@ import Menu from "antd/lib/menu"; import Icon from "antd/lib/icon"; import Modal from "antd/lib/modal"; import Tooltip from "antd/lib/tooltip"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import DashboardGrid from "@/components/dashboards/DashboardGrid"; import FavoritesControl from "@/components/FavoritesControl"; import EditInPlace from "@/components/EditInPlace"; import { DashboardTagsControl } from "@/components/tags-control/TagsControl"; import Parameters from "@/components/Parameters"; import Filters from "@/components/Filters"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { Dashboard } from "@/services/dashboard"; import recordEvent from "@/services/recordEvent"; import getTags from "@/services/getTags"; @@ -407,13 +406,9 @@ DashboardPage.defaultProps = { onError: PropTypes.func, }; +const WrappedDashboardPage = withUserSession(DashboardPage); + export default { path: "/dashboard/:dashboardSlug", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }; diff --git a/client/app/pages/dashboards/PublicDashboardPage.jsx b/client/app/pages/dashboards/PublicDashboardPage.jsx index d1dc41b76c..063886b4ef 100644 --- a/client/app/pages/dashboards/PublicDashboardPage.jsx +++ b/client/app/pages/dashboards/PublicDashboardPage.jsx @@ -1,13 +1,12 @@ import { isEmpty } from "lodash"; import React from "react"; import PropTypes from "prop-types"; -import SignedOutPageWrapper from "@/components/ApplicationArea/SignedOutPageWrapper"; +import withApiKeySession from "@/components/ApplicationArea/withApiKeySession"; import BigMessage from "@/components/BigMessage"; import PageHeader from "@/components/PageHeader"; import Parameters from "@/components/Parameters"; import DashboardGrid from "@/components/dashboards/DashboardGrid"; import Filters from "@/components/Filters"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { Dashboard } from "@/services/dashboard"; import logoUrl from "@/assets/images/redash_icon_small.png"; import useDashboard from "./useDashboard"; @@ -96,14 +95,16 @@ class PublicDashboardPage extends React.Component { } } +const WrappedPublicDashboardPage = withApiKeySession(PublicDashboardPage); + export default { path: "/public/dashboards/:token", authenticated: false, render: currentRoute => ( - - - {({ handleError }) => } - - + ), }; diff --git a/client/app/pages/data-sources/DataSourcesList.jsx b/client/app/pages/data-sources/DataSourcesList.jsx index e21d779594..3870157d1a 100644 --- a/client/app/pages/data-sources/DataSourcesList.jsx +++ b/client/app/pages/data-sources/DataSourcesList.jsx @@ -4,7 +4,7 @@ import Button from "antd/lib/button"; import { isEmpty } from "lodash"; import DataSource, { IMG_ROOT } from "@/services/data-source"; import { policy } from "@/services/policy"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import CardsList from "@/components/cards-list/CardsList"; import LoadingState from "@/components/items-list/components/LoadingState"; @@ -12,7 +12,6 @@ import CreateSourceDialog from "@/components/CreateSourceDialog"; import DynamicComponent from "@/components/DynamicComponent"; import helper from "@/components/dynamic-form/dynamicFormHelper"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import recordEvent from "@/services/recordEvent"; class DataSourcesList extends React.Component { @@ -145,39 +144,29 @@ class DataSourcesList extends React.Component { } } -const DataSourcesListPage = wrapSettingsTab( - { - permission: "admin", - title: "Data Sources", - path: "data_sources", - order: 1, - }, - DataSourcesList +const DataSourcesListPage = withUserSession( + wrapSettingsTab( + { + permission: "admin", + title: "Data Sources", + path: "data_sources", + order: 1, + }, + DataSourcesList + ) ); export default [ { path: "/data_sources", title: "Data Sources", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }, { path: "/data_sources/new", title: "Data Sources", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, ]; diff --git a/client/app/pages/data-sources/EditDataSource.jsx b/client/app/pages/data-sources/EditDataSource.jsx index a9bca67293..92a634e26b 100644 --- a/client/app/pages/data-sources/EditDataSource.jsx +++ b/client/app/pages/data-sources/EditDataSource.jsx @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import { get, find, toUpper } from "lodash"; import Modal from "antd/lib/modal"; import DataSource, { IMG_ROOT } from "@/services/data-source"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import notification from "@/services/notification"; import LoadingState from "@/components/items-list/components/LoadingState"; @@ -11,7 +11,6 @@ import DynamicForm from "@/components/dynamic-form/DynamicForm"; import helper from "@/components/dynamic-form/dynamicFormHelper"; import HelpTrigger, { TYPES as HELP_TRIGGER_TYPES } from "@/components/HelpTrigger"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; class EditDataSource extends React.Component { static propTypes = { @@ -137,16 +136,10 @@ class EditDataSource extends React.Component { } } -const EditDataSourcePage = wrapSettingsTab(null, EditDataSource); +const EditDataSourcePage = withUserSession(wrapSettingsTab(null, EditDataSource)); export default { path: "/data_sources/:dataSourceId([0-9]+)", title: "Data Sources", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }; diff --git a/client/app/pages/destinations/DestinationsList.jsx b/client/app/pages/destinations/DestinationsList.jsx index 4a4828bccb..980ddbcfa0 100644 --- a/client/app/pages/destinations/DestinationsList.jsx +++ b/client/app/pages/destinations/DestinationsList.jsx @@ -4,14 +4,13 @@ import Button from "antd/lib/button"; import { isEmpty, isString, find, get } from "lodash"; import Destination, { IMG_ROOT } from "@/services/destination"; import { policy } from "@/services/policy"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import CardsList from "@/components/cards-list/CardsList"; import LoadingState from "@/components/items-list/components/LoadingState"; import CreateSourceDialog from "@/components/CreateSourceDialog"; import helper from "@/components/dynamic-form/dynamicFormHelper"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; class DestinationsList extends React.Component { static propTypes = { @@ -133,39 +132,29 @@ class DestinationsList extends React.Component { } } -const DestinationsListPage = wrapSettingsTab( - { - permission: "admin", - title: "Alert Destinations", - path: "destinations", - order: 4, - }, - DestinationsList +const DestinationsListPage = withUserSession( + wrapSettingsTab( + { + permission: "admin", + title: "Alert Destinations", + path: "destinations", + order: 4, + }, + DestinationsList + ) ); export default [ { path: "/destinations", title: "Alert Destinations", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }, { path: "/destinations/new", title: "Alert Destinations", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, ]; diff --git a/client/app/pages/destinations/EditDestination.jsx b/client/app/pages/destinations/EditDestination.jsx index bd5f54259e..e723e2d085 100644 --- a/client/app/pages/destinations/EditDestination.jsx +++ b/client/app/pages/destinations/EditDestination.jsx @@ -3,14 +3,13 @@ import React from "react"; import PropTypes from "prop-types"; import Modal from "antd/lib/modal"; import Destination, { IMG_ROOT } from "@/services/destination"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import notification from "@/services/notification"; import LoadingState from "@/components/items-list/components/LoadingState"; import DynamicForm from "@/components/dynamic-form/DynamicForm"; import helper from "@/components/dynamic-form/dynamicFormHelper"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; class EditDestination extends React.Component { static propTypes = { @@ -104,16 +103,10 @@ class EditDestination extends React.Component { } } -const EditDestinationPage = wrapSettingsTab(null, EditDestination); +const EditDestinationPage = withUserSession(wrapSettingsTab(null, EditDestination)); export default { path: "/destinations/:destinationId([0-9]+)", title: "Alert Destinations", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }; diff --git a/client/app/pages/groups/GroupDataSources.jsx b/client/app/pages/groups/GroupDataSources.jsx index 360936f226..f8fe72c7a8 100644 --- a/client/app/pages/groups/GroupDataSources.jsx +++ b/client/app/pages/groups/GroupDataSources.jsx @@ -5,7 +5,7 @@ import Dropdown from "antd/lib/dropdown"; import Menu from "antd/lib/menu"; import Icon from "antd/lib/icon"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; @@ -23,7 +23,6 @@ import ListItemAddon from "@/components/groups/ListItemAddon"; import Sidebar from "@/components/groups/DetailsPageSidebar"; import Layout from "@/components/layouts/ContentWithSidebar"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import notification from "@/services/notification"; import { currentUser } from "@/services/auth"; @@ -229,21 +228,23 @@ class GroupDataSources extends React.Component { } } -const GroupDataSourcesPage = wrapSettingsTab( - null, - liveItemsList( - GroupDataSources, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest(unused, { params: { groupId } }) { - return { id: groupId }; - }, - getResource() { - return Group.dataSources.bind(Group); - }, - }), - () => new StateStorage({ orderByField: "name" }) +const GroupDataSourcesPage = withUserSession( + wrapSettingsTab( + null, + liveItemsList( + GroupDataSources, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest(unused, { params: { groupId } }) { + return { id: groupId }; + }, + getResource() { + return Group.dataSources.bind(Group); + }, + }), + () => new StateStorage({ orderByField: "name" }) + ) ) ); @@ -251,16 +252,10 @@ export default { path: "/groups/:groupId([0-9]+)/data_sources", title: "Group Data Sources", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }; diff --git a/client/app/pages/groups/GroupMembers.jsx b/client/app/pages/groups/GroupMembers.jsx index eebe42c941..ee985f51d3 100644 --- a/client/app/pages/groups/GroupMembers.jsx +++ b/client/app/pages/groups/GroupMembers.jsx @@ -2,7 +2,7 @@ import { includes, map } from "lodash"; import React from "react"; import Button from "antd/lib/button"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; @@ -20,7 +20,6 @@ import ListItemAddon from "@/components/groups/ListItemAddon"; import Sidebar from "@/components/groups/DetailsPageSidebar"; import Layout from "@/components/layouts/ContentWithSidebar"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import notification from "@/services/notification"; import { currentUser } from "@/services/auth"; @@ -192,21 +191,23 @@ class GroupMembers extends React.Component { } } -const GroupMembersPage = wrapSettingsTab( - null, - liveItemsList( - GroupMembers, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest(unused, { params: { groupId } }) { - return { id: groupId }; - }, - getResource() { - return Group.members.bind(Group); - }, - }), - () => new StateStorage({ orderByField: "name" }) +const GroupMembersPage = withUserSession( + wrapSettingsTab( + null, + liveItemsList( + GroupMembers, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest(unused, { params: { groupId } }) { + return { id: groupId }; + }, + getResource() { + return Group.members.bind(Group); + }, + }), + () => new StateStorage({ orderByField: "name" }) + ) ) ); @@ -214,16 +215,10 @@ export default { path: "/groups/:groupId([0-9]+)", title: "Group Members", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }; diff --git a/client/app/pages/groups/GroupsList.jsx b/client/app/pages/groups/GroupsList.jsx index 8f5406eae5..1b34fa31cf 100644 --- a/client/app/pages/groups/GroupsList.jsx +++ b/client/app/pages/groups/GroupsList.jsx @@ -1,7 +1,7 @@ import React from "react"; import Button from "antd/lib/button"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; @@ -16,7 +16,6 @@ import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTab import CreateGroupDialog from "@/components/groups/CreateGroupDialog"; import DeleteGroupButton from "@/components/groups/DeleteGroupButton"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import Group from "@/services/group"; import { currentUser } from "@/services/auth"; @@ -126,26 +125,28 @@ class GroupsList extends React.Component { } } -const GroupsListPage = wrapSettingsTab( - { - permission: "list_users", - title: "Groups", - path: "groups", - order: 3, - }, - liveItemsList( - GroupsList, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest() { - return {}; - }, - getResource() { - return Group.query.bind(Group); - }, - }), - () => new StateStorage({ orderByField: "name", itemsPerPage: 10 }) +const GroupsListPage = withUserSession( + wrapSettingsTab( + { + permission: "list_users", + title: "Groups", + path: "groups", + order: 3, + }, + liveItemsList( + GroupsList, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest() { + return {}; + }, + getResource() { + return Group.query.bind(Group); + }, + }), + () => new StateStorage({ orderByField: "name", itemsPerPage: 10 }) + ) ) ); @@ -153,16 +154,10 @@ export default { path: "/groups", title: "Groups", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }; diff --git a/client/app/pages/home/Home.jsx b/client/app/pages/home/Home.jsx index 2ef9abfdfd..3323b894c7 100644 --- a/client/app/pages/home/Home.jsx +++ b/client/app/pages/home/Home.jsx @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import { includes, isEmpty } from "lodash"; import Alert from "antd/lib/alert"; import Icon from "antd/lib/icon"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import EmptyState from "@/components/empty-state/EmptyState"; import DynamicComponent from "@/components/DynamicComponent"; import BeaconConsent from "@/components/BeaconConsent"; @@ -173,12 +173,10 @@ function Home() { ); } +const HomePage = withUserSession(Home); + export default { path: "/", title: "Redash", - render: currentRoute => ( - - - - ), + render: currentRoute => , }; diff --git a/client/app/pages/queries-list/QueriesList.jsx b/client/app/pages/queries-list/QueriesList.jsx index 287973978c..8e6dd7c1d6 100644 --- a/client/app/pages/queries-list/QueriesList.jsx +++ b/client/app/pages/queries-list/QueriesList.jsx @@ -1,6 +1,6 @@ import React from "react"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import PageHeader from "@/components/PageHeader"; import Paginator from "@/components/Paginator"; import { QueryTagsControl } from "@/components/tags-control/TagsControl"; @@ -15,7 +15,6 @@ import * as Sidebar from "@/components/items-list/components/Sidebar"; import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTable"; import Layout from "@/components/layouts/ContentWithSidebar"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { Query } from "@/services/query"; import { currentUser } from "@/services/auth"; @@ -144,23 +143,25 @@ class QueriesList extends React.Component { } } -const QueriesListPage = itemsList( - QueriesList, - () => - new ResourceItemsSource({ - getResource({ params: { currentPage } }) { - return { - all: Query.query.bind(Query), - my: Query.myQueries.bind(Query), - favorites: Query.favorites.bind(Query), - archive: Query.archive.bind(Query), - }[currentPage]; - }, - getItemProcessor() { - return item => new Query(item); - }, - }), - () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) +const QueriesListPage = withUserSession( + itemsList( + QueriesList, + () => + new ResourceItemsSource({ + getResource({ params: { currentPage } }) { + return { + all: Query.query.bind(Query), + my: Query.myQueries.bind(Query), + favorites: Query.favorites.bind(Query), + archive: Query.archive.bind(Query), + }[currentPage]; + }, + getItemProcessor() { + return item => new Query(item); + }, + }), + () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) + ) ); export default [ @@ -168,68 +169,44 @@ export default [ path: "/queries", title: "Queries", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/queries/favorites", title: "Favorite Queries", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/queries/archive", title: "Archived Queries", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/queries/my", title: "My Queries", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, ]; diff --git a/client/app/pages/queries/QuerySource.jsx b/client/app/pages/queries/QuerySource.jsx index b4087d6a7c..ba5d45c975 100644 --- a/client/app/pages/queries/QuerySource.jsx +++ b/client/app/pages/queries/QuerySource.jsx @@ -3,7 +3,7 @@ import React, { useState, useRef, useEffect, useCallback } from "react"; import PropTypes from "prop-types"; import { useDebouncedCallback } from "use-debounce"; import Select from "antd/lib/select"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import Resizable from "@/components/Resizable"; import Parameters from "@/components/Parameters"; import EditInPlace from "@/components/EditInPlace"; @@ -11,7 +11,6 @@ import EditVisualizationButton from "@/components/EditVisualizationButton"; import QueryControlDropdown from "@/components/EditVisualizationButton/QueryControlDropdown"; import QueryEditor from "@/components/queries/QueryEditor"; import TimeAgo from "@/components/TimeAgo"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { durationHumanize, prettySize } from "@/lib/utils"; import { Query } from "@/services/query"; import recordEvent from "@/services/recordEvent"; @@ -444,15 +443,13 @@ QuerySource.propTypes = { query: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types }; +const QuerySourcePage = withUserSession(QuerySource); + export default [ { path: "/queries/new", render: currentRoute => ( - - - {({ handleError }) => } - - + ), resolve: { query: () => Query.newQuery(), @@ -461,11 +458,7 @@ export default [ { path: "/queries/:queryId([0-9]+)/source", render: currentRoute => ( - - - {({ handleError }) => } - - + ), resolve: { query: ({ queryId }) => Query.get({ id: queryId }), diff --git a/client/app/pages/queries/QueryView.jsx b/client/app/pages/queries/QueryView.jsx index f4be264071..5772a758ca 100644 --- a/client/app/pages/queries/QueryView.jsx +++ b/client/app/pages/queries/QueryView.jsx @@ -2,13 +2,12 @@ import React, { useState, useEffect, useCallback } from "react"; import PropTypes from "prop-types"; import Divider from "antd/lib/divider"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import EditInPlace from "@/components/EditInPlace"; import Parameters from "@/components/Parameters"; import TimeAgo from "@/components/TimeAgo"; import QueryControlDropdown from "@/components/EditVisualizationButton/QueryControlDropdown"; import EditVisualizationButton from "@/components/EditVisualizationButton"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { Query } from "@/services/query"; import DataSource from "@/services/data-source"; @@ -185,15 +184,11 @@ function QueryView(props) { QueryView.propTypes = { query: PropTypes.object.isRequired }; // eslint-disable-line react/forbid-prop-types +const QueryViewPage = withUserSession(QueryView); + export default { path: "/queries/:queryId([0-9]+)", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , resolve: { query: ({ queryId }) => Query.get({ id: queryId }), }, diff --git a/client/app/pages/queries/VisualizationEmbed.jsx b/client/app/pages/queries/VisualizationEmbed.jsx index 842eb9f380..137dd313cf 100644 --- a/client/app/pages/queries/VisualizationEmbed.jsx +++ b/client/app/pages/queries/VisualizationEmbed.jsx @@ -8,7 +8,7 @@ import Dropdown from "antd/lib/dropdown"; import Icon from "antd/lib/icon"; import Menu from "antd/lib/menu"; import Tooltip from "antd/lib/tooltip"; -import SignedOutPageWrapper from "@/components/ApplicationArea/SignedOutPageWrapper"; +import withApiKeySession from "@/components/ApplicationArea/withApiKeySession"; import { Query } from "@/services/query"; import location from "@/services/location"; import { formatDateTime } from "@/lib/utils"; @@ -18,7 +18,6 @@ import { Moment } from "@/components/proptypes"; import TimeAgo from "@/components/TimeAgo"; import Timer from "@/components/Timer"; import QueryResultsLink from "@/components/EditVisualizationButton/QueryResultsLink"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import VisualizationName from "@/visualizations/VisualizationName"; import VisualizationRenderer from "@/visualizations/VisualizationRenderer"; import { VisualizationType } from "@/visualizations"; @@ -265,16 +264,12 @@ VisualizationEmbed.defaultProps = { onError: () => {}, }; +const VisualizationEmbedPage = withApiKeySession(VisualizationEmbed); + export default { path: "/embed/query/:queryId/visualization/:visualizationId", authenticated: false, render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }; diff --git a/client/app/pages/query-snippets/QuerySnippetsList.jsx b/client/app/pages/query-snippets/QuerySnippetsList.jsx index 2459587faf..665d32927c 100644 --- a/client/app/pages/query-snippets/QuerySnippetsList.jsx +++ b/client/app/pages/query-snippets/QuerySnippetsList.jsx @@ -3,7 +3,7 @@ import React from "react"; import Button from "antd/lib/button"; import Modal from "antd/lib/modal"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; import QuerySnippetDialog from "@/components/query-snippets/QuerySnippetDialog"; @@ -15,7 +15,6 @@ import { StateStorage } from "@/components/items-list/classes/StateStorage"; import LoadingState from "@/components/items-list/components/LoadingState"; import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTable"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import QuerySnippet from "@/services/query-snippet"; import { currentUser } from "@/services/auth"; @@ -186,26 +185,28 @@ class QuerySnippetsList extends React.Component { } } -const QuerySnippetsListPage = wrapSettingsTab( - { - permission: "create_query", - title: "Query Snippets", - path: "query_snippets", - order: 5, - }, - liveItemsList( - QuerySnippetsList, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest() { - return {}; - }, - getResource() { - return QuerySnippet.query.bind(QuerySnippet); - }, - }), - () => new StateStorage({ orderByField: "trigger", itemsPerPage: 10 }) +const QuerySnippetsListPage = withUserSession( + wrapSettingsTab( + { + permission: "create_query", + title: "Query Snippets", + path: "query_snippets", + order: 5, + }, + liveItemsList( + QuerySnippetsList, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest() { + return {}; + }, + getResource() { + return QuerySnippet.query.bind(QuerySnippet); + }, + }), + () => new StateStorage({ orderByField: "trigger", itemsPerPage: 10 }) + ) ) ); @@ -214,34 +215,22 @@ export default [ path: "/query_snippets", title: "Query Snippets", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/query_snippets/:querySnippetId(new|[0-9]+)", title: "Query Snippets", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, ]; diff --git a/client/app/pages/settings/OrganizationSettings.jsx b/client/app/pages/settings/OrganizationSettings.jsx index a87d25c968..c56a840565 100644 --- a/client/app/pages/settings/OrganizationSettings.jsx +++ b/client/app/pages/settings/OrganizationSettings.jsx @@ -9,9 +9,8 @@ import Input from "antd/lib/input"; import Select from "antd/lib/select"; import Checkbox from "antd/lib/checkbox"; import Tooltip from "antd/lib/tooltip"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import LoadingState from "@/components/items-list/components/LoadingState"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { clientConfig } from "@/services/auth"; import recordEvent from "@/services/recordEvent"; @@ -271,24 +270,20 @@ class OrganizationSettings extends React.Component { } } -const OrganizationSettingsPage = wrapSettingsTab( - { - permission: "admin", - title: "Settings", - path: "settings/organization", - order: 6, - }, - OrganizationSettings +const OrganizationSettingsPage = withUserSession( + wrapSettingsTab( + { + permission: "admin", + title: "Settings", + path: "settings/organization", + order: 6, + }, + OrganizationSettings + ) ); export default { path: "/settings/organization", title: "Organization Settings", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }; diff --git a/client/app/pages/users/UserProfile.jsx b/client/app/pages/users/UserProfile.jsx index 3b34386916..c47dda1f64 100644 --- a/client/app/pages/users/UserProfile.jsx +++ b/client/app/pages/users/UserProfile.jsx @@ -1,13 +1,12 @@ import React from "react"; import PropTypes from "prop-types"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import EmailSettingsWarning from "@/components/EmailSettingsWarning"; import UserEdit from "@/components/users/UserEdit"; import UserShow from "@/components/users/UserShow"; import LoadingState from "@/components/items-list/components/LoadingState"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import User from "@/services/user"; import { currentUser } from "@/services/auth"; import "./settings.less"; @@ -48,36 +47,26 @@ class UserProfile extends React.Component { } } -const UserProfilePage = wrapSettingsTab( - { - title: "Account", - path: "users/me", - order: 7, - }, - UserProfile +const UserProfilePage = withUserSession( + wrapSettingsTab( + { + title: "Account", + path: "users/me", + order: 7, + }, + UserProfile + ) ); export default [ { path: "/users/me", title: "Account", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }, { path: "/users/:userId([0-9]+)", title: "Users", - render: currentRoute => ( - - - {({ handleError }) => } - - - ), + render: currentRoute => , }, ]; diff --git a/client/app/pages/users/UsersList.jsx b/client/app/pages/users/UsersList.jsx index 39c760003f..f8559971f2 100644 --- a/client/app/pages/users/UsersList.jsx +++ b/client/app/pages/users/UsersList.jsx @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import Button from "antd/lib/button"; import Modal from "antd/lib/modal"; -import AuthenticatedPageWrapper from "@/components/ApplicationArea/AuthenticatedPageWrapper"; +import withUserSession from "@/components/ApplicationArea/withUserSession"; import Paginator from "@/components/Paginator"; import DynamicComponent from "@/components/DynamicComponent"; import { UserPreviewCard } from "@/components/PreviewCard"; @@ -22,7 +22,6 @@ import ItemsTable, { Columns } from "@/components/items-list/components/ItemsTab import Layout from "@/components/layouts/ContentWithSidebar"; import CreateUserDialog from "@/components/users/CreateUserDialog"; import wrapSettingsTab from "@/components/SettingsWrapper"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { currentUser } from "@/services/auth"; import { policy } from "@/services/policy"; @@ -242,38 +241,40 @@ class UsersList extends React.Component { } } -const UsersListPage = wrapSettingsTab( - { - permission: "list_users", - title: "Users", - path: "users", - isActive: path => path.startsWith("/users") && path !== "/users/me", - order: 2, - }, - itemsList( - UsersList, - () => - new ResourceItemsSource({ - getRequest(request, { params: { currentPage } }) { - switch (currentPage) { - case "active": - request.pending = false; - break; - case "pending": - request.pending = true; - break; - case "disabled": - request.disabled = true; - break; - // no default - } - return request; - }, - getResource() { - return User.query.bind(User); - }, - }), - () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) +const UsersListPage = withUserSession( + wrapSettingsTab( + { + permission: "list_users", + title: "Users", + path: "users", + isActive: path => path.startsWith("/users") && path !== "/users/me", + order: 2, + }, + itemsList( + UsersList, + () => + new ResourceItemsSource({ + getRequest(request, { params: { currentPage } }) { + switch (currentPage) { + case "active": + request.pending = false; + break; + case "pending": + request.pending = true; + break; + case "disabled": + request.disabled = true; + break; + // no default + } + return request; + }, + getResource() { + return User.query.bind(User); + }, + }), + () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) + ) ) ); @@ -282,68 +283,44 @@ export default [ path: "/users", title: "Users", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/users/new", title: "Users", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/users/pending", title: "Pending Invitations", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, { path: "/users/disabled", title: "Disabled Users", render: currentRoute => ( - - - {({ handleError }) => ( - - )} - - + ), }, ]; From 8348fe0a166f32be31a9e12e68c8916d6b4b0bc4 Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Thu, 23 Jan 2020 10:24:20 +0200 Subject: [PATCH 2/5] Replace HoC wrappers with functions to create route definition --- .../routeWithApiKeySession.jsx | 56 ++++++++++ .../ApplicationArea/routeWithUserSession.jsx | 72 +++++++++++++ .../ApplicationArea/withApiKeySession.jsx | 42 -------- .../ApplicationArea/withUserSession.jsx | 67 ------------ client/app/pages/admin/Jobs.jsx | 10 +- client/app/pages/admin/OutdatedQueries.jsx | 54 +++++----- client/app/pages/admin/SystemStatus.jsx | 10 +- client/app/pages/alert/Alert.jsx | 22 ++-- client/app/pages/alerts/AlertsList.jsx | 38 ++++--- client/app/pages/dashboards/DashboardList.jsx | 50 +++++---- client/app/pages/dashboards/DashboardPage.jsx | 10 +- .../pages/dashboards/PublicDashboardPage.jsx | 18 +--- .../pages/data-sources/DataSourcesList.jsx | 34 +++--- .../app/pages/data-sources/EditDataSource.jsx | 10 +- .../pages/destinations/DestinationsList.jsx | 34 +++--- .../pages/destinations/EditDestination.jsx | 10 +- client/app/pages/groups/GroupDataSources.jsx | 42 ++++---- client/app/pages/groups/GroupMembers.jsx | 42 ++++---- client/app/pages/groups/GroupsList.jsx | 52 +++++---- client/app/pages/home/Home.jsx | 10 +- client/app/pages/queries-list/QueriesList.jsx | 70 ++++++------ client/app/pages/queries/QuerySource.jsx | 22 ++-- client/app/pages/queries/QueryView.jsx | 10 +- .../app/pages/queries/VisualizationEmbed.jsx | 14 +-- .../query-snippets/QuerySnippetsList.jsx | 60 +++++------ .../pages/settings/OrganizationSettings.jsx | 26 +++-- client/app/pages/users/UserProfile.jsx | 30 +++--- client/app/pages/users/UsersList.jsx | 100 +++++++++--------- 28 files changed, 490 insertions(+), 525 deletions(-) create mode 100644 client/app/components/ApplicationArea/routeWithApiKeySession.jsx create mode 100644 client/app/components/ApplicationArea/routeWithUserSession.jsx delete mode 100644 client/app/components/ApplicationArea/withApiKeySession.jsx delete mode 100644 client/app/components/ApplicationArea/withUserSession.jsx diff --git a/client/app/components/ApplicationArea/routeWithApiKeySession.jsx b/client/app/components/ApplicationArea/routeWithApiKeySession.jsx new file mode 100644 index 0000000000..8e6843adfb --- /dev/null +++ b/client/app/components/ApplicationArea/routeWithApiKeySession.jsx @@ -0,0 +1,56 @@ +import React, { useEffect, useState, useContext } from "react"; +import PropTypes from "prop-types"; +import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; +import { Auth } from "@/services/auth"; + +function ApiKeySessionWrapper({ apiKey, currentRoute, renderChildren }) { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const { handleError } = useContext(ErrorBoundaryContext); + + useEffect(() => { + let isCancelled = false; + Auth.setApiKey(apiKey); + Auth.loadConfig() + .then(() => { + if (!isCancelled) { + setIsAuthenticated(true); + } + }) + .catch(() => { + if (!isCancelled) { + setIsAuthenticated(false); + } + }); + return () => { + isCancelled = true; + }; + }, [apiKey]); + + if (!isAuthenticated) { + return null; + } + + return ( + + {renderChildren(currentRoute, { apiKey, onError: handleError })} + + ); +} + +ApiKeySessionWrapper.propTypes = { + apiKey: PropTypes.string.isRequired, + renderChildren: PropTypes.func, +}; + +ApiKeySessionWrapper.defaultProps = { + renderChildren: () => null, +}; + +export default function routeWithApiKeySession({ render, getApiKey, ...rest }) { + return { + ...rest, + render: currentRoute => ( + + ), + }; +} diff --git a/client/app/components/ApplicationArea/routeWithUserSession.jsx b/client/app/components/ApplicationArea/routeWithUserSession.jsx new file mode 100644 index 0000000000..f3f58ee6f1 --- /dev/null +++ b/client/app/components/ApplicationArea/routeWithUserSession.jsx @@ -0,0 +1,72 @@ +import React, { useEffect, useState } from "react"; +import PropTypes from "prop-types"; +import ErrorBoundary, { ErrorBoundaryContext } from "@/components/ErrorBoundary"; +import { Auth } from "@/services/auth"; +import organizationStatus from "@/services/organizationStatus"; +import ApplicationHeader from "./ApplicationHeader"; +import ErrorMessage from "./ErrorMessage"; + +function UserSessionWrapper({ bodyClass, currentRoute, renderChildren }) { + const [isAuthenticated, setIsAuthenticated] = useState(!!Auth.isAuthenticated()); + + useEffect(() => { + let isCancelled = false; + Promise.all([Auth.requireSession(), organizationStatus.refresh()]) + .then(() => { + if (!isCancelled) { + setIsAuthenticated(!!Auth.isAuthenticated()); + } + }) + .catch(() => { + if (!isCancelled) { + setIsAuthenticated(false); + } + }); + return () => { + isCancelled = true; + }; + }, []); + + useEffect(() => { + if (bodyClass) { + document.body.classList.toggle(bodyClass, true); + return () => { + document.body.classList.toggle(bodyClass, false); + }; + } + }, [bodyClass]); + + if (!isAuthenticated) { + return null; + } + + return ( + + + + }> + + {({ handleError }) => renderChildren(currentRoute, { onError: handleError })} + + + + + ); +} + +UserSessionWrapper.propTypes = { + bodyClass: PropTypes.string, + renderChildren: PropTypes.func, +}; + +UserSessionWrapper.defaultProps = { + bodyClass: null, + renderChildren: () => null, +}; + +export default function routeWithUserSession({ render, bodyClass, ...rest }) { + return { + ...rest, + render: currentRoute => , + }; +} diff --git a/client/app/components/ApplicationArea/withApiKeySession.jsx b/client/app/components/ApplicationArea/withApiKeySession.jsx deleted file mode 100644 index 3c37f5d0fb..0000000000 --- a/client/app/components/ApplicationArea/withApiKeySession.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import React, { useEffect, useState, useContext } from "react"; -import PropTypes from "prop-types"; -import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; -import { Auth } from "@/services/auth"; - -export default function withApiKeySession(WrappedComponent) { - function ApiKeySessionWrapper({ apiKey, ...props }) { - const [isAuthenticated, setIsAuthenticated] = useState(false); - const { handleError } = useContext(ErrorBoundaryContext); - - useEffect(() => { - let isCancelled = false; - Auth.setApiKey(apiKey); - Auth.loadConfig() - .then(() => { - if (!isCancelled) { - setIsAuthenticated(true); - } - }) - .catch(() => { - if (!isCancelled) { - setIsAuthenticated(false); - } - }); - return () => { - isCancelled = true; - }; - }, [apiKey]); - - if (!isAuthenticated) { - return null; - } - - return ; - } - - ApiKeySessionWrapper.propTypes = { - apiKey: PropTypes.string.isRequired, - }; - - return ApiKeySessionWrapper; -} diff --git a/client/app/components/ApplicationArea/withUserSession.jsx b/client/app/components/ApplicationArea/withUserSession.jsx deleted file mode 100644 index be52928de2..0000000000 --- a/client/app/components/ApplicationArea/withUserSession.jsx +++ /dev/null @@ -1,67 +0,0 @@ -import React, { useEffect, useState } from "react"; -import PropTypes from "prop-types"; -import ErrorBoundary, { ErrorBoundaryContext } from "@/components/ErrorBoundary"; -import { Auth } from "@/services/auth"; -import organizationStatus from "@/services/organizationStatus"; -import ApplicationHeader from "./ApplicationHeader"; -import ErrorMessage from "./ErrorMessage"; - -export default function withUserSession(WrappedComponent) { - function UserSessionWrapper({ bodyClass, ...props }) { - const [isAuthenticated, setIsAuthenticated] = useState(!!Auth.isAuthenticated()); - - useEffect(() => { - let isCancelled = false; - Promise.all([Auth.requireSession(), organizationStatus.refresh()]) - .then(() => { - if (!isCancelled) { - setIsAuthenticated(!!Auth.isAuthenticated()); - } - }) - .catch(() => { - if (!isCancelled) { - setIsAuthenticated(false); - } - }); - return () => { - isCancelled = true; - }; - }, []); - - useEffect(() => { - if (bodyClass) { - document.body.classList.toggle(bodyClass, true); - return () => { - document.body.classList.toggle(bodyClass, false); - }; - } - }, [bodyClass]); - - if (!isAuthenticated) { - return null; - } - - return ( - <> - - }> - - {({ handleError }) => } - - - - ); - } - - UserSessionWrapper.propTypes = { - bodyClass: PropTypes.string, - children: PropTypes.node, - }; - - UserSessionWrapper.defaultProps = { - bodyClass: null, - children: null, - }; - - return UserSessionWrapper; -} diff --git a/client/app/pages/admin/Jobs.jsx b/client/app/pages/admin/Jobs.jsx index 5a1bb0ca86..dcf1ece74f 100644 --- a/client/app/pages/admin/Jobs.jsx +++ b/client/app/pages/admin/Jobs.jsx @@ -5,7 +5,7 @@ import { axios } from "@/services/axios"; import Alert from "antd/lib/alert"; import Tabs from "antd/lib/tabs"; import * as Grid from "antd/lib/grid"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import Layout from "@/components/admin/Layout"; import { CounterCard, WorkersTable, QueuesTable, OtherJobsTable } from "@/components/admin/RQStatus"; @@ -120,10 +120,8 @@ class Jobs extends React.Component { } } -const JobsPage = withUserSession(Jobs); - -export default { +export default routeWithUserSession({ path: "/admin/queries/jobs", title: "RQ Status", - render: currentRoute => , -}; + render: (currentRoute, props) => , +}); diff --git a/client/app/pages/admin/OutdatedQueries.jsx b/client/app/pages/admin/OutdatedQueries.jsx index c8a58b4e28..47a1da5b55 100644 --- a/client/app/pages/admin/OutdatedQueries.jsx +++ b/client/app/pages/admin/OutdatedQueries.jsx @@ -4,7 +4,7 @@ import { axios } from "@/services/axios"; import Switch from "antd/lib/switch"; import * as Grid from "antd/lib/grid"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import Paginator from "@/components/Paginator"; import { QueryTagsControl } from "@/components/tags-control/TagsControl"; import SchedulePhrase from "@/components/queries/SchedulePhrase"; @@ -146,39 +146,37 @@ class OutdatedQueries extends React.Component { } } -const OutdatedQueriesPage = withUserSession( - itemsList( - OutdatedQueries, - () => - new ItemsSource({ - doRequest(request, context) { - return ( - axios - .get("/api/admin/queries/outdated") - // eslint-disable-next-line camelcase - .then(({ queries, updated_at }) => { - context.setCustomParams({ lastUpdatedAt: parseFloat(updated_at) }); - return queries; - }) - ); - }, - processResults(items) { - return map(items, item => new Query(item)); - }, - isPlainList: true, - }), - () => new StateStorage({ orderByField: "created_at", orderByReverse: true }) - ) +const OutdatedQueriesPage = itemsList( + OutdatedQueries, + () => + new ItemsSource({ + doRequest(request, context) { + return ( + axios + .get("/api/admin/queries/outdated") + // eslint-disable-next-line camelcase + .then(({ queries, updated_at }) => { + context.setCustomParams({ lastUpdatedAt: parseFloat(updated_at) }); + return queries; + }) + ); + }, + processResults(items) { + return map(items, item => new Query(item)); + }, + isPlainList: true, + }), + () => new StateStorage({ orderByField: "created_at", orderByReverse: true }) ); -export default { +export default routeWithUserSession({ path: "/admin/queries/outdated", title: "Outdated Queries", - render: currentRoute => ( + render: (currentRoute, props) => ( ), -}; +}); diff --git a/client/app/pages/admin/SystemStatus.jsx b/client/app/pages/admin/SystemStatus.jsx index bb8d31febf..dafa7e6f1c 100644 --- a/client/app/pages/admin/SystemStatus.jsx +++ b/client/app/pages/admin/SystemStatus.jsx @@ -3,7 +3,7 @@ import React from "react"; import { axios } from "@/services/axios"; import PropTypes from "prop-types"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import Layout from "@/components/admin/Layout"; import * as StatusBlock from "@/components/admin/StatusBlock"; import recordEvent from "@/services/recordEvent"; @@ -80,10 +80,8 @@ class SystemStatus extends React.Component { } } -const SystemStatusPage = withUserSession(SystemStatus); - -export default { +export default routeWithUserSession({ path: "/admin/status", title: "System Status", - render: currentRoute => , -}; + render: (currentRoute, props) => , +}); diff --git a/client/app/pages/alert/Alert.jsx b/client/app/pages/alert/Alert.jsx index 1918c7d389..1a2af44167 100644 --- a/client/app/pages/alert/Alert.jsx +++ b/client/app/pages/alert/Alert.jsx @@ -3,7 +3,7 @@ import React from "react"; import PropTypes from "prop-types"; import { currentUser } from "@/services/auth"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import notification from "@/services/notification"; import AlertService from "@/services/alert"; @@ -251,22 +251,20 @@ class Alert extends React.Component { } } -const AlertPage = withUserSession(Alert); - export default [ - { + routeWithUserSession({ path: "/alerts/new", title: "New Alert", - render: currentRoute => , - }, - { + render: (currentRoute, props) => , + }), + routeWithUserSession({ path: "/alerts/:alertId([0-9]+)", title: "Alert", - render: currentRoute => , - }, - { + render: (currentRoute, props) => , + }), + routeWithUserSession({ path: "/alerts/:alertId([0-9]+)/edit", title: "Alert", - render: currentRoute => , - }, + render: (currentRoute, props) => , + }), ]; diff --git a/client/app/pages/alerts/AlertsList.jsx b/client/app/pages/alerts/AlertsList.jsx index 2f60cbbddf..f4351ced47 100644 --- a/client/app/pages/alerts/AlertsList.jsx +++ b/client/app/pages/alerts/AlertsList.jsx @@ -1,6 +1,6 @@ import { toUpper } from "lodash"; import React from "react"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import PageHeader from "@/components/PageHeader"; import Paginator from "@/components/Paginator"; import EmptyState from "@/components/empty-state/EmptyState"; @@ -105,31 +105,29 @@ class AlertsList extends React.Component { } } -const AlertsListPage = withUserSession( - liveItemsList( - AlertsList, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest() { - return {}; - }, - getResource() { - return Alert.query.bind(Alert); - }, - }), - () => new StateStorage({ orderByField: "created_at", orderByReverse: true, itemsPerPage: 20 }) - ) +const AlertsListPage = liveItemsList( + AlertsList, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest() { + return {}; + }, + getResource() { + return Alert.query.bind(Alert); + }, + }), + () => new StateStorage({ orderByField: "created_at", orderByReverse: true, itemsPerPage: 20 }) ); -export default { +export default routeWithUserSession({ path: "/alerts", title: "Alerts", - render: currentRoute => ( + render: (currentRoute, props) => ( ), -}; +}); diff --git a/client/app/pages/dashboards/DashboardList.jsx b/client/app/pages/dashboards/DashboardList.jsx index 7c5f7651a2..f3b2c695d5 100644 --- a/client/app/pages/dashboards/DashboardList.jsx +++ b/client/app/pages/dashboards/DashboardList.jsx @@ -1,6 +1,6 @@ import React from "react"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import PageHeader from "@/components/PageHeader"; import Paginator from "@/components/Paginator"; import { DashboardTagsControl } from "@/components/tags-control/TagsControl"; @@ -130,46 +130,44 @@ class DashboardList extends React.Component { } } -const DashboardListPage = withUserSession( - itemsList( - DashboardList, - () => - new ResourceItemsSource({ - getResource({ params: { currentPage } }) { - return { - all: Dashboard.query.bind(Dashboard), - favorites: Dashboard.favorites.bind(Dashboard), - }[currentPage]; - }, - getItemProcessor() { - return item => new Dashboard(item); - }, - }), - () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) - ) +const DashboardListPage = itemsList( + DashboardList, + () => + new ResourceItemsSource({ + getResource({ params: { currentPage } }) { + return { + all: Dashboard.query.bind(Dashboard), + favorites: Dashboard.favorites.bind(Dashboard), + }[currentPage]; + }, + getItemProcessor() { + return item => new Dashboard(item); + }, + }), + () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) ); export default [ - { + routeWithUserSession({ path: "/dashboards", title: "Dashboards", - render: currentRoute => ( + render: (currentRoute, ...props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/dashboards/favorites", title: "Favorite Dashboards", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, + }), ]; diff --git a/client/app/pages/dashboards/DashboardPage.jsx b/client/app/pages/dashboards/DashboardPage.jsx index e7a80fafb1..d9c281f25e 100644 --- a/client/app/pages/dashboards/DashboardPage.jsx +++ b/client/app/pages/dashboards/DashboardPage.jsx @@ -9,7 +9,7 @@ import Menu from "antd/lib/menu"; import Icon from "antd/lib/icon"; import Modal from "antd/lib/modal"; import Tooltip from "antd/lib/tooltip"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import DashboardGrid from "@/components/dashboards/DashboardGrid"; import FavoritesControl from "@/components/FavoritesControl"; import EditInPlace from "@/components/EditInPlace"; @@ -406,9 +406,7 @@ DashboardPage.defaultProps = { onError: PropTypes.func, }; -const WrappedDashboardPage = withUserSession(DashboardPage); - -export default { +export default routeWithUserSession({ path: "/dashboard/:dashboardSlug", - render: currentRoute => , -}; + render: (currentRoute, props) => , +}); diff --git a/client/app/pages/dashboards/PublicDashboardPage.jsx b/client/app/pages/dashboards/PublicDashboardPage.jsx index 063886b4ef..84f77e35c3 100644 --- a/client/app/pages/dashboards/PublicDashboardPage.jsx +++ b/client/app/pages/dashboards/PublicDashboardPage.jsx @@ -1,7 +1,7 @@ import { isEmpty } from "lodash"; import React from "react"; import PropTypes from "prop-types"; -import withApiKeySession from "@/components/ApplicationArea/withApiKeySession"; +import routeWithApiKeySession from "@/components/ApplicationArea/routeWithApiKeySession"; import BigMessage from "@/components/BigMessage"; import PageHeader from "@/components/PageHeader"; import Parameters from "@/components/Parameters"; @@ -95,16 +95,8 @@ class PublicDashboardPage extends React.Component { } } -const WrappedPublicDashboardPage = withApiKeySession(PublicDashboardPage); - -export default { +export default routeWithApiKeySession({ path: "/public/dashboards/:token", - authenticated: false, - render: currentRoute => ( - - ), -}; + render: (currentRoute, props) => , + getApiKey: curentRoute => curentRoute.routeParams.token, +}); diff --git a/client/app/pages/data-sources/DataSourcesList.jsx b/client/app/pages/data-sources/DataSourcesList.jsx index 3870157d1a..98d5eb7b74 100644 --- a/client/app/pages/data-sources/DataSourcesList.jsx +++ b/client/app/pages/data-sources/DataSourcesList.jsx @@ -4,7 +4,7 @@ import Button from "antd/lib/button"; import { isEmpty } from "lodash"; import DataSource, { IMG_ROOT } from "@/services/data-source"; import { policy } from "@/services/policy"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import CardsList from "@/components/cards-list/CardsList"; import LoadingState from "@/components/items-list/components/LoadingState"; @@ -144,29 +144,27 @@ class DataSourcesList extends React.Component { } } -const DataSourcesListPage = withUserSession( - wrapSettingsTab( - { - permission: "admin", - title: "Data Sources", - path: "data_sources", - order: 1, - }, - DataSourcesList - ) +const DataSourcesListPage = wrapSettingsTab( + { + permission: "admin", + title: "Data Sources", + path: "data_sources", + order: 1, + }, + DataSourcesList ); export default [ - { + routeWithUserSession({ path: "/data_sources", title: "Data Sources", - render: currentRoute => , - }, - { + render: (currentRoute, props) => , + }), + routeWithUserSession({ path: "/data_sources/new", title: "Data Sources", - render: currentRoute => ( - + render: (currentRoute, props) => ( + ), - }, + }), ]; diff --git a/client/app/pages/data-sources/EditDataSource.jsx b/client/app/pages/data-sources/EditDataSource.jsx index 92a634e26b..c1afa2b4d9 100644 --- a/client/app/pages/data-sources/EditDataSource.jsx +++ b/client/app/pages/data-sources/EditDataSource.jsx @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import { get, find, toUpper } from "lodash"; import Modal from "antd/lib/modal"; import DataSource, { IMG_ROOT } from "@/services/data-source"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import notification from "@/services/notification"; import LoadingState from "@/components/items-list/components/LoadingState"; @@ -136,10 +136,10 @@ class EditDataSource extends React.Component { } } -const EditDataSourcePage = withUserSession(wrapSettingsTab(null, EditDataSource)); +const EditDataSourcePage = wrapSettingsTab(null, EditDataSource); -export default { +export default routeWithUserSession({ path: "/data_sources/:dataSourceId([0-9]+)", title: "Data Sources", - render: currentRoute => , -}; + render: (currentRoute, props) => , +}); diff --git a/client/app/pages/destinations/DestinationsList.jsx b/client/app/pages/destinations/DestinationsList.jsx index 980ddbcfa0..494291747e 100644 --- a/client/app/pages/destinations/DestinationsList.jsx +++ b/client/app/pages/destinations/DestinationsList.jsx @@ -4,7 +4,7 @@ import Button from "antd/lib/button"; import { isEmpty, isString, find, get } from "lodash"; import Destination, { IMG_ROOT } from "@/services/destination"; import { policy } from "@/services/policy"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import CardsList from "@/components/cards-list/CardsList"; import LoadingState from "@/components/items-list/components/LoadingState"; @@ -132,29 +132,27 @@ class DestinationsList extends React.Component { } } -const DestinationsListPage = withUserSession( - wrapSettingsTab( - { - permission: "admin", - title: "Alert Destinations", - path: "destinations", - order: 4, - }, - DestinationsList - ) +const DestinationsListPage = wrapSettingsTab( + { + permission: "admin", + title: "Alert Destinations", + path: "destinations", + order: 4, + }, + DestinationsList ); export default [ - { + routeWithUserSession({ path: "/destinations", title: "Alert Destinations", - render: currentRoute => , - }, - { + render: (currentRoute, props) => , + }), + routeWithUserSession({ path: "/destinations/new", title: "Alert Destinations", - render: currentRoute => ( - + render: (currentRoute, props) => ( + ), - }, + }), ]; diff --git a/client/app/pages/destinations/EditDestination.jsx b/client/app/pages/destinations/EditDestination.jsx index e723e2d085..4c149f307b 100644 --- a/client/app/pages/destinations/EditDestination.jsx +++ b/client/app/pages/destinations/EditDestination.jsx @@ -3,7 +3,7 @@ import React from "react"; import PropTypes from "prop-types"; import Modal from "antd/lib/modal"; import Destination, { IMG_ROOT } from "@/services/destination"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import notification from "@/services/notification"; import LoadingState from "@/components/items-list/components/LoadingState"; @@ -103,10 +103,10 @@ class EditDestination extends React.Component { } } -const EditDestinationPage = withUserSession(wrapSettingsTab(null, EditDestination)); +const EditDestinationPage = wrapSettingsTab(null, EditDestination); -export default { +export default routeWithUserSession({ path: "/destinations/:destinationId([0-9]+)", title: "Alert Destinations", - render: currentRoute => , -}; + render: (currentRoute, props) => , +}); diff --git a/client/app/pages/groups/GroupDataSources.jsx b/client/app/pages/groups/GroupDataSources.jsx index f8fe72c7a8..0ca65fe127 100644 --- a/client/app/pages/groups/GroupDataSources.jsx +++ b/client/app/pages/groups/GroupDataSources.jsx @@ -5,7 +5,7 @@ import Dropdown from "antd/lib/dropdown"; import Menu from "antd/lib/menu"; import Icon from "antd/lib/icon"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; @@ -228,34 +228,32 @@ class GroupDataSources extends React.Component { } } -const GroupDataSourcesPage = withUserSession( - wrapSettingsTab( - null, - liveItemsList( - GroupDataSources, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest(unused, { params: { groupId } }) { - return { id: groupId }; - }, - getResource() { - return Group.dataSources.bind(Group); - }, - }), - () => new StateStorage({ orderByField: "name" }) - ) +const GroupDataSourcesPage = wrapSettingsTab( + null, + liveItemsList( + GroupDataSources, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest(unused, { params: { groupId } }) { + return { id: groupId }; + }, + getResource() { + return Group.dataSources.bind(Group); + }, + }), + () => new StateStorage({ orderByField: "name" }) ) ); -export default { +export default routeWithUserSession({ path: "/groups/:groupId([0-9]+)/data_sources", title: "Group Data Sources", - render: currentRoute => ( + render: (currentRoute, props) => ( ), -}; +}); diff --git a/client/app/pages/groups/GroupMembers.jsx b/client/app/pages/groups/GroupMembers.jsx index ee985f51d3..c946f09386 100644 --- a/client/app/pages/groups/GroupMembers.jsx +++ b/client/app/pages/groups/GroupMembers.jsx @@ -2,7 +2,7 @@ import { includes, map } from "lodash"; import React from "react"; import Button from "antd/lib/button"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; @@ -191,34 +191,32 @@ class GroupMembers extends React.Component { } } -const GroupMembersPage = withUserSession( - wrapSettingsTab( - null, - liveItemsList( - GroupMembers, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest(unused, { params: { groupId } }) { - return { id: groupId }; - }, - getResource() { - return Group.members.bind(Group); - }, - }), - () => new StateStorage({ orderByField: "name" }) - ) +const GroupMembersPage = wrapSettingsTab( + null, + liveItemsList( + GroupMembers, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest(unused, { params: { groupId } }) { + return { id: groupId }; + }, + getResource() { + return Group.members.bind(Group); + }, + }), + () => new StateStorage({ orderByField: "name" }) ) ); -export default { +export default routeWithUserSession({ path: "/groups/:groupId([0-9]+)", title: "Group Members", - render: currentRoute => ( + render: (currentRoute, props) => ( ), -}; +}); diff --git a/client/app/pages/groups/GroupsList.jsx b/client/app/pages/groups/GroupsList.jsx index 1b34fa31cf..0919c3625d 100644 --- a/client/app/pages/groups/GroupsList.jsx +++ b/client/app/pages/groups/GroupsList.jsx @@ -1,7 +1,7 @@ import React from "react"; import Button from "antd/lib/button"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; @@ -125,39 +125,37 @@ class GroupsList extends React.Component { } } -const GroupsListPage = withUserSession( - wrapSettingsTab( - { - permission: "list_users", - title: "Groups", - path: "groups", - order: 3, - }, - liveItemsList( - GroupsList, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest() { - return {}; - }, - getResource() { - return Group.query.bind(Group); - }, - }), - () => new StateStorage({ orderByField: "name", itemsPerPage: 10 }) - ) +const GroupsListPage = wrapSettingsTab( + { + permission: "list_users", + title: "Groups", + path: "groups", + order: 3, + }, + liveItemsList( + GroupsList, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest() { + return {}; + }, + getResource() { + return Group.query.bind(Group); + }, + }), + () => new StateStorage({ orderByField: "name", itemsPerPage: 10 }) ) ); -export default { +export default routeWithUserSession({ path: "/groups", title: "Groups", - render: currentRoute => ( + render: (currentRoute, props) => ( ), -}; +}); diff --git a/client/app/pages/home/Home.jsx b/client/app/pages/home/Home.jsx index 3323b894c7..aa7972c568 100644 --- a/client/app/pages/home/Home.jsx +++ b/client/app/pages/home/Home.jsx @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import { includes, isEmpty } from "lodash"; import Alert from "antd/lib/alert"; import Icon from "antd/lib/icon"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import EmptyState from "@/components/empty-state/EmptyState"; import DynamicComponent from "@/components/DynamicComponent"; import BeaconConsent from "@/components/BeaconConsent"; @@ -173,10 +173,8 @@ function Home() { ); } -const HomePage = withUserSession(Home); - -export default { +export default routeWithUserSession({ path: "/", title: "Redash", - render: currentRoute => , -}; + render: (currentRoute, props) => , +}); diff --git a/client/app/pages/queries-list/QueriesList.jsx b/client/app/pages/queries-list/QueriesList.jsx index 8e6dd7c1d6..32df9e3d8c 100644 --- a/client/app/pages/queries-list/QueriesList.jsx +++ b/client/app/pages/queries-list/QueriesList.jsx @@ -1,6 +1,6 @@ import React from "react"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import PageHeader from "@/components/PageHeader"; import Paginator from "@/components/Paginator"; import { QueryTagsControl } from "@/components/tags-control/TagsControl"; @@ -143,70 +143,68 @@ class QueriesList extends React.Component { } } -const QueriesListPage = withUserSession( - itemsList( - QueriesList, - () => - new ResourceItemsSource({ - getResource({ params: { currentPage } }) { - return { - all: Query.query.bind(Query), - my: Query.myQueries.bind(Query), - favorites: Query.favorites.bind(Query), - archive: Query.archive.bind(Query), - }[currentPage]; - }, - getItemProcessor() { - return item => new Query(item); - }, - }), - () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) - ) +const QueriesListPage = itemsList( + QueriesList, + () => + new ResourceItemsSource({ + getResource({ params: { currentPage } }) { + return { + all: Query.query.bind(Query), + my: Query.myQueries.bind(Query), + favorites: Query.favorites.bind(Query), + archive: Query.archive.bind(Query), + }[currentPage]; + }, + getItemProcessor() { + return item => new Query(item); + }, + }), + () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) ); export default [ - { + routeWithUserSession({ path: "/queries", title: "Queries", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/queries/favorites", title: "Favorite Queries", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/queries/archive", title: "Archived Queries", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/queries/my", title: "My Queries", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, + }), ]; diff --git a/client/app/pages/queries/QuerySource.jsx b/client/app/pages/queries/QuerySource.jsx index ba5d45c975..9d53e668d6 100644 --- a/client/app/pages/queries/QuerySource.jsx +++ b/client/app/pages/queries/QuerySource.jsx @@ -3,7 +3,7 @@ import React, { useState, useRef, useEffect, useCallback } from "react"; import PropTypes from "prop-types"; import { useDebouncedCallback } from "use-debounce"; import Select from "antd/lib/select"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import Resizable from "@/components/Resizable"; import Parameters from "@/components/Parameters"; import EditInPlace from "@/components/EditInPlace"; @@ -443,25 +443,21 @@ QuerySource.propTypes = { query: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types }; -const QuerySourcePage = withUserSession(QuerySource); - export default [ - { + routeWithUserSession({ path: "/queries/new", - render: currentRoute => ( - - ), + render: (currentRoute, props) => , resolve: { query: () => Query.newQuery(), }, - }, - { + bodyClass: "fixed-layout", + }), + routeWithUserSession({ path: "/queries/:queryId([0-9]+)/source", - render: currentRoute => ( - - ), + render: (currentRoute, props) => , resolve: { query: ({ queryId }) => Query.get({ id: queryId }), }, - }, + bodyClass: "fixed-layout", + }), ]; diff --git a/client/app/pages/queries/QueryView.jsx b/client/app/pages/queries/QueryView.jsx index 5772a758ca..1bead2cd4a 100644 --- a/client/app/pages/queries/QueryView.jsx +++ b/client/app/pages/queries/QueryView.jsx @@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from "react"; import PropTypes from "prop-types"; import Divider from "antd/lib/divider"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import EditInPlace from "@/components/EditInPlace"; import Parameters from "@/components/Parameters"; import TimeAgo from "@/components/TimeAgo"; @@ -184,12 +184,10 @@ function QueryView(props) { QueryView.propTypes = { query: PropTypes.object.isRequired }; // eslint-disable-line react/forbid-prop-types -const QueryViewPage = withUserSession(QueryView); - -export default { +export default routeWithUserSession({ path: "/queries/:queryId([0-9]+)", - render: currentRoute => , + render: (currentRoute, props) => , resolve: { query: ({ queryId }) => Query.get({ id: queryId }), }, -}; +}); diff --git a/client/app/pages/queries/VisualizationEmbed.jsx b/client/app/pages/queries/VisualizationEmbed.jsx index 137dd313cf..44488148dc 100644 --- a/client/app/pages/queries/VisualizationEmbed.jsx +++ b/client/app/pages/queries/VisualizationEmbed.jsx @@ -8,7 +8,7 @@ import Dropdown from "antd/lib/dropdown"; import Icon from "antd/lib/icon"; import Menu from "antd/lib/menu"; import Tooltip from "antd/lib/tooltip"; -import withApiKeySession from "@/components/ApplicationArea/withApiKeySession"; +import routeWithApiKeySession from "@/components/ApplicationArea/routeWithApiKeySession"; import { Query } from "@/services/query"; import location from "@/services/location"; import { formatDateTime } from "@/lib/utils"; @@ -264,12 +264,8 @@ VisualizationEmbed.defaultProps = { onError: () => {}, }; -const VisualizationEmbedPage = withApiKeySession(VisualizationEmbed); - -export default { +export default routeWithApiKeySession({ path: "/embed/query/:queryId/visualization/:visualizationId", - authenticated: false, - render: currentRoute => ( - - ), -}; + render: (currentRoute, props) => , + getApiKey: () => location.search.api_key, +}); diff --git a/client/app/pages/query-snippets/QuerySnippetsList.jsx b/client/app/pages/query-snippets/QuerySnippetsList.jsx index 665d32927c..f890fa54bc 100644 --- a/client/app/pages/query-snippets/QuerySnippetsList.jsx +++ b/client/app/pages/query-snippets/QuerySnippetsList.jsx @@ -3,7 +3,7 @@ import React from "react"; import Button from "antd/lib/button"; import Modal from "antd/lib/modal"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; import QuerySnippetDialog from "@/components/query-snippets/QuerySnippetDialog"; @@ -185,52 +185,50 @@ class QuerySnippetsList extends React.Component { } } -const QuerySnippetsListPage = withUserSession( - wrapSettingsTab( - { - permission: "create_query", - title: "Query Snippets", - path: "query_snippets", - order: 5, - }, - liveItemsList( - QuerySnippetsList, - () => - new ResourceItemsSource({ - isPlainList: true, - getRequest() { - return {}; - }, - getResource() { - return QuerySnippet.query.bind(QuerySnippet); - }, - }), - () => new StateStorage({ orderByField: "trigger", itemsPerPage: 10 }) - ) +const QuerySnippetsListPage = wrapSettingsTab( + { + permission: "create_query", + title: "Query Snippets", + path: "query_snippets", + order: 5, + }, + liveItemsList( + QuerySnippetsList, + () => + new ResourceItemsSource({ + isPlainList: true, + getRequest() { + return {}; + }, + getResource() { + return QuerySnippet.query.bind(QuerySnippet); + }, + }), + () => new StateStorage({ orderByField: "trigger", itemsPerPage: 10 }) ) ); export default [ - { + routeWithUserSession({ path: "/query_snippets", title: "Query Snippets", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/query_snippets/:querySnippetId(new|[0-9]+)", title: "Query Snippets", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, + }), ]; diff --git a/client/app/pages/settings/OrganizationSettings.jsx b/client/app/pages/settings/OrganizationSettings.jsx index c56a840565..7c9039adbc 100644 --- a/client/app/pages/settings/OrganizationSettings.jsx +++ b/client/app/pages/settings/OrganizationSettings.jsx @@ -9,7 +9,7 @@ import Input from "antd/lib/input"; import Select from "antd/lib/select"; import Checkbox from "antd/lib/checkbox"; import Tooltip from "antd/lib/tooltip"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import LoadingState from "@/components/items-list/components/LoadingState"; import { clientConfig } from "@/services/auth"; @@ -270,20 +270,18 @@ class OrganizationSettings extends React.Component { } } -const OrganizationSettingsPage = withUserSession( - wrapSettingsTab( - { - permission: "admin", - title: "Settings", - path: "settings/organization", - order: 6, - }, - OrganizationSettings - ) +const OrganizationSettingsPage = wrapSettingsTab( + { + permission: "admin", + title: "Settings", + path: "settings/organization", + order: 6, + }, + OrganizationSettings ); -export default { +export default routeWithUserSession({ path: "/settings/organization", title: "Organization Settings", - render: currentRoute => , -}; + render: (currentRoute, props) => , +}); diff --git a/client/app/pages/users/UserProfile.jsx b/client/app/pages/users/UserProfile.jsx index c47dda1f64..abbaa4fa18 100644 --- a/client/app/pages/users/UserProfile.jsx +++ b/client/app/pages/users/UserProfile.jsx @@ -1,7 +1,7 @@ import React from "react"; import PropTypes from "prop-types"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import EmailSettingsWarning from "@/components/EmailSettingsWarning"; import UserEdit from "@/components/users/UserEdit"; import UserShow from "@/components/users/UserShow"; @@ -47,26 +47,24 @@ class UserProfile extends React.Component { } } -const UserProfilePage = withUserSession( - wrapSettingsTab( - { - title: "Account", - path: "users/me", - order: 7, - }, - UserProfile - ) +const UserProfilePage = wrapSettingsTab( + { + title: "Account", + path: "users/me", + order: 7, + }, + UserProfile ); export default [ - { + routeWithUserSession({ path: "/users/me", title: "Account", - render: currentRoute => , - }, - { + render: (currentRoute, props) => , + }), + routeWithUserSession({ path: "/users/:userId([0-9]+)", title: "Users", - render: currentRoute => , - }, + render: (currentRoute, props) => , + }), ]; diff --git a/client/app/pages/users/UsersList.jsx b/client/app/pages/users/UsersList.jsx index f8559971f2..eca20b68dd 100644 --- a/client/app/pages/users/UsersList.jsx +++ b/client/app/pages/users/UsersList.jsx @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import Button from "antd/lib/button"; import Modal from "antd/lib/modal"; -import withUserSession from "@/components/ApplicationArea/withUserSession"; +import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession"; import Paginator from "@/components/Paginator"; import DynamicComponent from "@/components/DynamicComponent"; import { UserPreviewCard } from "@/components/PreviewCard"; @@ -241,86 +241,84 @@ class UsersList extends React.Component { } } -const UsersListPage = withUserSession( - wrapSettingsTab( - { - permission: "list_users", - title: "Users", - path: "users", - isActive: path => path.startsWith("/users") && path !== "/users/me", - order: 2, - }, - itemsList( - UsersList, - () => - new ResourceItemsSource({ - getRequest(request, { params: { currentPage } }) { - switch (currentPage) { - case "active": - request.pending = false; - break; - case "pending": - request.pending = true; - break; - case "disabled": - request.disabled = true; - break; - // no default - } - return request; - }, - getResource() { - return User.query.bind(User); - }, - }), - () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) - ) +const UsersListPage = wrapSettingsTab( + { + permission: "list_users", + title: "Users", + path: "users", + isActive: path => path.startsWith("/users") && path !== "/users/me", + order: 2, + }, + itemsList( + UsersList, + () => + new ResourceItemsSource({ + getRequest(request, { params: { currentPage } }) { + switch (currentPage) { + case "active": + request.pending = false; + break; + case "pending": + request.pending = true; + break; + case "disabled": + request.disabled = true; + break; + // no default + } + return request; + }, + getResource() { + return User.query.bind(User); + }, + }), + () => new UrlStateStorage({ orderByField: "created_at", orderByReverse: true }) ) ); export default [ - { + routeWithUserSession({ path: "/users", title: "Users", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/users/new", title: "Users", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/users/pending", title: "Pending Invitations", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, - { + }), + routeWithUserSession({ path: "/users/disabled", title: "Disabled Users", - render: currentRoute => ( + render: (currentRoute, props) => ( ), - }, + }), ]; From e90f2ce9c943b6e3d1564351020608f1de10fe4d Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Thu, 23 Jan 2020 10:30:03 +0200 Subject: [PATCH 3/5] Some updates for code consistency --- client/app/pages/alerts/AlertsList.jsx | 4 ++-- client/app/pages/groups/GroupDataSources.jsx | 4 ++-- client/app/pages/groups/GroupMembers.jsx | 4 ++-- client/app/pages/groups/GroupsList.jsx | 4 ++-- client/app/pages/query-snippets/QuerySnippetsList.jsx | 4 ++-- client/app/pages/users/UsersList.jsx | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/client/app/pages/alerts/AlertsList.jsx b/client/app/pages/alerts/AlertsList.jsx index f4351ced47..ee1461fe23 100644 --- a/client/app/pages/alerts/AlertsList.jsx +++ b/client/app/pages/alerts/AlertsList.jsx @@ -4,7 +4,7 @@ import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSess import PageHeader from "@/components/PageHeader"; import Paginator from "@/components/Paginator"; import EmptyState from "@/components/empty-state/EmptyState"; -import { wrap as liveItemsList, ControllerType } from "@/components/items-list/ItemsList"; +import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource"; import { StateStorage } from "@/components/items-list/classes/StateStorage"; @@ -105,7 +105,7 @@ class AlertsList extends React.Component { } } -const AlertsListPage = liveItemsList( +const AlertsListPage = itemsList( AlertsList, () => new ResourceItemsSource({ diff --git a/client/app/pages/groups/GroupDataSources.jsx b/client/app/pages/groups/GroupDataSources.jsx index 0ca65fe127..626ba07de8 100644 --- a/client/app/pages/groups/GroupDataSources.jsx +++ b/client/app/pages/groups/GroupDataSources.jsx @@ -9,7 +9,7 @@ import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSess import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; -import { wrap as liveItemsList, ControllerType } from "@/components/items-list/ItemsList"; +import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource"; import { StateStorage } from "@/components/items-list/classes/StateStorage"; @@ -230,7 +230,7 @@ class GroupDataSources extends React.Component { const GroupDataSourcesPage = wrapSettingsTab( null, - liveItemsList( + itemsList( GroupDataSources, () => new ResourceItemsSource({ diff --git a/client/app/pages/groups/GroupMembers.jsx b/client/app/pages/groups/GroupMembers.jsx index c946f09386..8a6f2273d1 100644 --- a/client/app/pages/groups/GroupMembers.jsx +++ b/client/app/pages/groups/GroupMembers.jsx @@ -6,7 +6,7 @@ import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSess import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; -import { wrap as liveItemsList, ControllerType } from "@/components/items-list/ItemsList"; +import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource"; import { StateStorage } from "@/components/items-list/classes/StateStorage"; @@ -193,7 +193,7 @@ class GroupMembers extends React.Component { const GroupMembersPage = wrapSettingsTab( null, - liveItemsList( + itemsList( GroupMembers, () => new ResourceItemsSource({ diff --git a/client/app/pages/groups/GroupsList.jsx b/client/app/pages/groups/GroupsList.jsx index 0919c3625d..d2a20f96be 100644 --- a/client/app/pages/groups/GroupsList.jsx +++ b/client/app/pages/groups/GroupsList.jsx @@ -5,7 +5,7 @@ import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSess import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; -import { wrap as liveItemsList, ControllerType } from "@/components/items-list/ItemsList"; +import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource"; import { StateStorage } from "@/components/items-list/classes/StateStorage"; @@ -132,7 +132,7 @@ const GroupsListPage = wrapSettingsTab( path: "groups", order: 3, }, - liveItemsList( + itemsList( GroupsList, () => new ResourceItemsSource({ diff --git a/client/app/pages/query-snippets/QuerySnippetsList.jsx b/client/app/pages/query-snippets/QuerySnippetsList.jsx index f890fa54bc..2a572766d4 100644 --- a/client/app/pages/query-snippets/QuerySnippetsList.jsx +++ b/client/app/pages/query-snippets/QuerySnippetsList.jsx @@ -8,7 +8,7 @@ import navigateTo from "@/components/ApplicationArea/navigateTo"; import Paginator from "@/components/Paginator"; import QuerySnippetDialog from "@/components/query-snippets/QuerySnippetDialog"; -import { wrap as liveItemsList, ControllerType } from "@/components/items-list/ItemsList"; +import { wrap as itemsList, ControllerType } from "@/components/items-list/ItemsList"; import { ResourceItemsSource } from "@/components/items-list/classes/ItemsSource"; import { StateStorage } from "@/components/items-list/classes/StateStorage"; @@ -192,7 +192,7 @@ const QuerySnippetsListPage = wrapSettingsTab( path: "query_snippets", order: 5, }, - liveItemsList( + itemsList( QuerySnippetsList, () => new ResourceItemsSource({ diff --git a/client/app/pages/users/UsersList.jsx b/client/app/pages/users/UsersList.jsx index eca20b68dd..38e0fde3e8 100644 --- a/client/app/pages/users/UsersList.jsx +++ b/client/app/pages/users/UsersList.jsx @@ -278,22 +278,22 @@ const UsersListPage = wrapSettingsTab( export default [ routeWithUserSession({ - path: "/users", + path: "/users/new", title: "Users", render: (currentRoute, props) => ( ), }), routeWithUserSession({ - path: "/users/new", + path: "/users", title: "Users", render: (currentRoute, props) => ( From abe6b5b7f99ec8e4795d666be2e2b112c4c6516f Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Thu, 23 Jan 2020 11:07:00 +0200 Subject: [PATCH 4/5] ItemsList component: remove currentRoute dependency --- client/app/components/ErrorBoundary.jsx | 5 +++- .../app/components/items-list/ItemsList.jsx | 24 +++++++------------ client/app/pages/admin/OutdatedQueries.jsx | 5 ++-- client/app/pages/alerts/AlertsList.jsx | 6 +---- client/app/pages/dashboards/DashboardList.jsx | 14 +++-------- client/app/pages/groups/GroupDataSources.jsx | 5 ++-- client/app/pages/groups/GroupMembers.jsx | 6 +---- client/app/pages/groups/GroupsList.jsx | 6 +---- client/app/pages/queries-list/QueriesList.jsx | 24 ++++--------------- .../query-snippets/QuerySnippetsList.jsx | 11 +++++---- client/app/pages/users/UsersList.jsx | 24 ++++++------------- 11 files changed, 43 insertions(+), 87 deletions(-) diff --git a/client/app/components/ErrorBoundary.jsx b/client/app/components/ErrorBoundary.jsx index c6780799db..78e354efab 100644 --- a/client/app/components/ErrorBoundary.jsx +++ b/client/app/components/ErrorBoundary.jsx @@ -8,7 +8,10 @@ const logger = debug("redash:errors"); export const ErrorBoundaryContext = React.createContext({ handleError: error => { - throw error; + // Allow calling chain to roll up, and then throw the error in global context + setTimeout(() => { + throw error; + }); }, reset: () => {}, }); diff --git a/client/app/components/items-list/ItemsList.jsx b/client/app/components/items-list/ItemsList.jsx index fba0c13493..f82fbdb169 100644 --- a/client/app/components/items-list/ItemsList.jsx +++ b/client/app/components/items-list/ItemsList.jsx @@ -38,13 +38,11 @@ export const ControllerType = PropTypes.shape({ export function wrap(WrappedComponent, createItemsSource, createStateStorage) { class ItemsListWrapper extends React.Component { static propTypes = { - ...omit(WrappedComponent.propTypes, ["controller"]), onError: PropTypes.func, children: PropTypes.node, }; static defaultProps = { - ...omit(WrappedComponent.defaultProps, ["controller"]), onError: error => { // Allow calling chain to roll up, and then throw the error in global context setTimeout(() => { @@ -102,20 +100,13 @@ export function wrap(WrappedComponent, createItemsSource, createStateStorage) { // eslint-disable-next-line class-methods-use-this getState({ isLoaded, totalCount, pageItems, params, ...rest }) { - params = { - // Custom params from items source - ...params, - - title: this.props.currentRoute.title, - ...this.props.routeParams, - - // Add to params all props except of own ones - ...omit(this.props, ["onError", "children", "currentRoute", "routeParams"]), - }; return { ...rest, - params, + params: { + ...params, // custom params from items source + ...omit(this.props, ["onError", "children"]), // add all props except of own ones + }, isLoaded, isEmpty: !isLoaded || totalCount === 0, @@ -128,8 +119,11 @@ export function wrap(WrappedComponent, createItemsSource, createStateStorage) { render() { // don't pass own props to wrapped component const { children, onError, ...props } = this.props; - props.controller = this.state; - return {children}; + return ( + + {children} + + ); } } diff --git a/client/app/pages/admin/OutdatedQueries.jsx b/client/app/pages/admin/OutdatedQueries.jsx index 47a1da5b55..0d60e3fc54 100644 --- a/client/app/pages/admin/OutdatedQueries.jsx +++ b/client/app/pages/admin/OutdatedQueries.jsx @@ -174,9 +174,10 @@ export default routeWithUserSession({ title: "Outdated Queries", render: (currentRoute, props) => ( ), }); diff --git a/client/app/pages/alerts/AlertsList.jsx b/client/app/pages/alerts/AlertsList.jsx index ee1461fe23..0289275d56 100644 --- a/client/app/pages/alerts/AlertsList.jsx +++ b/client/app/pages/alerts/AlertsList.jsx @@ -124,10 +124,6 @@ export default routeWithUserSession({ path: "/alerts", title: "Alerts", render: (currentRoute, props) => ( - + ), }); diff --git a/client/app/pages/dashboards/DashboardList.jsx b/client/app/pages/dashboards/DashboardList.jsx index f3b2c695d5..786c59c8e2 100644 --- a/client/app/pages/dashboards/DashboardList.jsx +++ b/client/app/pages/dashboards/DashboardList.jsx @@ -151,23 +151,15 @@ export default [ routeWithUserSession({ path: "/dashboards", title: "Dashboards", - render: (currentRoute, ...props) => ( - + render: (currentRoute, props) => ( + ), }), routeWithUserSession({ path: "/dashboards/favorites", title: "Favorite Dashboards", render: (currentRoute, props) => ( - + ), }), ]; diff --git a/client/app/pages/groups/GroupDataSources.jsx b/client/app/pages/groups/GroupDataSources.jsx index 626ba07de8..2722bd802d 100644 --- a/client/app/pages/groups/GroupDataSources.jsx +++ b/client/app/pages/groups/GroupDataSources.jsx @@ -251,9 +251,10 @@ export default routeWithUserSession({ title: "Group Data Sources", render: (currentRoute, props) => ( ), }); diff --git a/client/app/pages/groups/GroupMembers.jsx b/client/app/pages/groups/GroupMembers.jsx index 8a6f2273d1..cb2610b1e1 100644 --- a/client/app/pages/groups/GroupMembers.jsx +++ b/client/app/pages/groups/GroupMembers.jsx @@ -213,10 +213,6 @@ export default routeWithUserSession({ path: "/groups/:groupId([0-9]+)", title: "Group Members", render: (currentRoute, props) => ( - + ), }); diff --git a/client/app/pages/groups/GroupsList.jsx b/client/app/pages/groups/GroupsList.jsx index d2a20f96be..cea6d513c6 100644 --- a/client/app/pages/groups/GroupsList.jsx +++ b/client/app/pages/groups/GroupsList.jsx @@ -152,10 +152,6 @@ export default routeWithUserSession({ path: "/groups", title: "Groups", render: (currentRoute, props) => ( - + ), }); diff --git a/client/app/pages/queries-list/QueriesList.jsx b/client/app/pages/queries-list/QueriesList.jsx index 32df9e3d8c..2482377084 100644 --- a/client/app/pages/queries-list/QueriesList.jsx +++ b/client/app/pages/queries-list/QueriesList.jsx @@ -167,44 +167,28 @@ export default [ path: "/queries", title: "Queries", render: (currentRoute, props) => ( - + ), }), routeWithUserSession({ path: "/queries/favorites", title: "Favorite Queries", render: (currentRoute, props) => ( - + ), }), routeWithUserSession({ path: "/queries/archive", title: "Archived Queries", render: (currentRoute, props) => ( - + ), }), routeWithUserSession({ path: "/queries/my", title: "My Queries", render: (currentRoute, props) => ( - + ), }), ]; diff --git a/client/app/pages/query-snippets/QuerySnippetsList.jsx b/client/app/pages/query-snippets/QuerySnippetsList.jsx index 2a572766d4..89fe5896f3 100644 --- a/client/app/pages/query-snippets/QuerySnippetsList.jsx +++ b/client/app/pages/query-snippets/QuerySnippetsList.jsx @@ -214,9 +214,10 @@ export default [ title: "Query Snippets", render: (currentRoute, props) => ( ), }), @@ -225,9 +226,11 @@ export default [ title: "Query Snippets", render: (currentRoute, props) => ( ), }), diff --git a/client/app/pages/users/UsersList.jsx b/client/app/pages/users/UsersList.jsx index 38e0fde3e8..798f09f0ee 100644 --- a/client/app/pages/users/UsersList.jsx +++ b/client/app/pages/users/UsersList.jsx @@ -282,9 +282,11 @@ export default [ title: "Users", render: (currentRoute, props) => ( ), }), @@ -292,33 +294,21 @@ export default [ path: "/users", title: "Users", render: (currentRoute, props) => ( - + ), }), routeWithUserSession({ path: "/users/pending", title: "Pending Invitations", render: (currentRoute, props) => ( - + ), }), routeWithUserSession({ path: "/users/disabled", title: "Disabled Users", render: (currentRoute, props) => ( - + ), }), ]; From 1a79f308b808c95d316e3dee654ea6d82c291b3b Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Thu, 23 Jan 2020 11:29:14 +0200 Subject: [PATCH 5/5] Prepare route parametes in wrapper functions --- .../routeWithApiKeySession.jsx | 9 +++++++- .../ApplicationArea/routeWithUserSession.jsx | 14 ++++++++++-- .../app/components/items-list/ItemsList.jsx | 2 +- client/app/pages/admin/Jobs.jsx | 2 +- client/app/pages/admin/OutdatedQueries.jsx | 9 +------- client/app/pages/admin/SystemStatus.jsx | 2 +- client/app/pages/alert/Alert.jsx | 6 ++--- client/app/pages/alerts/AlertsList.jsx | 6 ++--- client/app/pages/dashboards/DashboardList.jsx | 10 +++------ client/app/pages/dashboards/DashboardPage.jsx | 2 +- .../pages/dashboards/PublicDashboardPage.jsx | 4 ++-- .../pages/data-sources/DataSourcesList.jsx | 6 ++--- .../app/pages/data-sources/EditDataSource.jsx | 2 +- .../pages/destinations/DestinationsList.jsx | 6 ++--- .../pages/destinations/EditDestination.jsx | 2 +- client/app/pages/groups/GroupDataSources.jsx | 9 +------- client/app/pages/groups/GroupMembers.jsx | 4 +--- client/app/pages/groups/GroupsList.jsx | 4 +--- client/app/pages/home/Home.jsx | 2 +- client/app/pages/queries-list/QueriesList.jsx | 18 +++++---------- client/app/pages/queries/QuerySource.jsx | 4 ++-- client/app/pages/queries/QueryView.jsx | 2 +- .../app/pages/queries/VisualizationEmbed.jsx | 2 +- .../query-snippets/QuerySnippetsList.jsx | 19 ++-------------- .../pages/settings/OrganizationSettings.jsx | 2 +- client/app/pages/users/UserProfile.jsx | 4 ++-- client/app/pages/users/UsersList.jsx | 22 ++++--------------- 27 files changed, 63 insertions(+), 111 deletions(-) diff --git a/client/app/components/ApplicationArea/routeWithApiKeySession.jsx b/client/app/components/ApplicationArea/routeWithApiKeySession.jsx index 8e6843adfb..895f4fb115 100644 --- a/client/app/components/ApplicationArea/routeWithApiKeySession.jsx +++ b/client/app/components/ApplicationArea/routeWithApiKeySession.jsx @@ -3,6 +3,13 @@ import PropTypes from "prop-types"; import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { Auth } from "@/services/auth"; +// This wrapper modifies `route.render` function and instead of passing `currentRoute` passes an object +// that contains: +// - `currentRoute.routeParams` +// - `pageTitle` field which is equal to `currentRoute.title` +// - `onError` field which is a `handleError` method of nearest error boundary +// - `apiKey` field + function ApiKeySessionWrapper({ apiKey, currentRoute, renderChildren }) { const [isAuthenticated, setIsAuthenticated] = useState(false); const { handleError } = useContext(ErrorBoundaryContext); @@ -32,7 +39,7 @@ function ApiKeySessionWrapper({ apiKey, currentRoute, renderChildren }) { return ( - {renderChildren(currentRoute, { apiKey, onError: handleError })} + {renderChildren({ ...currentRoute.routeParams, pageTitle: currentRoute.title, onError: handleError, apiKey })} ); } diff --git a/client/app/components/ApplicationArea/routeWithUserSession.jsx b/client/app/components/ApplicationArea/routeWithUserSession.jsx index f3f58ee6f1..a062f6981e 100644 --- a/client/app/components/ApplicationArea/routeWithUserSession.jsx +++ b/client/app/components/ApplicationArea/routeWithUserSession.jsx @@ -6,6 +6,12 @@ import organizationStatus from "@/services/organizationStatus"; import ApplicationHeader from "./ApplicationHeader"; import ErrorMessage from "./ErrorMessage"; +// This wrapper modifies `route.render` function and instead of passing `currentRoute` passes an object +// that contains: +// - `currentRoute.routeParams` +// - `pageTitle` field which is equal to `currentRoute.title` +// - `onError` field which is a `handleError` method of nearest error boundary + function UserSessionWrapper({ bodyClass, currentRoute, renderChildren }) { const [isAuthenticated, setIsAuthenticated] = useState(!!Auth.isAuthenticated()); @@ -46,7 +52,9 @@ function UserSessionWrapper({ bodyClass, currentRoute, renderChildren }) { }> - {({ handleError }) => renderChildren(currentRoute, { onError: handleError })} + {({ handleError }) => + renderChildren({ ...currentRoute.routeParams, pageTitle: currentRoute.title, onError: handleError }) + } @@ -67,6 +75,8 @@ UserSessionWrapper.defaultProps = { export default function routeWithUserSession({ render, bodyClass, ...rest }) { return { ...rest, - render: currentRoute => , + render: currentRoute => ( + + ), }; } diff --git a/client/app/components/items-list/ItemsList.jsx b/client/app/components/items-list/ItemsList.jsx index f82fbdb169..1d2de3f00e 100644 --- a/client/app/components/items-list/ItemsList.jsx +++ b/client/app/components/items-list/ItemsList.jsx @@ -5,7 +5,7 @@ import hoistNonReactStatics from "hoist-non-react-statics"; import { clientConfig } from "@/services/auth"; export const ControllerType = PropTypes.shape({ - // values of props declared by wrapped component, current route's locals (`resolve: { ... }`) and title + // values of props declared by wrapped component and some additional props from items list params: PropTypes.object.isRequired, isLoaded: PropTypes.bool.isRequired, diff --git a/client/app/pages/admin/Jobs.jsx b/client/app/pages/admin/Jobs.jsx index dcf1ece74f..da7b86ddde 100644 --- a/client/app/pages/admin/Jobs.jsx +++ b/client/app/pages/admin/Jobs.jsx @@ -123,5 +123,5 @@ class Jobs extends React.Component { export default routeWithUserSession({ path: "/admin/queries/jobs", title: "RQ Status", - render: (currentRoute, props) => , + render: pageProps => , }); diff --git a/client/app/pages/admin/OutdatedQueries.jsx b/client/app/pages/admin/OutdatedQueries.jsx index 0d60e3fc54..a41afc16d7 100644 --- a/client/app/pages/admin/OutdatedQueries.jsx +++ b/client/app/pages/admin/OutdatedQueries.jsx @@ -172,12 +172,5 @@ const OutdatedQueriesPage = itemsList( export default routeWithUserSession({ path: "/admin/queries/outdated", title: "Outdated Queries", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }); diff --git a/client/app/pages/admin/SystemStatus.jsx b/client/app/pages/admin/SystemStatus.jsx index dafa7e6f1c..9d659738f4 100644 --- a/client/app/pages/admin/SystemStatus.jsx +++ b/client/app/pages/admin/SystemStatus.jsx @@ -83,5 +83,5 @@ class SystemStatus extends React.Component { export default routeWithUserSession({ path: "/admin/status", title: "System Status", - render: (currentRoute, props) => , + render: pageProps => , }); diff --git a/client/app/pages/alert/Alert.jsx b/client/app/pages/alert/Alert.jsx index 1a2af44167..be147858dc 100644 --- a/client/app/pages/alert/Alert.jsx +++ b/client/app/pages/alert/Alert.jsx @@ -255,16 +255,16 @@ export default [ routeWithUserSession({ path: "/alerts/new", title: "New Alert", - render: (currentRoute, props) => , + render: pageProps => , }), routeWithUserSession({ path: "/alerts/:alertId([0-9]+)", title: "Alert", - render: (currentRoute, props) => , + render: pageProps => , }), routeWithUserSession({ path: "/alerts/:alertId([0-9]+)/edit", title: "Alert", - render: (currentRoute, props) => , + render: pageProps => , }), ]; diff --git a/client/app/pages/alerts/AlertsList.jsx b/client/app/pages/alerts/AlertsList.jsx index 0289275d56..2b67728f78 100644 --- a/client/app/pages/alerts/AlertsList.jsx +++ b/client/app/pages/alerts/AlertsList.jsx @@ -69,7 +69,7 @@ class AlertsList extends React.Component { return (
- +
{!controller.isLoaded && } {controller.isLoaded && controller.isEmpty && ( @@ -123,7 +123,5 @@ const AlertsListPage = itemsList( export default routeWithUserSession({ path: "/alerts", title: "Alerts", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }); diff --git a/client/app/pages/dashboards/DashboardList.jsx b/client/app/pages/dashboards/DashboardList.jsx index 786c59c8e2..808f51d1fd 100644 --- a/client/app/pages/dashboards/DashboardList.jsx +++ b/client/app/pages/dashboards/DashboardList.jsx @@ -75,7 +75,7 @@ class DashboardList extends React.Component { return (
- + ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/dashboards/favorites", title: "Favorite Dashboards", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), ]; diff --git a/client/app/pages/dashboards/DashboardPage.jsx b/client/app/pages/dashboards/DashboardPage.jsx index d9c281f25e..885abf29c2 100644 --- a/client/app/pages/dashboards/DashboardPage.jsx +++ b/client/app/pages/dashboards/DashboardPage.jsx @@ -408,5 +408,5 @@ DashboardPage.defaultProps = { export default routeWithUserSession({ path: "/dashboard/:dashboardSlug", - render: (currentRoute, props) => , + render: pageProps => , }); diff --git a/client/app/pages/dashboards/PublicDashboardPage.jsx b/client/app/pages/dashboards/PublicDashboardPage.jsx index 84f77e35c3..562a852f6b 100644 --- a/client/app/pages/dashboards/PublicDashboardPage.jsx +++ b/client/app/pages/dashboards/PublicDashboardPage.jsx @@ -97,6 +97,6 @@ class PublicDashboardPage extends React.Component { export default routeWithApiKeySession({ path: "/public/dashboards/:token", - render: (currentRoute, props) => , - getApiKey: curentRoute => curentRoute.routeParams.token, + render: pageProps => , + getApiKey: currentRoute => currentRoute.routeParams.token, }); diff --git a/client/app/pages/data-sources/DataSourcesList.jsx b/client/app/pages/data-sources/DataSourcesList.jsx index 98d5eb7b74..0512285511 100644 --- a/client/app/pages/data-sources/DataSourcesList.jsx +++ b/client/app/pages/data-sources/DataSourcesList.jsx @@ -158,13 +158,11 @@ export default [ routeWithUserSession({ path: "/data_sources", title: "Data Sources", - render: (currentRoute, props) => , + render: pageProps => , }), routeWithUserSession({ path: "/data_sources/new", title: "Data Sources", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), ]; diff --git a/client/app/pages/data-sources/EditDataSource.jsx b/client/app/pages/data-sources/EditDataSource.jsx index c1afa2b4d9..f04ea18183 100644 --- a/client/app/pages/data-sources/EditDataSource.jsx +++ b/client/app/pages/data-sources/EditDataSource.jsx @@ -141,5 +141,5 @@ const EditDataSourcePage = wrapSettingsTab(null, EditDataSource); export default routeWithUserSession({ path: "/data_sources/:dataSourceId([0-9]+)", title: "Data Sources", - render: (currentRoute, props) => , + render: pageProps => , }); diff --git a/client/app/pages/destinations/DestinationsList.jsx b/client/app/pages/destinations/DestinationsList.jsx index 494291747e..e807df188a 100644 --- a/client/app/pages/destinations/DestinationsList.jsx +++ b/client/app/pages/destinations/DestinationsList.jsx @@ -146,13 +146,11 @@ export default [ routeWithUserSession({ path: "/destinations", title: "Alert Destinations", - render: (currentRoute, props) => , + render: pageProps => , }), routeWithUserSession({ path: "/destinations/new", title: "Alert Destinations", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), ]; diff --git a/client/app/pages/destinations/EditDestination.jsx b/client/app/pages/destinations/EditDestination.jsx index 4c149f307b..3d11df6a49 100644 --- a/client/app/pages/destinations/EditDestination.jsx +++ b/client/app/pages/destinations/EditDestination.jsx @@ -108,5 +108,5 @@ const EditDestinationPage = wrapSettingsTab(null, EditDestination); export default routeWithUserSession({ path: "/destinations/:destinationId([0-9]+)", title: "Alert Destinations", - render: (currentRoute, props) => , + render: pageProps => , }); diff --git a/client/app/pages/groups/GroupDataSources.jsx b/client/app/pages/groups/GroupDataSources.jsx index 2722bd802d..9cc409b3e9 100644 --- a/client/app/pages/groups/GroupDataSources.jsx +++ b/client/app/pages/groups/GroupDataSources.jsx @@ -249,12 +249,5 @@ const GroupDataSourcesPage = wrapSettingsTab( export default routeWithUserSession({ path: "/groups/:groupId([0-9]+)/data_sources", title: "Group Data Sources", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }); diff --git a/client/app/pages/groups/GroupMembers.jsx b/client/app/pages/groups/GroupMembers.jsx index cb2610b1e1..1548db0b0d 100644 --- a/client/app/pages/groups/GroupMembers.jsx +++ b/client/app/pages/groups/GroupMembers.jsx @@ -212,7 +212,5 @@ const GroupMembersPage = wrapSettingsTab( export default routeWithUserSession({ path: "/groups/:groupId([0-9]+)", title: "Group Members", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }); diff --git a/client/app/pages/groups/GroupsList.jsx b/client/app/pages/groups/GroupsList.jsx index cea6d513c6..e3d43fe63a 100644 --- a/client/app/pages/groups/GroupsList.jsx +++ b/client/app/pages/groups/GroupsList.jsx @@ -151,7 +151,5 @@ const GroupsListPage = wrapSettingsTab( export default routeWithUserSession({ path: "/groups", title: "Groups", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }); diff --git a/client/app/pages/home/Home.jsx b/client/app/pages/home/Home.jsx index aa7972c568..641d0b6d17 100644 --- a/client/app/pages/home/Home.jsx +++ b/client/app/pages/home/Home.jsx @@ -176,5 +176,5 @@ function Home() { export default routeWithUserSession({ path: "/", title: "Redash", - render: (currentRoute, props) => , + render: pageProps => , }); diff --git a/client/app/pages/queries-list/QueriesList.jsx b/client/app/pages/queries-list/QueriesList.jsx index 2482377084..f528be1ffd 100644 --- a/client/app/pages/queries-list/QueriesList.jsx +++ b/client/app/pages/queries-list/QueriesList.jsx @@ -92,7 +92,7 @@ class QueriesList extends React.Component { return (
- + ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/queries/favorites", title: "Favorite Queries", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/queries/archive", title: "Archived Queries", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/queries/my", title: "My Queries", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), ]; diff --git a/client/app/pages/queries/QuerySource.jsx b/client/app/pages/queries/QuerySource.jsx index 9d53e668d6..f109148a27 100644 --- a/client/app/pages/queries/QuerySource.jsx +++ b/client/app/pages/queries/QuerySource.jsx @@ -446,7 +446,7 @@ QuerySource.propTypes = { export default [ routeWithUserSession({ path: "/queries/new", - render: (currentRoute, props) => , + render: pageProps => , resolve: { query: () => Query.newQuery(), }, @@ -454,7 +454,7 @@ export default [ }), routeWithUserSession({ path: "/queries/:queryId([0-9]+)/source", - render: (currentRoute, props) => , + render: pageProps => , resolve: { query: ({ queryId }) => Query.get({ id: queryId }), }, diff --git a/client/app/pages/queries/QueryView.jsx b/client/app/pages/queries/QueryView.jsx index 1bead2cd4a..db6ea15a39 100644 --- a/client/app/pages/queries/QueryView.jsx +++ b/client/app/pages/queries/QueryView.jsx @@ -186,7 +186,7 @@ QueryView.propTypes = { query: PropTypes.object.isRequired }; // eslint-disable- export default routeWithUserSession({ path: "/queries/:queryId([0-9]+)", - render: (currentRoute, props) => , + render: pageProps => , resolve: { query: ({ queryId }) => Query.get({ id: queryId }), }, diff --git a/client/app/pages/queries/VisualizationEmbed.jsx b/client/app/pages/queries/VisualizationEmbed.jsx index 44488148dc..6589a9b39d 100644 --- a/client/app/pages/queries/VisualizationEmbed.jsx +++ b/client/app/pages/queries/VisualizationEmbed.jsx @@ -266,6 +266,6 @@ VisualizationEmbed.defaultProps = { export default routeWithApiKeySession({ path: "/embed/query/:queryId/visualization/:visualizationId", - render: (currentRoute, props) => , + render: pageProps => , getApiKey: () => location.search.api_key, }); diff --git a/client/app/pages/query-snippets/QuerySnippetsList.jsx b/client/app/pages/query-snippets/QuerySnippetsList.jsx index 89fe5896f3..ee3b4920fb 100644 --- a/client/app/pages/query-snippets/QuerySnippetsList.jsx +++ b/client/app/pages/query-snippets/QuerySnippetsList.jsx @@ -212,26 +212,11 @@ export default [ routeWithUserSession({ path: "/query_snippets", title: "Query Snippets", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/query_snippets/:querySnippetId(new|[0-9]+)", title: "Query Snippets", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), ]; diff --git a/client/app/pages/settings/OrganizationSettings.jsx b/client/app/pages/settings/OrganizationSettings.jsx index 7c9039adbc..d5758fbc30 100644 --- a/client/app/pages/settings/OrganizationSettings.jsx +++ b/client/app/pages/settings/OrganizationSettings.jsx @@ -283,5 +283,5 @@ const OrganizationSettingsPage = wrapSettingsTab( export default routeWithUserSession({ path: "/settings/organization", title: "Organization Settings", - render: (currentRoute, props) => , + render: pageProps => , }); diff --git a/client/app/pages/users/UserProfile.jsx b/client/app/pages/users/UserProfile.jsx index abbaa4fa18..d1a7554557 100644 --- a/client/app/pages/users/UserProfile.jsx +++ b/client/app/pages/users/UserProfile.jsx @@ -60,11 +60,11 @@ export default [ routeWithUserSession({ path: "/users/me", title: "Account", - render: (currentRoute, props) => , + render: pageProps => , }), routeWithUserSession({ path: "/users/:userId([0-9]+)", title: "Users", - render: (currentRoute, props) => , + render: pageProps => , }), ]; diff --git a/client/app/pages/users/UsersList.jsx b/client/app/pages/users/UsersList.jsx index 798f09f0ee..a5f3e54f2f 100644 --- a/client/app/pages/users/UsersList.jsx +++ b/client/app/pages/users/UsersList.jsx @@ -280,35 +280,21 @@ export default [ routeWithUserSession({ path: "/users/new", title: "Users", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/users", title: "Users", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/users/pending", title: "Pending Invitations", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), routeWithUserSession({ path: "/users/disabled", title: "Disabled Users", - render: (currentRoute, props) => ( - - ), + render: pageProps => , }), ];