From 7d64b47e9e059ade82f0cb211c6706578156c643 Mon Sep 17 00:00:00 2001 From: Damian Stasik Date: Sun, 5 Dec 2021 22:33:28 +0100 Subject: [PATCH 01/13] refactor: use new React context API --- src/components/Filter/Filter.react.js | 22 +++++++++---------- src/components/Popover/Popover.react.js | 2 -- .../PushAudienceDialog.react.js | 11 ++++------ .../PushPreview/PushPreview.react.js | 8 +++---- src/context/currentApp.js | 1 + src/dashboard/AppData.react.js | 22 +++++++++---------- src/dashboard/Settings/AppleCerts.react.js | 20 +++++++---------- src/dashboard/Settings/Collaborators.react.js | 9 +++----- src/dashboard/Settings/SettingsData.react.js | 16 +++++--------- 9 files changed, 46 insertions(+), 65 deletions(-) create mode 100644 src/context/currentApp.js diff --git a/src/components/Filter/Filter.react.js b/src/components/Filter/Filter.react.js index f6c5c60ff1..baad7c8e44 100644 --- a/src/components/Filter/Filter.react.js +++ b/src/components/Filter/Filter.react.js @@ -5,12 +5,13 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import * as Filters from 'lib/Filters'; -import { List, Map } from 'immutable'; -import PropTypes from 'lib/PropTypes'; -import React from 'react'; -import stringCompare from 'lib/stringCompare'; -import ParseApp from 'lib/ParseApp'; +import * as Filters from 'lib/Filters'; +import { List, Map } from 'immutable'; +import PropTypes from 'lib/PropTypes'; +import React from 'react'; +import stringCompare from 'lib/stringCompare'; +import ParseApp from 'lib/ParseApp'; +import { CurrentApp } from 'context/CurrentApp'; function changeField(schema, filters, index, newField) { let newFilter = new Map({ @@ -44,7 +45,8 @@ function deleteRow(filters, index) { return filters.delete(index); } -let Filter = ({ schema, filters, renderRow, onChange, blacklist, className }, context) => { +let Filter = ({ schema, filters, renderRow, onChange, blacklist, className }) => { + const currentApp = React.useContext(CurrentApp); blacklist = blacklist || []; let available = Filters.availableFilters(schema, filters); return ( @@ -60,7 +62,7 @@ let Filter = ({ schema, filters, renderRow, onChange, blacklist, className }, co } // Get the column preference of the current class. - const currentColumnPreference = context.currentApp.columnPreference[className]; + const currentColumnPreference = currentApp.columnPreference[className]; // Check if the preference exists. if (currentColumnPreference) { @@ -137,7 +139,3 @@ Filter.propTypes = { 'A function for rendering a row of a filter.' ) }; - -Filter.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/components/Popover/Popover.react.js b/src/components/Popover/Popover.react.js index 3a23f91732..30fef24eb3 100644 --- a/src/components/Popover/Popover.react.js +++ b/src/components/Popover/Popover.react.js @@ -9,7 +9,6 @@ import PropTypes from 'lib/PropTypes'; import hasAncestor from 'lib/hasAncestor'; import React from 'react'; import styles from 'components/Popover/Popover.scss'; -import ParseApp from 'lib/ParseApp'; import { createPortal } from 'react-dom'; // We use this component to proxy the current tree's context @@ -98,5 +97,4 @@ export default class Popover extends React.Component { Popover.contextTypes = { history: PropTypes.object, router: PropTypes.object, - currentApp: PropTypes.instanceOf(ParseApp) }; diff --git a/src/components/PushAudienceDialog/PushAudienceDialog.react.js b/src/components/PushAudienceDialog/PushAudienceDialog.react.js index 8fb0355dbd..4e40b76bd3 100644 --- a/src/components/PushAudienceDialog/PushAudienceDialog.react.js +++ b/src/components/PushAudienceDialog/PushAudienceDialog.react.js @@ -17,7 +17,6 @@ import Label from 'components/Label/Label.react'; import Modal from 'components/Modal/Modal.react'; import MultiSelect from 'components/MultiSelect/MultiSelect.react'; import MultiSelectOption from 'components/MultiSelect/MultiSelectOption.react'; -import ParseApp from 'lib/ParseApp'; import PropTypes from 'lib/PropTypes'; import queryFromFilters from 'lib/queryFromFilters'; import React from 'react'; @@ -25,6 +24,7 @@ import styles from 'components/PushAudienceDialog/PushAudienceDia import TextInput from 'components/TextInput/TextInput.react'; import Toggle from 'components/Toggle/Toggle.react'; import { List, Map } from 'immutable'; +import { CurrentApp } from 'context/currentApp'; const PARSE_SERVER_SUPPORTS_SAVED_AUDIENCES = true; const AUDIENCE_SIZE_FETCHING_ENABLED = true; @@ -44,6 +44,7 @@ let filterFormatter = (filters, schema) => { } export default class PushAudienceDialog extends React.Component { + static contextType = CurrentApp; constructor() { super(); this.xhrHandle = null; @@ -113,7 +114,7 @@ export default class PushAudienceDialog extends React.Component { } fetchAudienceSize() { - if (!this.context || !this.context.currentApp) { //so we don't break the PIG demo + if (!this.context) { //so we don't break the PIG demo return; } @@ -124,7 +125,7 @@ export default class PushAudienceDialog extends React.Component { query = parseQuery.toJSON().where || {}; } query.deviceType = { $in: this.state.platforms }; - let {xhr, promise} = this.context.currentApp.fetchPushSubscriberCount(PushConstants.NEW_SEGMENT_ID, query); + let {xhr, promise} = this.context.fetchPushSubscriberCount(PushConstants.NEW_SEGMENT_ID, query); if (this.xhrHandle) { //cancel existing xhr - prevent from stacking this.xhrHandle.abort(); } @@ -272,10 +273,6 @@ export default class PushAudienceDialog extends React.Component { } } -PushAudienceDialog.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; - PushAudienceDialog.propTypes = { editMode: PropTypes.bool.describe( 'Flag if true to be edit mode of dialog.' diff --git a/src/components/PushPreview/PushPreview.react.js b/src/components/PushPreview/PushPreview.react.js index 99e67c3e5d..e654136278 100644 --- a/src/components/PushPreview/PushPreview.react.js +++ b/src/components/PushPreview/PushPreview.react.js @@ -11,6 +11,7 @@ import React from 'react'; import SegmentSelect from 'components/SegmentSelect/SegmentSelect.react'; import styles from 'components/PushPreview/PushPreview.scss'; import VisiblePreview from 'components/PushPreview/VisiblePreview.react'; +import { CurrentApp } from 'context/currentApp'; import { getDateMethod, MONTHS, @@ -37,6 +38,7 @@ let timeString = (time, isLocal) => { } export default class PushPreview extends React.Component { + static contextType = CurrentApp; constructor(props) { super(props); @@ -134,7 +136,7 @@ export default class PushPreview extends React.Component { type={this.state.currentPreview.toLowerCase().replace(/\s/, '')} message={previewMessage} time={previewTime || new Date()} - appName={this.context.currentApp.name} + appName={this.context.name} fade={isExperiment} /> ); if (!isExperiment && pushState.data_type === 'json') { @@ -177,7 +179,3 @@ export default class PushPreview extends React.Component { ); } } - -PushPreview.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/context/currentApp.js b/src/context/currentApp.js new file mode 100644 index 0000000000..6ccbd43fa2 --- /dev/null +++ b/src/context/currentApp.js @@ -0,0 +1 @@ +export const CurrentApp = React.createContext(null); \ No newline at end of file diff --git a/src/dashboard/AppData.react.js b/src/dashboard/AppData.react.js index bd44686c86..283c5d3146 100644 --- a/src/dashboard/AppData.react.js +++ b/src/dashboard/AppData.react.js @@ -5,12 +5,12 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import React from 'react'; -import PropTypes from 'lib/PropTypes'; -import AppSelector from 'dashboard/AppSelector.react'; -import AppsManager from 'lib/AppsManager'; -import history from 'dashboard/history'; -import ParseApp from 'lib/ParseApp'; +import React from 'react'; +import PropTypes from 'lib/PropTypes'; +import AppSelector from 'dashboard/AppSelector.react'; +import AppsManager from 'lib/AppsManager'; +import history from 'dashboard/history'; +import { CurrentApp } from 'context/CurrentApp'; class AppData extends React.Component { constructor(props) { @@ -21,7 +21,6 @@ class AppData extends React.Component { getChildContext() { return { generatePath: this.generatePath, - currentApp: AppsManager.findAppBySlugOrName(this.props.params.appId) }; } @@ -42,16 +41,17 @@ class AppData extends React.Component { return
; } return ( -
- {this.props.children} -
+ +
+ {this.props.children} +
+
); } } AppData.childContextTypes = { generatePath: PropTypes.func, - currentApp: PropTypes.instanceOf(ParseApp) }; export default AppData; diff --git a/src/dashboard/Settings/AppleCerts.react.js b/src/dashboard/Settings/AppleCerts.react.js index e30adac87a..1de385a640 100644 --- a/src/dashboard/Settings/AppleCerts.react.js +++ b/src/dashboard/Settings/AppleCerts.react.js @@ -5,13 +5,13 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import PropTypes from 'lib/PropTypes'; -import Modal from 'components/Modal/Modal.react'; -import ParseApp from 'lib/ParseApp'; -import PushCerts from 'components/PushCerts/PushCerts.react'; -import React from 'react'; +import Modal from 'components/Modal/Modal.react'; +import PushCerts from 'components/PushCerts/PushCerts.react'; +import React from 'react'; +import { CurrentApp } from 'context/currentApp'; export default class AppleCerts extends React.Component { + static contextType = CurrentApp; constructor() { super(); @@ -24,7 +24,7 @@ export default class AppleCerts extends React.Component { componentDidMount() { this.mounted = true; - this.context.currentApp.getAppleCerts().then((certs) => { + this.context.getAppleCerts().then((certs) => { if (this.mounted) { this.setState({ certs }); } @@ -36,7 +36,7 @@ export default class AppleCerts extends React.Component { } handleUpload(file) { - this.context.currentApp.uploadAppleCert(file).then((cert) => { + this.context.uploadAppleCert(file).then((cert) => { this.state.certs.unshift(cert); this.setState({ uploadPending: false }); }, (err) => { @@ -68,7 +68,7 @@ export default class AppleCerts extends React.Component { onCancel={() => this.setState({ deletePending: null })} onConfirm={() => { let id = this.state.deletePending; - this.context.currentApp.deleteAppleCert(id).then(() => { + this.context.deleteAppleCert(id).then(() => { for (let i = 0; i < this.state.certs.length; i++) { if (this.state.certs[i].id === id) { this.state.certs.splice(i, 1); @@ -83,7 +83,3 @@ export default class AppleCerts extends React.Component { ); } } - -AppleCerts.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/dashboard/Settings/Collaborators.react.js b/src/dashboard/Settings/Collaborators.react.js index 3caca00ed9..486038c7ff 100644 --- a/src/dashboard/Settings/Collaborators.react.js +++ b/src/dashboard/Settings/Collaborators.react.js @@ -12,11 +12,11 @@ import FormTable from 'components/FormTable/FormTable.react'; import FormNote from 'components/FormNote/FormNote.react'; import InlineSubmitInput from 'components/InlineSubmitInput/InlineSubmitInput.react'; import Label from 'components/Label/Label.react'; -import ParseApp from 'lib/ParseApp'; import PropTypes from 'lib/PropTypes'; import React from 'react'; import TextInput from 'components/TextInput/TextInput.react'; import validateEmailFormat from 'lib/validateEmailFormat'; +import { CurrentApp } from 'context/currentApp'; // Component for displaying and modifying an app's collaborator emails. // There is a single input field for new collaborator emails. As soon as the @@ -29,6 +29,7 @@ import validateEmailFormat from 'lib/validateEmailFormat'; // The parent also is responsible for passing onRemove, which is called when the // users removes a collaborator. export default class Collaborators extends React.Component { + static contextType = CurrentApp; constructor() { super(); @@ -38,7 +39,7 @@ export default class Collaborators extends React.Component { handleAdd(newEmail) { //TODO: Show some in-progress thing while the collaborator is being validated, or maybe have some sort of //async validator in the parent form. Currently if you mash the add button, they same collaborator gets added many times. - return this.context.currentApp.validateCollaborator(newEmail).then((response) => { + return this.context.validateCollaborator(newEmail).then((response) => { // lastError logic assumes we only have 1 input field if (response.success) { let newCollaborators = this.props.collaborators.concat({ userEmail: newEmail }) @@ -123,10 +124,6 @@ export default class Collaborators extends React.Component { } } -Collaborators.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; - Collaborators.propTypes = { legend: PropTypes.string.isRequired.describe( 'Title of this section' diff --git a/src/dashboard/Settings/SettingsData.react.js b/src/dashboard/Settings/SettingsData.react.js index 54ff99e297..4b2a37e931 100644 --- a/src/dashboard/Settings/SettingsData.react.js +++ b/src/dashboard/Settings/SettingsData.react.js @@ -5,11 +5,11 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import PropTypes from 'lib/PropTypes'; -import ParseApp from 'lib/ParseApp'; -import React from 'react'; +import React from 'react'; +import { CurrentApp } from 'context/currentApp'; export default class SettingsData extends React.Component { + static contextType = CurrentApp; constructor() { super(); @@ -19,7 +19,7 @@ export default class SettingsData extends React.Component { } componentDidMount() { - this.context.currentApp.fetchSettingsFields().then(({ fields }) => { + this.context.fetchSettingsFields().then(({ fields }) => { this.setState({ fields }); }); } @@ -27,14 +27,14 @@ export default class SettingsData extends React.Component { componentWillReceiveProps(props, context) { if (this.context !== context) { this.setState({ fields: undefined }); - context.currentApp.fetchSettingsFields().then(({ fields }) => { + context.fetchSettingsFields().then(({ fields }) => { this.setState({ fields }); }); } } saveChanges(changes) { - let promise = this.context.currentApp.saveSettingsFields(changes) + let promise = this.context.saveSettingsFields(changes) promise.then(({successes}) => { let newFields = {...this.state.fields, ...successes}; this.setState({fields: newFields}); @@ -54,7 +54,3 @@ export default class SettingsData extends React.Component { ); } } - -SettingsData.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; From 86e6556be4394c93061a3455fabef998f4272dd2 Mon Sep 17 00:00:00 2001 From: Damian Stasik Date: Sun, 5 Dec 2021 22:49:41 +0100 Subject: [PATCH 02/13] another chunk of code refactored --- .../PushAudiencesBaseRow.react.js | 12 ++--- src/components/Sidebar/Sidebar.react.js | 12 ++--- src/dashboard/DashboardView.react.js | 26 +++++----- .../Data/ApiConsole/GraphQLConsole.react.js | 10 ++-- .../Data/ApiConsole/RestConsole.react.js | 48 +++++++++---------- .../Data/Browser/BrowserTable.react.js | 11 ++--- .../Data/Browser/DataBrowser.react.js | 34 ++++++------- .../Data/Browser/EditRowDialog.react.js | 6 --- .../Data/Browser/ExportDialog.react.js | 14 ++---- .../Data/Browser/LoginDialog.react.js | 6 --- .../Data/Browser/ObjectPickerDialog.react.js | 10 ++-- .../Data/Browser/SecureFieldsDialog.react.js | 10 ++-- .../Data/Browser/SecurityDialog.react.js | 10 ++-- src/dashboard/Data/Jobs/JobEdit.react.js | 2 - src/dashboard/Data/Jobs/JobsData.react.js | 18 +++---- src/dashboard/Data/Jobs/RunNowButton.react.js | 14 ++---- .../Data/Playground/Playground.react.js | 6 +-- src/dashboard/Push/PushAudiencesData.react.js | 12 ++--- 18 files changed, 98 insertions(+), 163 deletions(-) diff --git a/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js b/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js index f643b9c5b0..5b00f94080 100644 --- a/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js +++ b/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js @@ -5,12 +5,12 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import PropTypes from 'lib/PropTypes'; -import ParseApp from 'lib/ParseApp'; import React from 'react'; import { NEW_SEGMENT_ID } from 'dashboard/Push/PushConstants'; +import { CurrentApp } from 'context/currentApp'; export default class PushAudiencesBaseRow extends React.Component { + static contextType = CurrentApp; constructor() { super(); this.xhrHandle = null; @@ -31,12 +31,12 @@ export default class PushAudiencesBaseRow extends React.Component { } fetchPushSubscriberCount(context) { - if (!context || !context.currentApp) { //so we don't break the PIG demo + if (!context) { //so we don't break the PIG demo return; } let query = this.props.id === NEW_SEGMENT_ID ? this.props.query : null; //Added count fetch logic directly to component - let {xhr, promise} = context.currentApp.fetchPushSubscriberCount(this.props.id, query); + let {xhr, promise} = context.fetchPushSubscriberCount(this.props.id, query); this.xhrHandle = xhr; promise.then(({ approximate, count }) => { this.setState({ approximate, count }); @@ -62,7 +62,3 @@ export default class PushAudiencesBaseRow extends React.Component { } } } - -PushAudiencesBaseRow.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/components/Sidebar/Sidebar.react.js b/src/components/Sidebar/Sidebar.react.js index c0dd363512..c3c2c6c806 100644 --- a/src/components/Sidebar/Sidebar.react.js +++ b/src/components/Sidebar/Sidebar.react.js @@ -5,19 +5,18 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import PropTypes from 'lib/PropTypes'; import AppsManager from 'lib/AppsManager'; import AppsMenu from 'components/Sidebar/AppsMenu.react'; import AppName from 'components/Sidebar/AppName.react'; import FooterMenu from 'components/Sidebar/FooterMenu.react'; import isInsidePopover from 'lib/isInsidePopover'; -import ParseApp from 'lib/ParseApp'; import Pin from 'components/Sidebar/Pin.react'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useContext } from 'react'; import SidebarHeader from 'components/Sidebar/SidebarHeader.react'; import SidebarSection from 'components/Sidebar/SidebarSection.react'; import SidebarSubItem from 'components/Sidebar/SidebarSubItem.react'; import styles from 'components/Sidebar/Sidebar.scss'; +import { CurrentApp } from 'context/currentApp'; const Sidebar = ({ prefix, @@ -30,7 +29,8 @@ const Sidebar = ({ appSelector, primaryBackgroundColor, secondaryBackgroundColor -}, { currentApp }) => { +}) => { + const currentApp = useContext(CurrentApp); const collapseWidth = 980; const [ appsMenuOpen, setAppsMenuOpen ] = useState(false); const [ collapsed, setCollapsed ] = useState(false); @@ -192,8 +192,4 @@ const Sidebar = ({ ); } -Sidebar.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; - export default Sidebar; diff --git a/src/dashboard/DashboardView.react.js b/src/dashboard/DashboardView.react.js index c1d53a6e0e..c947872ccc 100644 --- a/src/dashboard/DashboardView.react.js +++ b/src/dashboard/DashboardView.react.js @@ -5,13 +5,14 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import PropTypes from 'lib/PropTypes'; -import ParseApp from 'lib/ParseApp'; -import React from 'react'; -import Sidebar from 'components/Sidebar/Sidebar.react'; -import styles from 'dashboard/Dashboard.scss'; +import PropTypes from 'lib/PropTypes'; +import React from 'react'; +import Sidebar from 'components/Sidebar/Sidebar.react'; +import styles from 'dashboard/Dashboard.scss'; +import { CurrentApp } from 'context/currentApp'; export default class DashboardView extends React.Component { + static contextType = CurrentApp; /* A DashboardView renders two pieces: the sidebar, and the app itself */ render() { @@ -19,14 +20,14 @@ export default class DashboardView extends React.Component { if (typeof this.renderSidebar === 'function') { sidebarChildren = this.renderSidebar(); } - let appSlug = (this.context.currentApp ? this.context.currentApp.slug : ''); + let appSlug = (this.context ? this.context.slug : ''); - if (!this.context.currentApp.hasCheckedForMigraton) { - this.context.currentApp.getMigrations().promise + if (!this.context.hasCheckedForMigraton) { + this.context.getMigrations().promise .then(() => this.forceUpdate(), () => {}); } - let features = this.context.currentApp.serverInfo.features; + let features = this.context.serverInfo.features; let coreSubsections = []; if (features.schemas && @@ -85,7 +86,7 @@ export default class DashboardView extends React.Component { link: '/api_console' }); - if (this.context.currentApp.migration) { + if (this.context.migration) { coreSubsections.push({ name: 'Migration', link: '/migration', @@ -242,8 +243,8 @@ export default class DashboardView extends React.Component { subsection={this.subsection} prefix={'/apps/' + appSlug} action={this.action} - primaryBackgroundColor={this.context.currentApp.primaryBackgroundColor} - secondaryBackgroundColor={this.context.currentApp.secondaryBackgroundColor} + primaryBackgroundColor={this.context.primaryBackgroundColor} + secondaryBackgroundColor={this.context.secondaryBackgroundColor} > {sidebarChildren} ); @@ -261,5 +262,4 @@ export default class DashboardView extends React.Component { DashboardView.contextTypes = { generatePath: PropTypes.func, - currentApp: PropTypes.instanceOf(ParseApp) }; diff --git a/src/dashboard/Data/ApiConsole/GraphQLConsole.react.js b/src/dashboard/Data/ApiConsole/GraphQLConsole.react.js index 10cf3ae2ee..6a5a007193 100644 --- a/src/dashboard/Data/ApiConsole/GraphQLConsole.react.js +++ b/src/dashboard/Data/ApiConsole/GraphQLConsole.react.js @@ -5,17 +5,17 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import ParseApp from 'lib/ParseApp'; -import PropTypes from 'lib/PropTypes'; import React, { Component } from 'react'; import GraphiQL from 'graphiql'; import EmptyState from 'components/EmptyState/EmptyState.react'; import Toolbar from 'components/Toolbar/Toolbar.react'; import styles from 'dashboard/Data/ApiConsole/ApiConsole.scss'; +import { CurrentApp } from 'context/currentApp'; export default class GraphQLConsole extends Component { + static contextType = CurrentApp; render() { - const { applicationId, clientKey, graphQLServerURL, masterKey } = this.context.currentApp; + const { applicationId, clientKey, graphQLServerURL, masterKey } = this.context; let content; if (!graphQLServerURL) { content = ( @@ -69,7 +69,3 @@ export default class GraphQLConsole extends Component { ); } } - -GraphQLConsole.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/dashboard/Data/ApiConsole/RestConsole.react.js b/src/dashboard/Data/ApiConsole/RestConsole.react.js index 23afd3abfc..20bb20019e 100644 --- a/src/dashboard/Data/ApiConsole/RestConsole.react.js +++ b/src/dashboard/Data/ApiConsole/RestConsole.react.js @@ -5,29 +5,29 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import Button from 'components/Button/Button.react'; -import Dropdown from 'components/Dropdown/Dropdown.react'; -import Field from 'components/Field/Field.react'; -import Fieldset from 'components/Fieldset/Fieldset.react'; -import fieldStyle from 'components/Field/Field.scss'; -import FlowFooter from 'components/FlowFooter/FlowFooter.react'; -import FormNote from 'components/FormNote/FormNote.react'; -import generateCurl from 'dashboard/Data/ApiConsole/generateCurl'; -import JsonPrinter from 'components/JsonPrinter/JsonPrinter.react'; -import Label from 'components/Label/Label.react'; -import Modal from 'components/Modal/Modal.react'; -import Option from 'components/Dropdown/Option.react'; -import Parse from 'parse'; -import ParseApp from 'lib/ParseApp'; -import PropTypes from 'lib/PropTypes'; +import Button from 'components/Button/Button.react'; +import Dropdown from 'components/Dropdown/Dropdown.react'; +import Field from 'components/Field/Field.react'; +import Fieldset from 'components/Fieldset/Fieldset.react'; +import fieldStyle from 'components/Field/Field.scss'; +import FlowFooter from 'components/FlowFooter/FlowFooter.react'; +import FormNote from 'components/FormNote/FormNote.react'; +import generateCurl from 'dashboard/Data/ApiConsole/generateCurl'; +import JsonPrinter from 'components/JsonPrinter/JsonPrinter.react'; +import Label from 'components/Label/Label.react'; +import Modal from 'components/Modal/Modal.react'; +import Option from 'components/Dropdown/Option.react'; +import Parse from 'parse'; import React, { Component } from 'react'; -import request from 'dashboard/Data/ApiConsole/request'; -import styles from 'dashboard/Data/ApiConsole/ApiConsole.scss'; -import TextInput from 'components/TextInput/TextInput.react'; -import Toggle from 'components/Toggle/Toggle.react'; -import Toolbar from 'components/Toolbar/Toolbar.react'; +import request from 'dashboard/Data/ApiConsole/request'; +import styles from 'dashboard/Data/ApiConsole/ApiConsole.scss'; +import TextInput from 'components/TextInput/TextInput.react'; +import Toggle from 'components/Toggle/Toggle.react'; +import Toolbar from 'components/Toolbar/Toolbar.react'; +import { CurrentApp } from 'context/currentApp'; export default class RestConsole extends Component { + static contextType = CurrentApp; constructor() { super() @@ -90,7 +90,7 @@ export default class RestConsole extends Component { options.sessionToken = this.state.sessionToken; } request( - this.context.currentApp, + this.context, this.state.method, endpoint, payload, @@ -133,7 +133,7 @@ export default class RestConsole extends Component { options.sessionToken = this.state.sessionToken; } let content = generateCurl( - this.context.currentApp, + this.context, this.state.method, this.state.endpoint, payload, @@ -192,7 +192,3 @@ export default class RestConsole extends Component { ); } } - -RestConsole.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/dashboard/Data/Browser/BrowserTable.react.js b/src/dashboard/Data/Browser/BrowserTable.react.js index 1052f752ac..eb48eaef0f 100644 --- a/src/dashboard/Data/Browser/BrowserTable.react.js +++ b/src/dashboard/Data/Browser/BrowserTable.react.js @@ -16,8 +16,7 @@ import encode from 'parse/lib/browser/encode'; import React from 'react'; import styles from 'dashboard/Data/Browser/Browser.scss'; import Button from 'components/Button/Button.react'; -import ParseApp from 'lib/ParseApp'; -import PropTypes from 'lib/PropTypes'; +import { CurrentApp } from 'context/currentApp'; const MAX_ROWS = 200; // Number of rows to render at any time const ROWS_OFFSET = 160; @@ -26,6 +25,7 @@ const ROW_HEIGHT = 30; const READ_ONLY = [ 'objectId', 'createdAt', 'updatedAt' ]; export default class BrowserTable extends React.Component { + static contextType = CurrentApp; constructor() { super(); @@ -444,13 +444,8 @@ export default class BrowserTable extends React.Component { handleDragDrop={this.props.handleHeaderDragDrop} onResize={this.props.handleResize} onAddColumn={this.props.onAddColumn} - preventSchemaEdits={this.context.currentApp.preventSchemaEdits} /> + preventSchemaEdits={this.context.preventSchemaEdits} />
); } } - -BrowserTable.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; - diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js index f0e7e040ba..8713d87514 100644 --- a/src/dashboard/Data/Browser/DataBrowser.react.js +++ b/src/dashboard/Data/Browser/DataBrowser.react.js @@ -10,9 +10,8 @@ import BrowserTable from 'dashboard/Data/Browser/BrowserTable.react'; import BrowserToolbar from 'dashboard/Data/Browser/BrowserToolbar.react'; import ContextMenu from 'components/ContextMenu/ContextMenu.react'; import * as ColumnPreferences from 'lib/ColumnPreferences'; -import ParseApp from 'lib/ParseApp'; import React from 'react'; -import PropTypes from 'lib/PropTypes'; +import { CurrentApp } from 'context/currentApp'; /** * DataBrowser renders the browser toolbar and data table @@ -20,13 +19,14 @@ import PropTypes from 'lib/PropTypes'; * and the keyboard interactions for the data table. */ export default class DataBrowser extends React.Component { - constructor(props, context) { - super(props, context); + static contextType = CurrentApp; + constructor(props) { + super(props); - const columnPreferences = context.currentApp.columnPreference || {} + const columnPreferences = this.context.columnPreference || {} let order = ColumnPreferences.getOrder( props.columns, - context.currentApp.applicationId, + this.context.applicationId, props.className, columnPreferences[props.className] ); @@ -52,10 +52,10 @@ export default class DataBrowser extends React.Component { componentWillReceiveProps(props, context) { if (props.className !== this.props.className) { - const columnPreferences = context.currentApp.columnPreference || {} + const columnPreferences = context.columnPreference || {} let order = ColumnPreferences.getOrder( props.columns, - context.currentApp.applicationId, + context.applicationId, props.className, columnPreferences[props.className] ); @@ -67,10 +67,10 @@ export default class DataBrowser extends React.Component { }); } else if (Object.keys(props.columns).length !== Object.keys(this.props.columns).length || (props.isUnique && props.uniqueField !== this.props.uniqueField)) { - const columnPreferences = context.currentApp.columnPreference || {} + const columnPreferences = context.columnPreference || {} let order = ColumnPreferences.getOrder( props.columns, - context.currentApp.applicationId, + context.applicationId, props.className, columnPreferences[props.className] ); @@ -90,7 +90,7 @@ export default class DataBrowser extends React.Component { if (this.saveOrderTimeout) { clearTimeout(this.saveOrderTimeout); } - let appId = this.context.currentApp.applicationId; + let appId = this.context.applicationId; let className = this.props.className; this.saveOrderTimeout = setTimeout(() => { ColumnPreferences.updatePreferences(order, appId, className) @@ -299,7 +299,7 @@ export default class DataBrowser extends React.Component { render() { let { className, count, disableSecurityDialog, onCancelPendingEditRows, editCloneRows, ...other } = this.props; - const { preventSchemaEdits, applicationId } = this.context.currentApp; + const { preventSchemaEdits, applicationId } = this.context; return (
{ + this.context.getExportProgress().then((progress) => { this.setState({ progress }); }); } @@ -60,7 +60,3 @@ export default class ExportDialog extends React.Component { ); } } - -ExportDialog.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/dashboard/Data/Browser/LoginDialog.react.js b/src/dashboard/Data/Browser/LoginDialog.react.js index 80f7ff11e1..19840d5a19 100644 --- a/src/dashboard/Data/Browser/LoginDialog.react.js +++ b/src/dashboard/Data/Browser/LoginDialog.react.js @@ -1,6 +1,4 @@ import React from 'react'; -import ParseApp from 'lib/ParseApp'; -import PropTypes from 'prop-types'; import Modal from 'components/Modal/Modal.react'; import LoginRow from 'components/LoginRow/LoginRow.react'; import Notification from 'dashboard/Data/Browser/Notification.react'; @@ -106,7 +104,3 @@ export default class LoginDialog extends React.Component { ); } } - -LoginDialog.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/dashboard/Data/Browser/ObjectPickerDialog.react.js b/src/dashboard/Data/Browser/ObjectPickerDialog.react.js index 9c13bcb2f6..619400dcf7 100644 --- a/src/dashboard/Data/Browser/ObjectPickerDialog.react.js +++ b/src/dashboard/Data/Browser/ObjectPickerDialog.react.js @@ -3,8 +3,6 @@ import { List } from 'immutable'; import Parse from 'parse'; import * as ColumnPreferences from 'lib/ColumnPreferences'; import queryFromFilters from 'lib/queryFromFilters'; -import PropTypes from 'lib/PropTypes'; -import ParseApp from 'lib/ParseApp'; import Modal from 'components/Modal/Modal.react'; import Button from 'components/Button/Button.react'; import TextInput from 'components/TextInput/TextInput.react'; @@ -15,12 +13,14 @@ import stylesToolbar from 'components/Toolbar/Toolbar.scss'; import stylesColumnsConfiguration from 'components/ColumnsConfiguration/ColumnsConfiguration.scss'; import stylesDataBrowserHeaderBar from 'components/DataBrowserHeaderBar/DataBrowserHeaderBar.scss'; import stylesFooter from 'components/Modal/Modal.scss'; +import { CurrentApp } from 'context/currentApp'; // The initial and max amount of rows fetched by lazy loading const MAX_ROWS_FETCHED = 200; const SELECTION_INPUT_ID = 'selectionInput'; export default class ObjectPickerDialog extends React.Component { + static contextType = CurrentApp; constructor(props, context) { super(props, context); @@ -207,7 +207,7 @@ export default class ObjectPickerDialog extends React.Component { Object.keys(selection).forEach(id => this.selectRow(id, true)); ColumnPreferences.getColumnSort( ordering, - this.context.currentApp.applicationId, + this.context.applicationId, className ); } @@ -406,7 +406,3 @@ export default class ObjectPickerDialog extends React.Component { ); } } - -ObjectPickerDialog.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/dashboard/Data/Browser/SecureFieldsDialog.react.js b/src/dashboard/Data/Browser/SecureFieldsDialog.react.js index 9c0a0f08ce..d82fd3690e 100644 --- a/src/dashboard/Data/Browser/SecureFieldsDialog.react.js +++ b/src/dashboard/Data/Browser/SecureFieldsDialog.react.js @@ -10,8 +10,7 @@ import Parse from 'parse'; import React from 'react'; import styles from 'dashboard/Data/Browser/Browser.scss'; import ProtectedFieldsDialog from 'components/ProtectedFieldsDialog/ProtectedFieldsDialog.react'; -import ParseApp from 'lib/ParseApp'; -import PropTypes from 'prop-types'; +import { CurrentApp } from 'context/currentApp'; const pointerPrefix = 'userField:'; @@ -91,6 +90,7 @@ function validateEntry(pointers, text, parseServerSupportsPointerPermissions) { } export default class SecureFieldsDialog extends React.Component { + static contextType = CurrentApp; constructor(props) { super(props); this.state = { open: false }; @@ -117,7 +117,7 @@ export default class SecureFieldsDialog extends React.Component { render() { let dialog = null; - let parseServerSupportsPointerPermissions = this.context.currentApp + let parseServerSupportsPointerPermissions = this.context .serverInfo.features.schemas.editClassLevelPermissions; if (this.props.perms && this.state.open) { dialog = ( @@ -163,7 +163,3 @@ export default class SecureFieldsDialog extends React.Component { return dialog; } } - -SecureFieldsDialog.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; diff --git a/src/dashboard/Data/Browser/SecurityDialog.react.js b/src/dashboard/Data/Browser/SecurityDialog.react.js index 370e6986a3..cc817006d2 100644 --- a/src/dashboard/Data/Browser/SecurityDialog.react.js +++ b/src/dashboard/Data/Browser/SecurityDialog.react.js @@ -5,12 +5,11 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import PropTypes from 'lib/PropTypes'; import Parse from 'parse' -import ParseApp from 'lib/ParseApp'; import PermissionsDialog from 'components/PermissionsDialog/PermissionsDialog.react'; import React from 'react'; import styles from 'dashboard/Data/Browser/Browser.scss'; +import { CurrentApp } from 'context/currentApp'; const pointerPrefix = 'userField:'; @@ -86,6 +85,7 @@ function validateEntry(pointers, text, parseServerSupportsPointerPermissions) { } export default class SecurityDialog extends React.Component { + static contextType = CurrentApp; constructor() { super(); @@ -110,7 +110,7 @@ export default class SecurityDialog extends React.Component { render() { let dialog = null; - let parseServerSupportsPointerPermissions = this.context.currentApp.serverInfo.features.schemas.editClassLevelPermissions; + let parseServerSupportsPointerPermissions = this.context.serverInfo.features.schemas.editClassLevelPermissions; if (this.props.perms && this.state.open) { dialog = ( { + this.context.runJob(this.props.job).then(() => { this.setState({ progress: false, result: 'success' }); this.timeout = setTimeout(() => this.setState({ result: null }), 3000); }, () => { @@ -55,7 +55,3 @@ export default class RunNowButton extends React.Component { ); } } - -RunNowButton.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp), -}; diff --git a/src/dashboard/Data/Playground/Playground.react.js b/src/dashboard/Data/Playground/Playground.react.js index be34ccc5e9..51403be9c7 100644 --- a/src/dashboard/Data/Playground/Playground.react.js +++ b/src/dashboard/Data/Playground/Playground.react.js @@ -3,15 +3,16 @@ import ReactJson from 'react-json-view'; import Parse from 'parse'; import PropTypes from 'lib/PropTypes'; -import ParseApp from 'lib/ParseApp'; import CodeEditor from 'components/CodeEditor/CodeEditor.react'; import Button from 'components/Button/Button.react'; import SaveButton from 'components/SaveButton/SaveButton.react'; import Toolbar from 'components/Toolbar/Toolbar.react'; +import { CurrentApp } from 'context/currentApp'; import styles from './Playground.scss'; export default class Playground extends Component { + static contextType = CurrentApp; constructor() { super(); this.section = 'Core'; @@ -72,7 +73,7 @@ export default class Playground extends Component { try { const { - currentApp: { applicationId, masterKey, serverURL, javascriptKey } + applicationId, masterKey, serverURL, javascriptKey } = this.context; const originalCode = this.editor.value; @@ -200,5 +201,4 @@ console.log(myObj);`} Playground.contextTypes = { generatePath: PropTypes.func, - currentApp: PropTypes.instanceOf(ParseApp) }; diff --git a/src/dashboard/Push/PushAudiencesData.react.js b/src/dashboard/Push/PushAudiencesData.react.js index b16a13fbae..14e73f0666 100644 --- a/src/dashboard/Push/PushAudiencesData.react.js +++ b/src/dashboard/Push/PushAudiencesData.react.js @@ -16,12 +16,14 @@ import PushAudiencesSelector from 'components/PushAudiencesSelector/PushAudien import queryFromFilters from 'lib/queryFromFilters'; import React from 'react'; import styles from './PushAudiencesData.scss'; -import { List } from 'immutable'; +import { List } from 'immutable'; +import { CurrentApp } from 'context/currentApp'; const XHR_KEY = 'PushAudiencesData'; //TODO: lazy render options - avoid necessary calls for count if user doesn't see the audience export default class PushAudiencesData extends React.Component { + static contextType = CurrentApp; constructor() { super(); this.state = { @@ -46,7 +48,7 @@ export default class PushAudiencesData extends React.Component { this.setState({ defaultAudience: { - createdAt: this.context.currentApp.createdAt, + createdAt: this.context.createdAt, name: 'Everyone', count: 0, objectId: 'everyone', @@ -54,7 +56,7 @@ export default class PushAudiencesData extends React.Component { } }); - this.context.currentApp.fetchAvailableDevices().then(({ available_devices }) => { + this.context.fetchAvailableDevices().then(({ available_devices }) => { this.setState({ availableDevices: available_devices }); @@ -260,7 +262,3 @@ export default class PushAudiencesData extends React.Component { ) } } - -PushAudiencesData.contextTypes = { - currentApp: PropTypes.instanceOf(ParseApp) -}; From 8a400a2ab424e1062d7b72b6b8e032a186fc8543 Mon Sep 17 00:00:00 2001 From: Damian Stasik Date: Mon, 6 Dec 2021 21:58:25 +0100 Subject: [PATCH 03/13] Refactor another slice of code --- .../CategoryList/CategoryList.react.js | 8 +- src/components/Filter/Filter.react.js | 3 +- src/context/currentApp.js | 2 + .../Analytics/Explorer/Explorer.react.js | 2 +- .../Analytics/Overview/Overview.react.js | 4 +- .../Performance/Performance.react.js | 7 +- .../Analytics/Retention/Retention.react.js | 5 +- .../SlowQueries/SlowQueries.react.js | 7 +- src/dashboard/AppData.react.js | 22 +----- src/dashboard/DashboardView.react.js | 5 -- .../Data/CloudCode/CloudCode.react.js | 10 ++- src/dashboard/Data/Jobs/JobEdit.react.js | 9 +-- src/dashboard/Data/Jobs/Jobs.react.js | 7 +- src/dashboard/Data/Logs/Logs.react.js | 9 ++- .../Data/Migration/Migration.react.js | 36 ++++----- .../Data/Playground/Playground.react.js | 5 -- src/dashboard/Push/PushAudiencesData.react.js | 2 - .../Push/PushAudiencesIndex.react.js | 5 +- src/dashboard/Push/PushDetails.react.js | 19 +++-- src/dashboard/Push/PushIndex.react.js | 9 ++- src/dashboard/Push/PushNew.react.js | 15 ++-- .../Settings/GeneralSettings.react.js | 38 +++++----- .../Settings/HostingSettings.react.js | 4 +- src/dashboard/Settings/PushSettings.react.js | 10 +-- .../Settings/SecuritySettings.react.js | 4 +- src/dashboard/Settings/UsersSettings.react.js | 26 +++---- src/lib/generatePath.js | 3 + src/lib/subscribeTo.js | 73 ++++++++----------- 28 files changed, 157 insertions(+), 192 deletions(-) create mode 100644 src/lib/generatePath.js diff --git a/src/components/CategoryList/CategoryList.react.js b/src/components/CategoryList/CategoryList.react.js index 97d55573c2..ad717825ca 100644 --- a/src/components/CategoryList/CategoryList.react.js +++ b/src/components/CategoryList/CategoryList.react.js @@ -9,6 +9,7 @@ import PropTypes from 'lib/PropTypes'; import React from 'react'; import styles from 'components/CategoryList/CategoryList.scss'; import { Link } from 'react-router-dom'; +import generatePath from 'lib/generatePath'; export default class CategoryList extends React.Component { constructor() { @@ -64,7 +65,8 @@ export default class CategoryList extends React.Component { } let count = c.count; let className = id === this.props.current ? styles.active : ''; - let link = this.context.generatePath( + // TODO: pass context + let link = generatePath( (this.props.linkPrefix || '') + (c.link || id) ); return ( @@ -84,7 +86,3 @@ CategoryList.propTypes = { current: PropTypes.string.describe('Id of current category to be highlighted.'), linkPrefix: PropTypes.string.describe('Link prefix used to generate link path.'), }; - -CategoryList.contextTypes = { - generatePath: PropTypes.func -}; diff --git a/src/components/Filter/Filter.react.js b/src/components/Filter/Filter.react.js index baad7c8e44..48db5f6fbb 100644 --- a/src/components/Filter/Filter.react.js +++ b/src/components/Filter/Filter.react.js @@ -10,8 +10,7 @@ import { List, Map } from 'immutable'; import PropTypes from 'lib/PropTypes'; import React from 'react'; import stringCompare from 'lib/stringCompare'; -import ParseApp from 'lib/ParseApp'; -import { CurrentApp } from 'context/CurrentApp'; +import { CurrentApp } from 'context/currentApp'; function changeField(schema, filters, index, newField) { let newFilter = new Map({ diff --git a/src/context/currentApp.js b/src/context/currentApp.js index 6ccbd43fa2..e0be6d8af3 100644 --- a/src/context/currentApp.js +++ b/src/context/currentApp.js @@ -1 +1,3 @@ +import React from 'react'; + export const CurrentApp = React.createContext(null); \ No newline at end of file diff --git a/src/dashboard/Analytics/Explorer/Explorer.react.js b/src/dashboard/Analytics/Explorer/Explorer.react.js index 7be72bc325..b1415687e7 100644 --- a/src/dashboard/Analytics/Explorer/Explorer.react.js +++ b/src/dashboard/Analytics/Explorer/Explorer.react.js @@ -173,7 +173,7 @@ class Explorer extends DashboardView { to: this.state.dateRange.end.getTime() / 1000 }; - let abortableRequest = this.context.currentApp.getAnalyticsTimeSeries(payload); + let abortableRequest = this.context.getAnalyticsTimeSeries(payload); promise = abortableRequest.promise.then((result) => { let activeQueries = this.state.activeQueries; activeQueries[i].result = result.map((point) => ( diff --git a/src/dashboard/Analytics/Overview/Overview.react.js b/src/dashboard/Analytics/Overview/Overview.react.js index 7b4af28c22..1848f055ff 100644 --- a/src/dashboard/Analytics/Overview/Overview.react.js +++ b/src/dashboard/Analytics/Overview/Overview.react.js @@ -100,12 +100,12 @@ export default class Overview extends DashboardView { } componentWillMount() { - this.fetchOverview(this.context.currentApp); + this.fetchOverview(this.context); } componentWillReceiveProps(nextProps, nextContext) { if (this.context !== nextContext) { - this.fetchOverview(nextContext.currentApp); + this.fetchOverview(nextContext); } } diff --git a/src/dashboard/Analytics/Performance/Performance.react.js b/src/dashboard/Analytics/Performance/Performance.react.js index 9d4a98533e..8b79771610 100644 --- a/src/dashboard/Analytics/Performance/Performance.react.js +++ b/src/dashboard/Analytics/Performance/Performance.react.js @@ -102,7 +102,7 @@ export default class Performance extends DashboardView { } componentWillMount() { - this.handleRunQuery(this.context.currentApp); + this.handleRunQuery(this.context); } componentWillUnmount() { @@ -111,7 +111,8 @@ export default class Performance extends DashboardView { componentWillReceiveProps(nextProps, nextContext) { if (this.context !== nextContext) { - this.handleRunQuery(nextContext.currentApp); + // TODO: use new context + this.handleRunQuery(nextContext); } } @@ -187,7 +188,7 @@ export default class Performance extends DashboardView {
diff --git a/src/dashboard/Analytics/Retention/Retention.react.js b/src/dashboard/Analytics/Retention/Retention.react.js index 5fe7e4a905..edb3568d79 100644 --- a/src/dashboard/Analytics/Retention/Retention.react.js +++ b/src/dashboard/Analytics/Retention/Retention.react.js @@ -53,7 +53,7 @@ export default class Retention extends DashboardView { } componentWillMount() { - this.fetchRetention(this.context.currentApp); + this.fetchRetention(this.context); } componentWillUnmount() { @@ -62,7 +62,8 @@ export default class Retention extends DashboardView { componentWillReceiveProps(nextProps, nextContext) { if (this.context !== nextContext) { - this.fetchRetention(nextContext.currentApp); + // TODO: use new context + this.fetchRetention(nextContext); } } diff --git a/src/dashboard/Analytics/SlowQueries/SlowQueries.react.js b/src/dashboard/Analytics/SlowQueries/SlowQueries.react.js index c0ac36aee7..9e4b6a3e39 100644 --- a/src/dashboard/Analytics/SlowQueries/SlowQueries.react.js +++ b/src/dashboard/Analytics/SlowQueries/SlowQueries.react.js @@ -67,7 +67,7 @@ class SlowQueries extends TableView { componentWillMount() { this.fetchDropdownData(this.props); - this.fetchSlowQueries(this.context.currentApp); + this.fetchSlowQueries(this.context); } componentWillUnmount() { @@ -77,7 +77,8 @@ class SlowQueries extends TableView { componentWillReceiveProps(nextProps, nextContext) { if (this.context !== nextContext) { this.fetchDropdownData(nextProps); - this.fetchSlowQueries(nextContext.currentApp); + // TODO: use new context + this.fetchSlowQueries(nextContext); } } @@ -232,7 +233,7 @@ class SlowQueries extends TableView {