chore: add hook linter (#18909)
* chore: install eslint-plugin-react-hooks * fix: login dependency list * chore(wip): lint hooks * chore(wip): hook linting * chore: fix / comment lint rules * chore: comment lint warningspull/18911/head
parent
a3be86b231
commit
8e922ed14e
|
@ -15,6 +15,7 @@ module.exports = {
|
|||
},
|
||||
extends: [
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'prettier/react',
|
||||
'prettier/@typescript-eslint',
|
||||
'eslint:recommended',
|
||||
|
|
|
@ -12,17 +12,31 @@ describe('The Login Page', () => {
|
|||
user = u
|
||||
})
|
||||
|
||||
cy.setupUser()
|
||||
cy.setupUser().then(({body}) => {
|
||||
cy.wrap(body.org.id).as('orgID')
|
||||
})
|
||||
|
||||
cy.visit('/')
|
||||
})
|
||||
|
||||
it('can login', () => {
|
||||
it('can login and logout', () => {
|
||||
cy.getByInputName('username').type(user.username)
|
||||
cy.getByInputName('password').type(user.password)
|
||||
cy.get('button[type=submit]').click()
|
||||
|
||||
cy.getByTestID('tree-nav').should('exist')
|
||||
|
||||
cy.getByTestID('logout--button').click()
|
||||
|
||||
cy.getByTestID('signin-page--content').should('exist')
|
||||
|
||||
// try to access a protected route
|
||||
cy.get<string>('@orgID').then(orgID => {
|
||||
cy.visit(`/orgs/${orgID}`)
|
||||
})
|
||||
|
||||
// assert that user is routed to signin
|
||||
cy.getByTestID('signin-page--content').should('exist')
|
||||
})
|
||||
|
||||
describe('login failure', () => {
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
"eslint-config-prettier": "^6.5.0",
|
||||
"eslint-plugin-jest": "^23.0.2",
|
||||
"eslint-plugin-react": "^7.16.0",
|
||||
"eslint-plugin-react-hooks": "^4.0.5",
|
||||
"express": "^4.14.0",
|
||||
"file-loader": "^4.1.0",
|
||||
"fork-ts-checker-webpack-plugin": "^1.4.3",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Libraries
|
||||
import {FC, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {useDispatch} from 'react-redux'
|
||||
import {RouteComponentProps} from 'react-router-dom'
|
||||
|
||||
// APIs
|
||||
import {postSignout} from 'src/client'
|
||||
|
@ -12,36 +12,31 @@ import {CLOUD, CLOUD_URL, CLOUD_LOGOUT_PATH} from 'src/shared/constants'
|
|||
// Components
|
||||
import {reset} from 'src/shared/actions/flags'
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = ReduxProps & RouteComponentProps
|
||||
type Props = RouteComponentProps
|
||||
|
||||
const Logout: FC<Props> = ({history, resetFeatureFlags}) => {
|
||||
const handleSignOut = async () => {
|
||||
if (CLOUD) {
|
||||
window.location.href = `${CLOUD_URL}${CLOUD_LOGOUT_PATH}`
|
||||
return
|
||||
} else {
|
||||
const resp = await postSignout({})
|
||||
|
||||
if (resp.status !== 204) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
history.push(`/signin`)
|
||||
}
|
||||
}
|
||||
const Logout: FC<Props> = ({history}) => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
resetFeatureFlags()
|
||||
const handleSignOut = async () => {
|
||||
if (CLOUD) {
|
||||
window.location.href = `${CLOUD_URL}${CLOUD_LOGOUT_PATH}`
|
||||
return
|
||||
} else {
|
||||
const resp = await postSignout({})
|
||||
|
||||
if (resp.status !== 204) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
history.push(`/signin`)
|
||||
}
|
||||
}
|
||||
dispatch(reset())
|
||||
handleSignOut()
|
||||
}, [])
|
||||
}, [dispatch, history])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
resetFeatureFlags: reset,
|
||||
}
|
||||
|
||||
const connector = connect(null, mdtp)
|
||||
|
||||
export default connector(withRouter(Logout))
|
||||
export default Logout
|
||||
|
|
|
@ -32,7 +32,7 @@ const AlertHistoryQueryParams: FC<Props & RouteComponentProps> = ({
|
|||
},
|
||||
history
|
||||
)
|
||||
}, [searchInput, historyType])
|
||||
}, [searchInput, historyType, history])
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -56,12 +56,12 @@ const ThresholdCondition: FC<Props> = ({
|
|||
get(threshold, 'max', 100),
|
||||
])
|
||||
|
||||
const min = get(threshold, 'value') || get(threshold, 'min', inputs[0])
|
||||
const max = get(threshold, 'max', inputs[1])
|
||||
|
||||
useEffect(() => {
|
||||
changeInputs([
|
||||
get(threshold, 'value') || get(threshold, 'min', inputs[0]),
|
||||
get(threshold, 'max', inputs[1]),
|
||||
])
|
||||
}, [threshold])
|
||||
changeInputs([min, max])
|
||||
}, [min, max])
|
||||
|
||||
const [yDomain] = useCheckYDomain(table.getColumn('_value', 'number'), [])
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FC, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -11,10 +11,7 @@ import {
|
|||
} from '@influxdata/clockface'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
checkBucketLimits as checkBucketLimitsAction,
|
||||
LimitStatus,
|
||||
} from 'src/cloud/actions/limits'
|
||||
import {checkBucketLimits, LimitStatus} from 'src/cloud/actions/limits'
|
||||
import {showOverlay, dismissOverlay} from 'src/overlays/actions/overlays'
|
||||
|
||||
// Utils
|
||||
|
@ -28,14 +25,14 @@ type Props = ReduxProps
|
|||
|
||||
const CreateBucketButton: FC<Props> = ({
|
||||
limitStatus,
|
||||
checkBucketLimits,
|
||||
onShowOverlay,
|
||||
onDismissOverlay,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
// Check bucket limits when component mounts
|
||||
checkBucketLimits()
|
||||
}, [])
|
||||
dispatch(checkBucketLimits())
|
||||
}, [dispatch])
|
||||
|
||||
const limitExceeded = limitStatus === LimitStatus.EXCEEDED
|
||||
const text = 'Create Bucket'
|
||||
|
@ -77,7 +74,6 @@ const mstp = (state: AppState) => {
|
|||
const mdtp = {
|
||||
onShowOverlay: showOverlay,
|
||||
onDismissOverlay: dismissOverlay,
|
||||
checkBucketLimits: checkBucketLimitsAction,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// Libraries
|
||||
import React, {FC, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {get, sortBy} from 'lodash'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
getDemoDataBucketMembership as getDemoDataBucketMembershipAction,
|
||||
getDemoDataBuckets as getDemoDataBucketsAction,
|
||||
getDemoDataBuckets,
|
||||
} from 'src/cloud/actions/demodata'
|
||||
|
||||
// Components
|
||||
|
@ -22,11 +22,11 @@ const DemoDataDropdown: FC<Props> = ({
|
|||
ownBucketsByID,
|
||||
demoDataBuckets,
|
||||
getDemoDataBucketMembership,
|
||||
getDemoDataBuckets,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
getDemoDataBuckets()
|
||||
}, [])
|
||||
dispatch(getDemoDataBuckets())
|
||||
}, [dispatch])
|
||||
|
||||
if (!demoDataBuckets.length) {
|
||||
return null
|
||||
|
@ -109,7 +109,6 @@ const mstp = (state: AppState) => ({
|
|||
|
||||
const mdtp = {
|
||||
getDemoDataBucketMembership: getDemoDataBucketMembershipAction,
|
||||
getDemoDataBuckets: getDemoDataBucketsAction,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
|
|
@ -5,9 +5,10 @@ import React, {
|
|||
useState,
|
||||
ChangeEvent,
|
||||
FormEvent,
|
||||
useCallback,
|
||||
} from 'react'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {get} from 'lodash'
|
||||
|
||||
// Components
|
||||
|
@ -35,7 +36,6 @@ import {OwnBucket} from 'src/types'
|
|||
|
||||
interface DispatchProps {
|
||||
onUpdateBucket: typeof updateBucket
|
||||
onNotify: typeof notify
|
||||
}
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
|
@ -43,23 +43,27 @@ type Props = ReduxProps & RouteComponentProps<{bucketID: string; orgID: string}>
|
|||
|
||||
const UpdateBucketOverlay: FunctionComponent<Props> = ({
|
||||
onUpdateBucket,
|
||||
onNotify,
|
||||
match,
|
||||
history,
|
||||
}) => {
|
||||
const {orgID, bucketID} = match.params
|
||||
const dispatch = useDispatch()
|
||||
const [bucketDraft, setBucketDraft] = useState<OwnBucket>(null)
|
||||
|
||||
const [loadingStatus, setLoadingStatus] = useState(RemoteDataState.Loading)
|
||||
|
||||
const [retentionSelection, setRetentionSelection] = useState(DEFAULT_SECONDS)
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
history.push(`/orgs/${orgID}/load-data/buckets`)
|
||||
}, [orgID, history])
|
||||
|
||||
useEffect(() => {
|
||||
const fetchBucket = async () => {
|
||||
const resp = await api.getBucket({bucketID})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
onNotify(getBucketFailed(bucketID, resp.data.message))
|
||||
dispatch(notify(getBucketFailed(bucketID, resp.data.message)))
|
||||
handleClose()
|
||||
return
|
||||
}
|
||||
|
@ -74,7 +78,7 @@ const UpdateBucketOverlay: FunctionComponent<Props> = ({
|
|||
setLoadingStatus(RemoteDataState.Done)
|
||||
}
|
||||
fetchBucket()
|
||||
}, [bucketID])
|
||||
}, [bucketID, handleClose, dispatch])
|
||||
|
||||
const handleChangeRetentionRule = (everySeconds: number): void => {
|
||||
setBucketDraft({
|
||||
|
@ -112,10 +116,6 @@ const UpdateBucketOverlay: FunctionComponent<Props> = ({
|
|||
setBucketDraft({...bucketDraft, [key]: value})
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
history.push(`/orgs/${orgID}/load-data/buckets`)
|
||||
}
|
||||
|
||||
const handleClickRename = () => {
|
||||
history.push(`/orgs/${orgID}/load-data/buckets/${bucketID}/rename`)
|
||||
}
|
||||
|
@ -157,7 +157,6 @@ const UpdateBucketOverlay: FunctionComponent<Props> = ({
|
|||
|
||||
const mdtp = {
|
||||
onUpdateBucket: updateBucket,
|
||||
onNotify: notify,
|
||||
}
|
||||
|
||||
const connector = connect(null, mdtp)
|
||||
|
|
|
@ -94,7 +94,7 @@ const CheckMatchingRulesCard: FC<Props> = ({orgID, tags, queryResults}) => {
|
|||
})
|
||||
|
||||
getMatchingRules()
|
||||
}, [tags, queryResults])
|
||||
}, [tags, queryResults]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
let contents: JSX.Element
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useEffect} from 'react'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {get} from 'lodash'
|
||||
|
||||
// Components
|
||||
|
@ -30,8 +30,6 @@ const EditCheckEditorOverlay: FunctionComponent<Props> = ({
|
|||
onUpdateAlertBuilderName,
|
||||
onResetAlertBuilder,
|
||||
onSaveCheckFromTimeMachine,
|
||||
onExecuteQueries,
|
||||
onGetCheckForTimeMachine,
|
||||
activeTimeMachineID,
|
||||
status,
|
||||
history,
|
||||
|
@ -42,13 +40,16 @@ const EditCheckEditorOverlay: FunctionComponent<Props> = ({
|
|||
loadedCheckID,
|
||||
view,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
onGetCheckForTimeMachine(checkID)
|
||||
}, [checkID])
|
||||
const dispatch = useDispatch()
|
||||
const query = get(view, 'properties.queries[0]', null)
|
||||
|
||||
useEffect(() => {
|
||||
onExecuteQueries()
|
||||
}, [get(view, 'properties.queries[0]', null)])
|
||||
dispatch(getCheckForTimeMachine(checkID))
|
||||
}, [dispatch, checkID])
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(executeQueries())
|
||||
}, [dispatch, query])
|
||||
|
||||
const handleClose = () => {
|
||||
history.push(`/orgs/${orgID}/alerting`)
|
||||
|
@ -108,9 +109,7 @@ const mstp = (state: AppState) => {
|
|||
}
|
||||
|
||||
const mdtp = {
|
||||
onGetCheckForTimeMachine: getCheckForTimeMachine,
|
||||
onSaveCheckFromTimeMachine: updateCheckFromTimeMachine,
|
||||
onExecuteQueries: executeQueries,
|
||||
onResetAlertBuilder: resetAlertBuilder,
|
||||
onUpdateAlertBuilderName: updateName,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
|
||||
// Components
|
||||
|
@ -34,18 +34,20 @@ const NewCheckOverlay: FunctionComponent<Props> = ({
|
|||
checkName,
|
||||
history,
|
||||
onSaveCheckFromTimeMachine,
|
||||
onSetActiveTimeMachine,
|
||||
onResetAlertBuilder,
|
||||
onUpdateAlertBuilderName,
|
||||
onInitializeAlertBuilder,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
const view = createView<CheckViewProperties>('deadman')
|
||||
onInitializeAlertBuilder('deadman')
|
||||
onSetActiveTimeMachine('alerting', {
|
||||
view,
|
||||
})
|
||||
}, [])
|
||||
dispatch(initializeAlertBuilder('deadman'))
|
||||
dispatch(
|
||||
setActiveTimeMachine('alerting', {
|
||||
view,
|
||||
})
|
||||
)
|
||||
}, [dispatch])
|
||||
|
||||
const handleClose = () => {
|
||||
history.push(`/orgs/${orgID}/alerting`)
|
||||
|
@ -80,11 +82,9 @@ const mstp = ({alertBuilder: {name, status}}: AppState) => {
|
|||
}
|
||||
|
||||
const mdtp = {
|
||||
onSetActiveTimeMachine: setActiveTimeMachine,
|
||||
onSaveCheckFromTimeMachine: createCheckFromTimeMachine,
|
||||
onResetAlertBuilder: resetAlertBuilder,
|
||||
onUpdateAlertBuilderName: updateName,
|
||||
onInitializeAlertBuilder: initializeAlertBuilder,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
|
||||
// Components
|
||||
|
@ -34,18 +34,20 @@ const NewCheckOverlay: FunctionComponent<Props> = ({
|
|||
checkName,
|
||||
history,
|
||||
onSaveCheckFromTimeMachine,
|
||||
onSetActiveTimeMachine,
|
||||
onResetAlertBuilder,
|
||||
onUpdateAlertBuilderName,
|
||||
onInitializeAlertBuilder,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
const view = createView<CheckViewProperties>('threshold')
|
||||
onInitializeAlertBuilder('threshold')
|
||||
onSetActiveTimeMachine('alerting', {
|
||||
view,
|
||||
})
|
||||
}, [])
|
||||
dispatch(initializeAlertBuilder('threshold'))
|
||||
dispatch(
|
||||
setActiveTimeMachine('alerting', {
|
||||
view,
|
||||
})
|
||||
)
|
||||
}, [dispatch])
|
||||
|
||||
const handleClose = () => {
|
||||
history.push(`/orgs/${orgID}/alerting`)
|
||||
|
@ -80,11 +82,9 @@ const mstp = ({alertBuilder: {name, status}}: AppState) => {
|
|||
}
|
||||
|
||||
const mdtp = {
|
||||
onSetActiveTimeMachine: setActiveTimeMachine,
|
||||
onSaveCheckFromTimeMachine: createCheckFromTimeMachine as any,
|
||||
onResetAlertBuilder: resetAlertBuilder,
|
||||
onUpdateAlertBuilderName: updateName,
|
||||
onInitializeAlertBuilder: initializeAlertBuilder,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import {FunctionComponent, useEffect, useState} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {FC, useEffect, useState} from 'react'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
|
||||
// Constants
|
||||
import {CLOUD} from 'src/shared/constants'
|
||||
|
@ -22,21 +22,18 @@ interface PassedInProps {
|
|||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = ReduxProps & PassedInProps
|
||||
|
||||
const OrgSettings: FunctionComponent<Props> = ({
|
||||
org,
|
||||
getOrgSettings,
|
||||
settings,
|
||||
children,
|
||||
}) => {
|
||||
const OrgSettings: FC<Props> = ({org, settings, children}) => {
|
||||
const dispatch = useDispatch()
|
||||
const [hasFetchedOrgSettings, setHasFetchedOrgSettings] = useState<boolean>(
|
||||
false
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (CLOUD && org && !hasFetchedOrgSettings) {
|
||||
setHasFetchedOrgSettings(true)
|
||||
getOrgSettings()
|
||||
dispatch(getOrgSettingsAction())
|
||||
}
|
||||
}, [org])
|
||||
}, [dispatch, org, hasFetchedOrgSettings])
|
||||
|
||||
useEffect(() => {
|
||||
updateReportingContext(
|
||||
|
|
|
@ -166,5 +166,5 @@ export const useLoadTimeReporting = (event: string) => {
|
|||
fields: {},
|
||||
tags: {event},
|
||||
})
|
||||
}, [])
|
||||
}, [event, loadStartTime])
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FC, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import GetResource from 'src/resources/components/GetResource'
|
||||
|
@ -26,11 +26,8 @@ const {Active} = AutoRefreshStatus
|
|||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = ReduxProps
|
||||
|
||||
const DashboardContainer: FC<Props> = ({
|
||||
autoRefresh,
|
||||
dashboard,
|
||||
onSetCurrentPage,
|
||||
}) => {
|
||||
const DashboardContainer: FC<Props> = ({autoRefresh, dashboard}) => {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
if (autoRefresh.status === Active) {
|
||||
GlobalAutoRefresher.poll(autoRefresh.interval)
|
||||
|
@ -45,11 +42,11 @@ const DashboardContainer: FC<Props> = ({
|
|||
}, [autoRefresh.status, autoRefresh.interval])
|
||||
|
||||
useEffect(() => {
|
||||
onSetCurrentPage('dashboard')
|
||||
dispatch(setCurrentPage('dashboard'))
|
||||
return () => {
|
||||
onSetCurrentPage('not set')
|
||||
dispatch(setCurrentPage('not set'))
|
||||
}
|
||||
}, [])
|
||||
}, [dispatch])
|
||||
|
||||
return (
|
||||
<DashboardRoute>
|
||||
|
@ -72,10 +69,6 @@ const mstp = (state: AppState) => {
|
|||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onSetCurrentPage: setCurrentPage,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
const connector = connect(mstp)
|
||||
|
||||
export default connector(DashboardContainer)
|
||||
|
|
|
@ -74,7 +74,7 @@ const DashboardHeader: FC<Props> = ({
|
|||
}) => {
|
||||
useEffect(() => {
|
||||
fireDashboardViewedEvent(dashboard.name)
|
||||
}, [dashboard.id])
|
||||
}, [dashboard.id]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const handleAddNote = () => {
|
||||
history.push(`/orgs/${org.id}/dashboards/${dashboard.id}/notes/new`)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useEffect} from 'react'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {get} from 'lodash'
|
||||
|
||||
// Components
|
||||
|
@ -26,7 +26,6 @@ type Props = ReduxProps &
|
|||
|
||||
const EditViewVEO: FunctionComponent<Props> = ({
|
||||
activeTimeMachineID,
|
||||
getViewAndResultsForVEO,
|
||||
onSaveView,
|
||||
onSetName,
|
||||
match: {
|
||||
|
@ -35,12 +34,13 @@ const EditViewVEO: FunctionComponent<Props> = ({
|
|||
history,
|
||||
view,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
// TODO split this up into "loadView" "setActiveTimeMachine"
|
||||
// and something to tell the component to pull from the context
|
||||
// of the dashboardID
|
||||
getViewAndResultsForVEO(dashboardID, cellID, 'veo')
|
||||
}, [])
|
||||
dispatch(getViewAndResultsForVEO(dashboardID, cellID, 'veo'))
|
||||
}, [dispatch, dashboardID, cellID])
|
||||
|
||||
const handleClose = () => {
|
||||
history.push(`/orgs/${orgID}/dashboards/${dashboardID}`)
|
||||
|
@ -91,7 +91,6 @@ const mstp = (state: AppState) => {
|
|||
}
|
||||
|
||||
const mdtp = {
|
||||
getViewAndResultsForVEO: getViewAndResultsForVEO,
|
||||
onSetName: setName,
|
||||
onSaveView: saveVEOView,
|
||||
}
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
// Libraries
|
||||
import React, {FC, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {useDispatch, useSelector} from 'react-redux'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {getTimeRange} from 'src/dashboards/selectors'
|
||||
|
||||
// Actions
|
||||
import * as actions from 'src/dashboards/actions/ranges'
|
||||
|
||||
// Types
|
||||
import {AppState} from 'src/types'
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = RouteComponentProps<{dashboardID: string}> & ReduxProps
|
||||
|
||||
const GetTimeRange: FC<Props> = ({
|
||||
location,
|
||||
match,
|
||||
timeRange,
|
||||
import {
|
||||
setDashboardTimeRange,
|
||||
updateQueryParams,
|
||||
}: Props) => {
|
||||
} from 'src/dashboards/actions/ranges'
|
||||
|
||||
type Props = RouteComponentProps<{dashboardID: string}>
|
||||
|
||||
const GetTimeRange: FC<Props> = ({location, match}: Props) => {
|
||||
const dispatch = useDispatch()
|
||||
const timeRange = useSelector(getTimeRange)
|
||||
const isEditing = location.pathname.includes('edit')
|
||||
const isNew = location.pathname.includes('new')
|
||||
|
||||
|
@ -29,27 +24,17 @@ const GetTimeRange: FC<Props> = ({
|
|||
}
|
||||
|
||||
// TODO: map this to current contextID
|
||||
setDashboardTimeRange(match.params.dashboardID, timeRange)
|
||||
dispatch(setDashboardTimeRange(match.params.dashboardID, timeRange))
|
||||
const {lower, upper} = timeRange
|
||||
updateQueryParams({
|
||||
lower,
|
||||
upper,
|
||||
})
|
||||
}, [isEditing, isNew])
|
||||
dispatch(
|
||||
updateQueryParams({
|
||||
lower,
|
||||
upper,
|
||||
})
|
||||
)
|
||||
}, [dispatch, isEditing, isNew, match.params.dashboardID, timeRange])
|
||||
|
||||
return <div />
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const timeRange = getTimeRange(state)
|
||||
return {timeRange}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
updateQueryParams: actions.updateQueryParams,
|
||||
setDashboardTimeRange: actions.setDashboardTimeRange,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
||||
export default withRouter(connector(GetTimeRange))
|
||||
export default withRouter(GetTimeRange)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useEffect} from 'react'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {get} from 'lodash'
|
||||
|
||||
// Components
|
||||
|
@ -26,7 +26,6 @@ type Props = ReduxProps &
|
|||
|
||||
const NewViewVEO: FunctionComponent<Props> = ({
|
||||
activeTimeMachineID,
|
||||
onLoadNewVEO,
|
||||
onSaveView,
|
||||
onSetName,
|
||||
match: {
|
||||
|
@ -35,9 +34,10 @@ const NewViewVEO: FunctionComponent<Props> = ({
|
|||
history,
|
||||
view,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
onLoadNewVEO()
|
||||
}, [dashboardID])
|
||||
dispatch(loadNewVEO())
|
||||
}, [dispatch, dashboardID])
|
||||
|
||||
const handleClose = () => {
|
||||
history.push(`/orgs/${orgID}/dashboards/${dashboardID}`)
|
||||
|
@ -47,7 +47,9 @@ const NewViewVEO: FunctionComponent<Props> = ({
|
|||
try {
|
||||
onSaveView(dashboardID)
|
||||
handleClose()
|
||||
} catch (e) {}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
let loadingState = RemoteDataState.Loading
|
||||
|
@ -89,7 +91,6 @@ const mstp = (state: AppState) => {
|
|||
const mdtp = {
|
||||
onSetName: setName,
|
||||
onSaveView: saveVEOView,
|
||||
onLoadNewVEO: loadNewVEO,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FC, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {useDispatch} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import TimeMachine from 'src/timeMachine/components/TimeMachine'
|
||||
|
@ -16,19 +16,15 @@ import {HoverTimeProvider} from 'src/dashboards/utils/hoverTime'
|
|||
import {queryBuilderFetcher} from 'src/timeMachine/apis/QueryBuilderFetcher'
|
||||
import {readQueryParams} from 'src/shared/utils/queryParams'
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = ReduxProps
|
||||
const DataExplorer: FC = () => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const DataExplorer: FC<Props> = ({
|
||||
onSetActiveTimeMachine,
|
||||
onSetBuilderBucketIfExists,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
const bucketQP = readQueryParams()['bucket']
|
||||
onSetActiveTimeMachine('de')
|
||||
dispatch(setActiveTimeMachine('de'))
|
||||
queryBuilderFetcher.clearCache()
|
||||
onSetBuilderBucketIfExists(bucketQP)
|
||||
}, [])
|
||||
dispatch(setBuilderBucketIfExists(bucketQP))
|
||||
}, [dispatch])
|
||||
|
||||
return (
|
||||
<LimitChecker>
|
||||
|
@ -42,11 +38,4 @@ const DataExplorer: FC<Props> = ({
|
|||
)
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onSetActiveTimeMachine: setActiveTimeMachine,
|
||||
onSetBuilderBucketIfExists: setBuilderBucketIfExists,
|
||||
}
|
||||
|
||||
const connector = connect(null, mdtp)
|
||||
|
||||
export default connector(DataExplorer)
|
||||
export default DataExplorer
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {get} from 'lodash'
|
||||
|
||||
|
@ -33,24 +33,23 @@ const DeleteDataOverlay: FunctionComponent<Props> = ({
|
|||
},
|
||||
bucketNameFromDE,
|
||||
timeRangeFromDE,
|
||||
resetPredicateState,
|
||||
setTimeRange,
|
||||
setBucketAndKeys,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
if (bucketNameFromDE) {
|
||||
setBucketAndKeys(bucketNameFromDE)
|
||||
dispatch(setBucketAndKeys(bucketNameFromDE))
|
||||
}
|
||||
}, [bucketNameFromDE])
|
||||
}, [dispatch, bucketNameFromDE])
|
||||
|
||||
useEffect(() => {
|
||||
if (timeRangeFromDE) {
|
||||
setTimeRange(convertTimeRangeToCustom(timeRangeFromDE))
|
||||
dispatch(setTimeRange(convertTimeRangeToCustom(timeRangeFromDE)))
|
||||
}
|
||||
}, [timeRangeFromDE])
|
||||
}, [dispatch, timeRangeFromDE])
|
||||
|
||||
const handleDismiss = () => {
|
||||
resetPredicateState()
|
||||
dispatch(resetPredicateState())
|
||||
history.push(`/orgs/${orgID}/data-explorer`)
|
||||
}
|
||||
|
||||
|
@ -80,12 +79,6 @@ const mstp = (state: AppState) => {
|
|||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
resetPredicateState,
|
||||
setTimeRange,
|
||||
setBucketAndKeys,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
const connector = connect(mstp)
|
||||
|
||||
export default connector(withRouter(DeleteDataOverlay))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {useLayoutEffect, FC, useEffect, useState} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {useDispatch} from 'react-redux'
|
||||
import {AutoSizer, InfiniteLoader, List} from 'react-virtualized'
|
||||
|
||||
// Components
|
||||
|
@ -11,7 +11,7 @@ import FooterRow from 'src/eventViewer/components/FooterRow'
|
|||
import ErrorRow from 'src/eventViewer/components/ErrorRow'
|
||||
|
||||
// Actions
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
import {notify} from 'src/shared/actions/notifications'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
|
@ -30,13 +30,14 @@ type OwnProps = {
|
|||
fields: Fields
|
||||
}
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = EventViewerChildProps & ReduxProps & OwnProps
|
||||
type Props = EventViewerChildProps & OwnProps
|
||||
|
||||
const EventTable: FC<Props> = ({state, dispatch, loadRows, fields, notify}) => {
|
||||
const rowLoadedFn = state => ({index}) => !!state.rows[index]
|
||||
|
||||
const EventTable: FC<Props> = ({state, dispatch, loadRows, fields}) => {
|
||||
const rowCount = getRowCount(state)
|
||||
|
||||
const isRowLoaded = ({index}) => !!state.rows[index]
|
||||
const isRowLoaded = rowLoadedFn(state)
|
||||
|
||||
const isRowLoadedBoolean = !!state.rows[0]
|
||||
|
||||
|
@ -44,6 +45,8 @@ const EventTable: FC<Props> = ({state, dispatch, loadRows, fields, notify}) => {
|
|||
|
||||
const [isLongRunningQuery, setIsLongRunningQuery] = useState(false)
|
||||
|
||||
const reduxDispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setIsLongRunningQuery(true)
|
||||
|
@ -52,9 +55,9 @@ const EventTable: FC<Props> = ({state, dispatch, loadRows, fields, notify}) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (isLongRunningQuery && !isRowLoadedBoolean) {
|
||||
notify(checkStatusLoading)
|
||||
reduxDispatch(notify(checkStatusLoading))
|
||||
}
|
||||
}, [isLongRunningQuery, isRowLoaded])
|
||||
}, [reduxDispatch, isLongRunningQuery, isRowLoadedBoolean, isRowLoaded])
|
||||
|
||||
const rowRenderer = ({key, index, style}) => {
|
||||
const isLastRow = index === state.rows.length
|
||||
|
@ -129,10 +132,4 @@ const EventTable: FC<Props> = ({state, dispatch, loadRows, fields, notify}) => {
|
|||
)
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
notify: notifyAction,
|
||||
}
|
||||
|
||||
const connector = connect(null, mdtp)
|
||||
|
||||
export default connector(EventTable)
|
||||
export default EventTable
|
||||
|
|
|
@ -28,13 +28,17 @@ const EventViewer: FC<Props> = ({loadRows, children, initialState}) => {
|
|||
|
||||
useEffect(() => {
|
||||
loadNextRows(state, dispatch, loadRows, Date.now())
|
||||
}, [])
|
||||
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useMountedLayoutEffect(() => {
|
||||
refresh(state, dispatch, loadRows)
|
||||
}, [loadRows])
|
||||
|
||||
return children({state, dispatch, loadRows})
|
||||
return children({
|
||||
state,
|
||||
dispatch,
|
||||
loadRows,
|
||||
})
|
||||
}
|
||||
|
||||
export default EventViewer
|
||||
|
|
|
@ -8,7 +8,11 @@ import {Button, ComponentSize} from '@influxdata/clockface'
|
|||
const LogoutButton: SFC = () => (
|
||||
<>
|
||||
<Link to="/logout">
|
||||
<Button text="Logout" size={ComponentSize.ExtraSmall} />
|
||||
<Button
|
||||
text="Logout"
|
||||
size={ComponentSize.ExtraSmall}
|
||||
testID="logout--button"
|
||||
/>
|
||||
</Link>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -12,7 +12,7 @@ const Pipe: FC<PipeProp> = props => {
|
|||
|
||||
return useMemo(
|
||||
() => createElement(PIPE_DEFINITIONS[data.type].component, props),
|
||||
[props.data, props.results]
|
||||
[props.data, props.results] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import {DapperScrollbars} from '@influxdata/clockface'
|
|||
const PipeList: FC = () => {
|
||||
const {id, pipes, updatePipe, results, meta} = useContext(NotebookContext)
|
||||
const {scrollPosition} = useContext(ScrollContext)
|
||||
const update = useCallback(updatePipe, [id])
|
||||
const update = useCallback(updatePipe, [id, updatePipe])
|
||||
|
||||
if (!pipes.length) {
|
||||
return <EmptyPipeList />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, {FC, useMemo} from 'react'
|
||||
import React, {FC, useMemo, useCallback} from 'react'
|
||||
import {default as StatelessAutoRefreshDropdown} from 'src/shared/components/dropdown_auto_refresh/AutoRefreshDropdown'
|
||||
import {TimeContextProps} from 'src/notebooks/components/header/Buttons'
|
||||
import {TimeBlock} from 'src/notebooks/context/time'
|
||||
|
@ -10,32 +10,34 @@ import {event} from 'src/notebooks/shared/event'
|
|||
const AutoRefreshDropdown: FC<TimeContextProps> = ({context, update}) => {
|
||||
const {refresh} = context
|
||||
|
||||
const updateRefresh = (interval: number) => {
|
||||
const status =
|
||||
interval === 0 ? AutoRefreshStatus.Paused : AutoRefreshStatus.Active
|
||||
const updateRefresh = useCallback(
|
||||
(interval: number) => {
|
||||
const status =
|
||||
interval === 0 ? AutoRefreshStatus.Paused : AutoRefreshStatus.Active
|
||||
|
||||
event('Auto Refresh Updated', {
|
||||
interval: '' + interval,
|
||||
})
|
||||
event('Auto Refresh Updated', {
|
||||
interval: '' + interval,
|
||||
})
|
||||
|
||||
update({
|
||||
refresh: {
|
||||
status,
|
||||
interval,
|
||||
},
|
||||
} as TimeBlock)
|
||||
}
|
||||
update({
|
||||
refresh: {
|
||||
status,
|
||||
interval,
|
||||
},
|
||||
} as TimeBlock)
|
||||
},
|
||||
[update]
|
||||
)
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
return useMemo(() => {
|
||||
return (
|
||||
<StatelessAutoRefreshDropdown
|
||||
selected={refresh}
|
||||
onChoose={updateRefresh}
|
||||
showManualRefresh={false}
|
||||
/>
|
||||
),
|
||||
[refresh]
|
||||
)
|
||||
)
|
||||
}, [refresh, updateRefresh])
|
||||
}
|
||||
|
||||
export default AutoRefreshDropdown
|
||||
|
|
|
@ -28,7 +28,7 @@ const Buttons: FC = () => {
|
|||
(data: TimeBlock) => {
|
||||
updateTimeContext(id, data)
|
||||
},
|
||||
[id]
|
||||
[id, updateTimeContext]
|
||||
)
|
||||
|
||||
if (!timeContext.hasOwnProperty(id)) {
|
||||
|
|
|
@ -25,12 +25,13 @@ export const Submit: FC = () => {
|
|||
const {timeContext} = useContext(TimeContext)
|
||||
const [isLoading, setLoading] = useState(RemoteDataState.NotStarted)
|
||||
const time = timeContext[id]
|
||||
const tr = !!time && time.range
|
||||
|
||||
useEffect(() => {
|
||||
submit()
|
||||
}, [!!time && time.range])
|
||||
}, [tr]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const submit = () => {
|
||||
const submit = async () => {
|
||||
event('Notebook Submit Button Clicked')
|
||||
|
||||
setLoading(RemoteDataState.Loading)
|
||||
|
@ -90,7 +91,9 @@ export const Submit: FC = () => {
|
|||
})
|
||||
.catch(e => {
|
||||
queryStruct.instances.forEach(index => {
|
||||
updateMeta(index, {loading: RemoteDataState.Error} as PipeMeta)
|
||||
updateMeta(index, {
|
||||
loading: RemoteDataState.Error,
|
||||
} as PipeMeta)
|
||||
updateResult(index, {
|
||||
error: e.message,
|
||||
} as BothResults)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, {FC, useMemo} from 'react'
|
||||
import React, {FC, useMemo, useCallback} from 'react'
|
||||
import {default as StatelessTimeRangeDropdown} from 'src/shared/components/TimeRangeDropdown'
|
||||
import {TimeContextProps} from 'src/notebooks/components/header/Buttons'
|
||||
import {TimeBlock} from 'src/notebooks/context/time'
|
||||
|
@ -9,17 +9,20 @@ import {event} from 'src/notebooks/shared/event'
|
|||
const TimeRangeDropdown: FC<TimeContextProps> = ({context, update}) => {
|
||||
const {range} = context
|
||||
|
||||
const updateRange = range => {
|
||||
event('Time Range Updated', {
|
||||
type: range.type,
|
||||
upper: range.upper as string,
|
||||
lower: range.lower,
|
||||
})
|
||||
const updateRange = useCallback(
|
||||
range => {
|
||||
event('Time Range Updated', {
|
||||
type: range.type,
|
||||
upper: range.upper as string,
|
||||
lower: range.lower,
|
||||
})
|
||||
|
||||
update({
|
||||
range,
|
||||
} as TimeBlock)
|
||||
}
|
||||
update({
|
||||
range,
|
||||
} as TimeBlock)
|
||||
},
|
||||
[update]
|
||||
)
|
||||
|
||||
return useMemo(() => {
|
||||
return (
|
||||
|
@ -28,7 +31,7 @@ const TimeRangeDropdown: FC<TimeContextProps> = ({context, update}) => {
|
|||
onSetTimeRange={updateRange}
|
||||
/>
|
||||
)
|
||||
}, [range])
|
||||
}, [range, updateRange])
|
||||
}
|
||||
|
||||
export default TimeRangeDropdown
|
||||
|
|
|
@ -10,10 +10,11 @@ import {event} from 'src/notebooks/shared/event'
|
|||
interface Props {
|
||||
onClick?: () => void
|
||||
direction: 'up' | 'down'
|
||||
active: boolean
|
||||
}
|
||||
|
||||
const MovePanelUpButton: FC<Props> = ({onClick, direction}) => {
|
||||
const status = onClick ? ComponentStatus.Default : ComponentStatus.Disabled
|
||||
const MovePanelUpButton: FC<Props> = ({onClick, direction, active}) => {
|
||||
const status = active ? ComponentStatus.Default : ComponentStatus.Disabled
|
||||
const icon = direction === 'up' ? IconFont.CaretUp : IconFont.CaretDown
|
||||
|
||||
const handleClick = (e: MouseEvent<HTMLButtonElement>): void => {
|
||||
|
|
|
@ -44,15 +44,19 @@ const NotebookPanelHeader: FC<HeaderProps> = ({index, controls}) => {
|
|||
const canBeMovedUp = index > 0
|
||||
const canBeMovedDown = index < pipes.length - 1
|
||||
|
||||
const moveUp = useCallback(
|
||||
canBeMovedUp ? () => movePipe(index, index - 1) : null,
|
||||
[index, pipes]
|
||||
)
|
||||
const moveDown = useCallback(
|
||||
canBeMovedDown ? () => movePipe(index, index + 1) : null,
|
||||
[index, pipes]
|
||||
)
|
||||
const remove = useCallback(() => removePipe(index), [index, pipes])
|
||||
const moveUp = useCallback(() => {
|
||||
if (canBeMovedUp) {
|
||||
movePipe(index, index - 1)
|
||||
}
|
||||
}, [index, canBeMovedUp, movePipe])
|
||||
|
||||
const moveDown = useCallback(() => {
|
||||
if (canBeMovedDown) {
|
||||
movePipe(index, index + 1)
|
||||
}
|
||||
}, [index, canBeMovedDown, movePipe])
|
||||
|
||||
const remove = useCallback(() => removePipe(index), [removePipe, index])
|
||||
|
||||
return (
|
||||
<div className="notebook-panel--header">
|
||||
|
@ -71,8 +75,16 @@ const NotebookPanelHeader: FC<HeaderProps> = ({index, controls}) => {
|
|||
justifyContent={JustifyContent.FlexEnd}
|
||||
>
|
||||
{controls}
|
||||
<MovePanelButton direction="up" onClick={moveUp} />
|
||||
<MovePanelButton direction="down" onClick={moveDown} />
|
||||
<MovePanelButton
|
||||
direction="up"
|
||||
onClick={moveUp}
|
||||
active={canBeMovedUp}
|
||||
/>
|
||||
<MovePanelButton
|
||||
direction="down"
|
||||
onClick={moveDown}
|
||||
active={canBeMovedDown}
|
||||
/>
|
||||
<PanelVisibilityToggle index={index} />
|
||||
<RemovePanelButton onRemove={remove} />
|
||||
</FlexBox>
|
||||
|
@ -88,8 +100,10 @@ const NotebookPanel: FC<Props> = ({index, children, controls}) => {
|
|||
const isFocused = meta[index].focus
|
||||
|
||||
useEffect(() => {
|
||||
updateMeta(index, {panelRef} as PipeMeta)
|
||||
}, [])
|
||||
updateMeta(index, {
|
||||
panelRef,
|
||||
} as PipeMeta)
|
||||
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const panelClassName = classnames('notebook-panel', {
|
||||
[`notebook-panel__visible`]: isVisible,
|
||||
|
@ -99,9 +113,11 @@ const NotebookPanel: FC<Props> = ({index, children, controls}) => {
|
|||
|
||||
const updatePanelFocus = useCallback(
|
||||
(focus: boolean): void => {
|
||||
updateMeta(index, {focus} as PipeMeta)
|
||||
updateMeta(index, {
|
||||
focus,
|
||||
} as PipeMeta)
|
||||
},
|
||||
[index, meta]
|
||||
[index, meta] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
)
|
||||
|
||||
const handleClick = (e: MouseEvent<HTMLDivElement>): void => {
|
||||
|
|
|
@ -48,7 +48,7 @@ export const BucketProvider: FC<Props> = React.memo(
|
|||
}
|
||||
|
||||
lockAndLoad(getBuckets)
|
||||
}, [loading])
|
||||
}, [loading, getBuckets])
|
||||
|
||||
return (
|
||||
<BucketContext.Provider
|
||||
|
|
|
@ -79,9 +79,9 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
const [meta, setMeta] = useState(DEFAULT_CONTEXT.meta)
|
||||
const [results, setResults] = useState(DEFAULT_CONTEXT.results)
|
||||
|
||||
const _setPipes = useCallback(setPipes, [id])
|
||||
const _setMeta = useCallback(setMeta, [id])
|
||||
const _setResults = useCallback(setResults, [id])
|
||||
const _setPipes = useCallback(setPipes, [id, setPipes])
|
||||
const _setMeta = useCallback(setMeta, [id, setMeta])
|
||||
const _setResults = useCallback(setResults, [id, setResults])
|
||||
|
||||
const addPipe = useCallback(
|
||||
(pipe: PipeData, insertAtIndex?: number) => {
|
||||
|
@ -141,7 +141,7 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
_setPipes(add(pipe))
|
||||
}
|
||||
},
|
||||
[id, pipes, meta, results]
|
||||
[pipes, meta, results, _setPipes, _setMeta, _setResults]
|
||||
)
|
||||
|
||||
const updatePipe = useCallback(
|
||||
|
@ -154,7 +154,7 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
return pipes.slice()
|
||||
})
|
||||
},
|
||||
[id, pipes]
|
||||
[_setPipes]
|
||||
)
|
||||
|
||||
const updateMeta = useCallback(
|
||||
|
@ -167,7 +167,7 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
return pipes.slice()
|
||||
})
|
||||
},
|
||||
[id, meta]
|
||||
[_setMeta]
|
||||
)
|
||||
|
||||
const updateResult = useCallback(
|
||||
|
@ -179,7 +179,7 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
return pipes.slice()
|
||||
})
|
||||
},
|
||||
[id, results]
|
||||
[_setResults]
|
||||
)
|
||||
|
||||
const movePipe = useCallback(
|
||||
|
@ -201,7 +201,7 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
_setMeta(move)
|
||||
_setResults(move)
|
||||
},
|
||||
[id]
|
||||
[_setPipes, _setResults, _setMeta]
|
||||
)
|
||||
|
||||
const removePipe = useCallback(
|
||||
|
@ -214,7 +214,7 @@ export const NotebookProvider: FC = ({children}) => {
|
|||
_setMeta(remove)
|
||||
_setResults(remove)
|
||||
},
|
||||
[id]
|
||||
[_setPipes, _setMeta, _setResults]
|
||||
)
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Libraries
|
||||
import React, {FC, useEffect, useContext} from 'react'
|
||||
import React, {FC, useEffect, useContext, useCallback} from 'react'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -24,9 +24,12 @@ const BucketSelector: FC<Props> = ({onUpdate, data}) => {
|
|||
const selectedBucketName = data.bucketName
|
||||
const {buckets, loading} = useContext(BucketContext)
|
||||
|
||||
const updateBucket = (updatedBucket: Bucket): void => {
|
||||
onUpdate({bucketName: updatedBucket.name})
|
||||
}
|
||||
const updateBucket = useCallback(
|
||||
(updatedBucket: Bucket): void => {
|
||||
onUpdate({bucketName: updatedBucket.name})
|
||||
},
|
||||
[onUpdate]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
// selectedBucketName will only evaluate false on the initial render
|
||||
|
@ -34,7 +37,7 @@ const BucketSelector: FC<Props> = ({onUpdate, data}) => {
|
|||
if (!!buckets.length && !selectedBucketName) {
|
||||
updateBucket(buckets[0])
|
||||
}
|
||||
}, [buckets])
|
||||
}, [buckets, selectedBucketName, updateBucket])
|
||||
|
||||
let body
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ import BucketProvider from 'src/notebooks/context/buckets'
|
|||
import 'src/notebooks/pipes/Query/style.scss'
|
||||
|
||||
const DataSource: FC<PipeProp> = ({data, onUpdate, Context}) => {
|
||||
return useMemo(
|
||||
() => (
|
||||
return useMemo(() => {
|
||||
return (
|
||||
<BucketProvider>
|
||||
<Context>
|
||||
<FlexBox
|
||||
|
@ -28,9 +28,8 @@ const DataSource: FC<PipeProp> = ({data, onUpdate, Context}) => {
|
|||
</FlexBox>
|
||||
</Context>
|
||||
</BucketProvider>
|
||||
),
|
||||
[data.bucketName, data.timeStart, data.timeStop]
|
||||
)
|
||||
)
|
||||
}, [data, onUpdate])
|
||||
}
|
||||
|
||||
export default DataSource
|
||||
|
|
|
@ -37,7 +37,7 @@ const Query: FC<PipeProp> = ({data, onUpdate, Context, results}) => {
|
|||
<Results results={results} onUpdate={onUpdate} data={data} />
|
||||
</Context>
|
||||
),
|
||||
[query.text, results, data.panelVisibility, data.panelHeight]
|
||||
[query.text, results, data.panelVisibility, data.panelHeight] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,22 +7,21 @@ interface Props {
|
|||
|
||||
const Embedded: FC<Props> = ({uri, visible}) => {
|
||||
const parts = uri.split(':')
|
||||
|
||||
if (!visible) {
|
||||
return null
|
||||
}
|
||||
const p1 = parts[1]
|
||||
const p2 = parts[2]
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<iframe
|
||||
src={`https://open.spotify.com/embed/${parts[1]}/${parts[2]}`}
|
||||
width="600"
|
||||
height="80"
|
||||
frameBorder="0"
|
||||
allow="encrypted-media"
|
||||
/>
|
||||
),
|
||||
[uri]
|
||||
() =>
|
||||
visible && (
|
||||
<iframe
|
||||
src={`https://open.spotify.com/embed/${p1}/${p2}`}
|
||||
width="600"
|
||||
height="80"
|
||||
frameBorder="0"
|
||||
allow="encrypted-media"
|
||||
/>
|
||||
),
|
||||
[visible, p1, p2]
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, {FC, useEffect, useState} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {getDashboards} from 'src/dashboards/actions/thunks'
|
||||
import {
|
||||
createCellWithView,
|
||||
|
@ -66,16 +66,16 @@ const DashboardList: FC<Props> = ({
|
|||
properties,
|
||||
onClose,
|
||||
dashboards,
|
||||
loadDashboards,
|
||||
createView,
|
||||
createViewAndDashboard,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
const [selectedDashboard, setSelectedDashboard] = useState(null)
|
||||
const [newName, setNewName] = useState(DEFAULT_DASHBOARD_NAME)
|
||||
|
||||
useEffect(() => {
|
||||
loadDashboards()
|
||||
}, [])
|
||||
dispatch(getDashboards())
|
||||
}, [dispatch])
|
||||
|
||||
const isEditingName =
|
||||
selectedDashboard && selectedDashboard.id === DashboardTemplate.id
|
||||
|
@ -212,7 +212,6 @@ const mstp = (state: AppState) => {
|
|||
}
|
||||
|
||||
const mdtp = {
|
||||
loadDashboards: getDashboards,
|
||||
createView: createCellWithView,
|
||||
createViewAndDashboard: createDashboardWithView,
|
||||
notify: notifyAction,
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
// Libraries
|
||||
import React, {FC, useRef, useEffect, ReactNode, useState} from 'react'
|
||||
import React, {
|
||||
FC,
|
||||
useRef,
|
||||
useEffect,
|
||||
ReactNode,
|
||||
useState,
|
||||
useCallback,
|
||||
} from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components
|
||||
|
@ -60,39 +67,29 @@ const Resizer: FC<Props> = ({
|
|||
[`panel-resizer--body__${visibility}`]: resizingEnabled && visibility,
|
||||
})
|
||||
|
||||
const updateResultsStyle = (): void => {
|
||||
const updateResultsStyle = useCallback(() => {
|
||||
if (bodyRef.current && resizingEnabled && visibility === 'visible') {
|
||||
bodyRef.current.setAttribute('style', `height: ${size}px`)
|
||||
} else {
|
||||
bodyRef.current.setAttribute('style', '')
|
||||
}
|
||||
}
|
||||
}, [resizingEnabled, size, visibility])
|
||||
|
||||
const handleUpdateVisibility = (panelVisibility: Visibility): void => {
|
||||
onUpdate({panelVisibility})
|
||||
}
|
||||
|
||||
const handleUpdateHeight = (panelHeight: number): void => {
|
||||
onUpdate({panelHeight})
|
||||
}
|
||||
const handleUpdateHeight = useCallback(
|
||||
(panelHeight: number): void => {
|
||||
onUpdate({panelHeight})
|
||||
},
|
||||
[onUpdate]
|
||||
)
|
||||
|
||||
// Ensure results renders with proper height on initial render
|
||||
// Ensure styles update when state & props update
|
||||
useEffect(() => {
|
||||
updateResultsStyle()
|
||||
}, [])
|
||||
|
||||
// Update results height when associated props change
|
||||
useEffect(() => {
|
||||
updateResultsStyle()
|
||||
}, [size, visibility, resizingEnabled])
|
||||
|
||||
// Update local height when context height changes
|
||||
// so long as it is a different value
|
||||
useEffect(() => {
|
||||
if (height !== size) {
|
||||
updateSize(height)
|
||||
}
|
||||
}, [height])
|
||||
}, [updateResultsStyle])
|
||||
|
||||
// Handle changes in drag state
|
||||
useEffect(() => {
|
||||
|
@ -110,7 +107,7 @@ const Resizer: FC<Props> = ({
|
|||
)
|
||||
handleUpdateHeight(size)
|
||||
}
|
||||
}, [isDragging])
|
||||
}, [isDragging, size, handleUpdateHeight])
|
||||
|
||||
const handleMouseMove = (e: MouseEvent): void => {
|
||||
if (!bodyRef.current) {
|
||||
|
|
|
@ -48,7 +48,7 @@ const RuleMessage: FC<Props> = ({endpoints, rule}) => {
|
|||
if (!rule.endpointID && endpoints.length) {
|
||||
onSelectEndpoint(endpoints[0].id)
|
||||
}
|
||||
}, [])
|
||||
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<Grid.Row>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Libraries
|
||||
import React, {FC, Component, ComponentClass, useEffect} from 'react'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {useDispatch} from 'react-redux'
|
||||
import {OverlayID} from 'src/overlays/reducers/overlays'
|
||||
|
||||
// Actions
|
||||
|
@ -20,48 +20,36 @@ interface OwnProps {
|
|||
onClose: OverlayDismissalWithRoute
|
||||
}
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type OverlayHandlerProps = OwnProps & ReduxProps & RouteComponentProps
|
||||
type OverlayHandlerProps = OwnProps & RouteComponentProps
|
||||
|
||||
const OverlayHandler: FC<OverlayHandlerProps> = props => {
|
||||
const {
|
||||
overlayID,
|
||||
onShowOverlay,
|
||||
onClose,
|
||||
match,
|
||||
history,
|
||||
onDismissOverlay,
|
||||
} = props
|
||||
const {overlayID, onClose, match, history} = props
|
||||
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
const closer = () => {
|
||||
onClose(history, match.params)
|
||||
}
|
||||
|
||||
onShowOverlay(overlayID, match.params, closer)
|
||||
dispatch(showOverlay(overlayID, match.params, closer))
|
||||
|
||||
return () => onDismissOverlay()
|
||||
}, [overlayID])
|
||||
return () => dispatch(dismissOverlay())
|
||||
}, [overlayID]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onShowOverlay: showOverlay,
|
||||
onDismissOverlay: dismissOverlay,
|
||||
}
|
||||
const routedComponent = withRouter(OverlayHandler)
|
||||
|
||||
const connector = connect(null, mdtp)
|
||||
const connectedComponent = connector(withRouter(OverlayHandler))
|
||||
|
||||
export default connectedComponent
|
||||
export default routedComponent
|
||||
|
||||
interface RouteOverlayProps {
|
||||
overlayID: OverlayID
|
||||
}
|
||||
|
||||
export function RouteOverlay<P>(
|
||||
WrappedComponent: typeof connectedComponent,
|
||||
WrappedComponent: typeof routedComponent,
|
||||
overlayID: string,
|
||||
onClose?: OverlayDismissalWithRoute
|
||||
): ComponentClass<P> {
|
||||
|
|
|
@ -83,7 +83,7 @@ const DeleteDataForm: FC<Props> = ({
|
|||
if (filters.every(filter => filter.key !== '' && filter.value !== '')) {
|
||||
handleDeleteDataPreview()
|
||||
}
|
||||
}, [filters])
|
||||
}, [filters]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const formatPredicatesForPreview = (predicates: Filter[]) => {
|
||||
let result = ''
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useEffect} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {withRouter, RouteComponentProps} from 'react-router-dom'
|
||||
import {Overlay, SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
|
||||
|
||||
|
@ -26,19 +26,19 @@ const DeleteDataOverlay: FunctionComponent<Props> = ({
|
|||
match: {
|
||||
params: {orgID, bucketID},
|
||||
},
|
||||
resetPredicateState,
|
||||
setBucketAndKeys,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
const bucket = buckets.find(bucket => bucket.id === bucketID)
|
||||
const bucketName = bucket?.name
|
||||
|
||||
useEffect(() => {
|
||||
if (bucket) {
|
||||
setBucketAndKeys(bucket.name)
|
||||
if (bucketName) {
|
||||
dispatch(setBucketAndKeys(bucketName))
|
||||
}
|
||||
}, [])
|
||||
}, [bucketName, dispatch])
|
||||
|
||||
const handleDismiss = () => {
|
||||
resetPredicateState()
|
||||
dispatch(resetPredicateState())
|
||||
history.push(`/orgs/${orgID}/load-data/buckets/`)
|
||||
}
|
||||
|
||||
|
@ -65,11 +65,6 @@ const mstp = (state: AppState) => {
|
|||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
resetPredicateState,
|
||||
setBucketAndKeys,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
const connector = connect(mstp)
|
||||
|
||||
export default connector(withRouter(DeleteDataOverlay))
|
||||
|
|
|
@ -41,7 +41,7 @@ const DurationInput: FC<Props> = ({
|
|||
if (value != inputValue) {
|
||||
setInputValue(value)
|
||||
}
|
||||
}, [value])
|
||||
}, [value, inputValue])
|
||||
|
||||
const handleClickSuggestion = (suggestion: string) => {
|
||||
setInputValue(suggestion)
|
||||
|
|
|
@ -136,7 +136,7 @@ const ThresholdsSettings: FunctionComponent<Props> = ({
|
|||
if (state.isDirty && state.isValid) {
|
||||
onSetThresholds(state.thresholds)
|
||||
}
|
||||
}, [state])
|
||||
}, [state, onSetThresholds])
|
||||
|
||||
return (
|
||||
<FlexBox
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {useEffect, FC} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {Switch, Route} from 'react-router-dom'
|
||||
import GetOrganizations from 'src/shared/containers/GetOrganizations'
|
||||
|
||||
|
@ -11,7 +11,7 @@ import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
|
|||
import {RemoteDataState, AppState} from 'src/types'
|
||||
|
||||
// Actions
|
||||
import {getFlags as getFlagsAction} from 'src/shared/actions/flags'
|
||||
import {getFlags} from 'src/shared/actions/flags'
|
||||
|
||||
// Utils
|
||||
import {activeFlags} from 'src/shared/selectors/flags'
|
||||
|
@ -20,12 +20,13 @@ import {updateReportingContext} from 'src/cloud/utils/reporting'
|
|||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = ReduxProps
|
||||
|
||||
const GetFlags: FC<Props> = ({status, getFlags, flags}) => {
|
||||
const GetFlags: FC<Props> = ({status, flags}) => {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
if (status === RemoteDataState.NotStarted) {
|
||||
getFlags()
|
||||
dispatch(getFlags())
|
||||
}
|
||||
}, [])
|
||||
}, [dispatch, status])
|
||||
|
||||
useEffect(() => {
|
||||
updateReportingContext(
|
||||
|
@ -46,15 +47,11 @@ const GetFlags: FC<Props> = ({status, getFlags, flags}) => {
|
|||
)
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
getFlags: getFlagsAction,
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => ({
|
||||
flags: activeFlags(state),
|
||||
status: state.flags.status || RemoteDataState.NotStarted,
|
||||
})
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
const connector = connect(mstp)
|
||||
|
||||
export default connector(GetFlags)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {useEffect, FunctionComponent} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {Route, Switch} from 'react-router-dom'
|
||||
|
||||
// Components
|
||||
|
@ -12,21 +12,19 @@ import App from 'src/App'
|
|||
import {RemoteDataState, AppState} from 'src/types'
|
||||
|
||||
// Actions
|
||||
import {getOrganizations as getOrganizationsAction} from 'src/organizations/actions/thunks'
|
||||
import {getOrganizations} from 'src/organizations/actions/thunks'
|
||||
import RouteToOrg from './RouteToOrg'
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = ReduxProps
|
||||
|
||||
const GetOrganizations: FunctionComponent<Props> = ({
|
||||
status,
|
||||
getOrganizations,
|
||||
}) => {
|
||||
const GetOrganizations: FunctionComponent<Props> = ({status}) => {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
if (status === RemoteDataState.NotStarted) {
|
||||
getOrganizations()
|
||||
dispatch(getOrganizations())
|
||||
}
|
||||
}, [])
|
||||
}, [dispatch, status])
|
||||
|
||||
return (
|
||||
<SpinnerContainer loading={status} spinnerComponent={<TechnoSpinner />}>
|
||||
|
@ -39,14 +37,10 @@ const GetOrganizations: FunctionComponent<Props> = ({
|
|||
)
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
getOrganizations: getOrganizationsAction,
|
||||
}
|
||||
|
||||
const mstp = ({resources}: AppState) => ({
|
||||
status: resources.orgs.status,
|
||||
})
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
const connector = connect(mstp)
|
||||
|
||||
export default connector(GetOrganizations)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {useEffect, useState, FC} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
import {Route, Switch} from 'react-router-dom'
|
||||
|
||||
// Components
|
||||
|
@ -35,7 +35,7 @@ import {AppState, Organization, ResourceType} from 'src/types'
|
|||
import {CLOUD} from 'src/shared/constants'
|
||||
|
||||
// Actions
|
||||
import {setOrg as setOrgAction} from 'src/organizations/actions/creators'
|
||||
import {setOrg} from 'src/organizations/actions/creators'
|
||||
|
||||
// Utils
|
||||
import {updateReportingContext} from 'src/cloud/utils/reporting'
|
||||
|
@ -65,15 +65,16 @@ const SetOrg: FC<Props> = ({
|
|||
},
|
||||
orgs,
|
||||
history,
|
||||
setOrg,
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(RemoteDataState.Loading)
|
||||
const dispatch = useDispatch()
|
||||
const foundOrg = orgs.find(o => o.id === orgID)
|
||||
const firstOrgID = orgs[0]?.id
|
||||
|
||||
useEffect(() => {
|
||||
// does orgID from url match any orgs that exist
|
||||
const foundOrg = orgs.find(o => o.id === orgID)
|
||||
if (foundOrg) {
|
||||
setOrg(foundOrg)
|
||||
dispatch(setOrg(foundOrg))
|
||||
updateReportingContext({orgID: orgID})
|
||||
setLoading(RemoteDataState.Done)
|
||||
return
|
||||
|
@ -86,8 +87,8 @@ const SetOrg: FC<Props> = ({
|
|||
}
|
||||
|
||||
// else default to first org
|
||||
history.push(`/orgs/${orgs[0].id}`)
|
||||
}, [orgID, orgs.length])
|
||||
history.push(`/orgs/${firstOrgID}`)
|
||||
}, [orgID, firstOrgID, foundOrg, dispatch, history, orgs.length])
|
||||
|
||||
const orgPath = '/orgs/:orgID'
|
||||
|
||||
|
@ -179,16 +180,12 @@ const SetOrg: FC<Props> = ({
|
|||
)
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
setOrg: setOrgAction,
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const orgs = getAll<Organization>(state, ResourceType.Orgs)
|
||||
|
||||
return {orgs}
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
const connector = connect(mstp)
|
||||
|
||||
export default connector(SetOrg)
|
||||
|
|
|
@ -24,7 +24,7 @@ export const useMountedEffect = (
|
|||
}
|
||||
|
||||
return effect()
|
||||
}, inputs)
|
||||
}, inputs) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}
|
||||
|
||||
export const useMountedLayoutEffect = (
|
||||
|
@ -41,5 +41,5 @@ export const useMountedLayoutEffect = (
|
|||
}
|
||||
|
||||
return effect()
|
||||
}, inputs)
|
||||
}, inputs) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ export const useOneWayReducer = <R extends Reducer<any, any>>(
|
|||
|
||||
return reducer(state, action)
|
||||
},
|
||||
[]
|
||||
[reducer]
|
||||
)
|
||||
|
||||
const [reducerState, dispatch] = useReducer(wrappedReducer, defaultState)
|
||||
|
|
|
@ -47,7 +47,7 @@ export const useVisXDomainSettings = (
|
|||
}
|
||||
|
||||
return getValidRange(data, timeRange)
|
||||
}, [storedDomain, data])
|
||||
}, [storedDomain, data]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const [domain, setDomain] = useOneWayState(initialDomain)
|
||||
const resetDomain = () => setDomain(initialDomain)
|
||||
|
@ -95,7 +95,7 @@ export const useVisYDomainSettings = (
|
|||
return getRemainingRange(data, timeRange, storedDomain)
|
||||
}
|
||||
return storedDomain
|
||||
}, [storedDomain, data])
|
||||
}, [storedDomain, data]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const [domain, setDomain] = useOneWayState(initialDomain)
|
||||
const resetDomain = () => setDomain(initialDomain)
|
||||
|
|
|
@ -21,10 +21,6 @@ interface Props {
|
|||
}
|
||||
|
||||
const CommunityTemplateListGroup: FC<Props> = ({title, count, children}) => {
|
||||
if (!React.Children.count(children)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const [mode, setMode] = useState<'expanded' | 'collapsed'>('collapsed')
|
||||
const groupClassName = classnames('community-templates--list-group', {
|
||||
[`community-templates--list-group__${mode}`]: mode,
|
||||
|
@ -38,6 +34,10 @@ const CommunityTemplateListGroup: FC<Props> = ({title, count, children}) => {
|
|||
}
|
||||
}
|
||||
|
||||
if (!React.Children.count(children)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={groupClassName}>
|
||||
<div
|
||||
|
|
|
@ -7,7 +7,7 @@ import React, {
|
|||
useRef,
|
||||
useReducer,
|
||||
} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -26,10 +26,7 @@ import {
|
|||
} from 'src/cloud/utils/limits'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
checkBucketLimits as checkBucketLimitsAction,
|
||||
LimitStatus,
|
||||
} from 'src/cloud/actions/limits'
|
||||
import {checkBucketLimits, LimitStatus} from 'src/cloud/actions/limits'
|
||||
import {createBucket} from 'src/buckets/actions/thunks'
|
||||
|
||||
// Types
|
||||
|
@ -53,8 +50,8 @@ const SelectorListCreateBucket: FC<Props> = ({
|
|||
createBucket,
|
||||
isRetentionLimitEnforced,
|
||||
limitStatus,
|
||||
checkBucketLimits,
|
||||
}) => {
|
||||
const reduxDispatch = useDispatch()
|
||||
const triggerRef = useRef<HTMLButtonElement>(null)
|
||||
const [state, dispatch] = useReducer(
|
||||
createBucketReducer,
|
||||
|
@ -63,8 +60,8 @@ const SelectorListCreateBucket: FC<Props> = ({
|
|||
|
||||
useEffect(() => {
|
||||
// Check bucket limits when component mounts
|
||||
checkBucketLimits()
|
||||
}, [])
|
||||
reduxDispatch(checkBucketLimits())
|
||||
}, [reduxDispatch])
|
||||
|
||||
const limitExceeded = limitStatus === LimitStatus.EXCEEDED
|
||||
|
||||
|
@ -172,7 +169,6 @@ const mstp = (state: AppState) => {
|
|||
|
||||
const mdtp = {
|
||||
createBucket,
|
||||
checkBucketLimits: checkBucketLimitsAction,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Libraries
|
||||
import React, {useState, useEffect, FunctionComponent} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
import {connect, ConnectedProps, useDispatch} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import FluxToolbarSearch from 'src/timeMachine/components/FluxToolbarSearch'
|
||||
|
@ -30,14 +30,14 @@ type Props = OwnProps & ReduxProps
|
|||
const VariableToolbar: FunctionComponent<Props> = ({
|
||||
variables,
|
||||
onClickVariable,
|
||||
hydrateVariables,
|
||||
}) => {
|
||||
const dispatch = useDispatch()
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const filteredVariables = variables.filter(v => v.name.includes(searchTerm))
|
||||
|
||||
useEffect(() => {
|
||||
hydrateVariables()
|
||||
}, [])
|
||||
dispatch(hydrateVariables())
|
||||
}, [dispatch])
|
||||
|
||||
let content: JSX.Element | JSX.Element[] = (
|
||||
<EmptyState size={ComponentSize.ExtraSmall}>
|
||||
|
@ -72,10 +72,6 @@ const mstp = (state: AppState) => {
|
|||
return {variables: sortVariablesByName(variables)}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
hydrateVariables: hydrateVariables,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
const connector = connect(mstp)
|
||||
|
||||
export default connector(VariableToolbar)
|
||||
|
|
|
@ -4345,6 +4345,11 @@ eslint-plugin-jest@^23.0.2:
|
|||
dependencies:
|
||||
"@typescript-eslint/experimental-utils" "^2.5.0"
|
||||
|
||||
eslint-plugin-react-hooks@^4.0.5:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.5.tgz#4879003aa38e5d05d0312175beb6e4a1f617bfcf"
|
||||
integrity sha512-3YLSjoArsE2rUwL8li4Yxx1SUg3DQWp+78N3bcJQGWVZckcp+yeQGsap/MSq05+thJk57o+Ww4PtZukXGL02TQ==
|
||||
|
||||
eslint-plugin-react@^7.16.0:
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.16.0.tgz#9928e4f3e2122ed3ba6a5b56d0303ba3e41d8c09"
|
||||
|
|
Loading…
Reference in New Issue