0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-21 21:49:51 +01:00

fix: react rule of hooks linting to error (#25232)

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Paul D'Ambra 2024-09-27 15:23:00 +01:00 committed by GitHub
parent af23230b97
commit d09bfce3d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 73 additions and 48 deletions

View File

@ -52,7 +52,7 @@ module.exports = {
'unused-imports',
],
rules: {
"react-hooks/rules-of-hooks": "warn",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
// PyCharm always adds curly braces, I guess vscode doesn't, PR reviewers often complain they are present on props that don't need them
// let's save the humans time and let the machines do the work

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -41,6 +41,7 @@ async function testSetup(
scope: ActivityScope,
url: string
): Promise<ReturnType<typeof activityLogLogic.build>> {
// eslint-disable-next-line react-hooks/rules-of-hooks
useMocks({
get: {
[url]: {

View File

@ -11,6 +11,7 @@ export function AlertDeletionWarning(): JSX.Element | null {
return null
}
// eslint-disable-next-line react-hooks/rules-of-hooks
const { shouldShowAlertDeletionWarning } = useValues(
alertsLogic({
insightShortId: insight.short_id,

View File

@ -479,13 +479,6 @@ export function ControlledDefinitionPopover({
group,
highlightedItemElement,
}: ControlledDefinitionPopoverContentsProps): JSX.Element | null {
// Supports all types specified in selectedItemHasPopover
const value = group.getValue?.(item)
if (!value || !item) {
return null
}
const { state, singularType, definition } = useValues(definitionPopoverLogic)
const { setDefinition } = useActions(definitionPopoverLogic)
@ -497,6 +490,13 @@ export function ControlledDefinitionPopover({
setDefinition(item)
}, [item])
// Supports all types specified in selectedItemHasPopover
const value = group.getValue?.(item)
if (!value || !item) {
return null
}
return (
<Popover
visible={visible}

View File

@ -50,6 +50,7 @@ export function LemonCollapse<K extends React.Key>({
let isPanelExpanded: (key: K) => boolean
let onPanelChange: (key: K, isExpanded: boolean) => void
if (props.multiple) {
// eslint-disable-next-line react-hooks/rules-of-hooks
const [localActiveKeys, setLocalActiveKeys] = useState<Set<K>>(new Set(props.defaultActiveKeys ?? []))
const effectiveActiveKeys = props.activeKeys ? new Set(props.activeKeys) : localActiveKeys
isPanelExpanded = (key: K) => effectiveActiveKeys.has(key)
@ -64,6 +65,7 @@ export function LemonCollapse<K extends React.Key>({
setLocalActiveKeys(newActiveKeys)
}
} else {
// eslint-disable-next-line react-hooks/rules-of-hooks
const [localActiveKey, setLocalActiveKey] = useState<K | null>(props.defaultActiveKey ?? null)
const effectiveActiveKey = props.activeKey ?? localActiveKey
isPanelExpanded = (key: K) => key === effectiveActiveKey

View File

@ -46,6 +46,7 @@ export const ToastTypes: Story = {
render: (args, { globals }) => {
const isDarkModeOn = globals.theme === 'dark'
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => {
lemonToast.dismiss()
args.toasts.forEach((toast) => {

View File

@ -134,16 +134,9 @@ export const AllProductsPlanComparison = ({
product: BillingProductV2Type
includeAddons?: boolean
}): JSX.Element | null => {
const plans = product.plans?.filter(
(plan) => !plan.included_if || plan.included_if == 'has_subscription' || plan.current_plan
)
if (plans?.length === 0) {
return null
}
const { billing, redirectPath, timeRemainingInSeconds, timeTotalInSeconds } = useValues(billingLogic)
const { ref: planComparisonRef } = useResizeObserver()
const { reportBillingUpgradeClicked, reportBillingDowngradeClicked } = useActions(eventUsageLogic)
const currentPlanIndex = plans.findIndex((plan) => plan.current_plan)
const { surveyID, comparisonModalHighlightedFeatureKey, billingProductLoading } = useValues(
billingProductLogic({ product })
)
@ -152,6 +145,14 @@ export const AllProductsPlanComparison = ({
)
const { featureFlags } = useValues(featureFlagLogic)
const plans = product.plans?.filter(
(plan) => !plan.included_if || plan.included_if == 'has_subscription' || plan.current_plan
)
if (plans?.length === 0) {
return null
}
const currentPlanIndex = plans.findIndex((plan) => plan.current_plan)
const nonInclusionProducts = billing?.products.filter((p) => !p.inclusion_only) || []
const inclusionProducts = billing?.products.filter((p) => !!p.inclusion_only) || []
const sortedProducts = nonInclusionProducts

View File

@ -112,17 +112,9 @@ export const PlanComparison = ({
product: BillingProductV2Type
includeAddons?: boolean
}): JSX.Element | null => {
const plans = product.plans?.filter(
(plan) => !plan.included_if || plan.included_if == 'has_subscription' || plan.current_plan
)
if (plans?.length === 0) {
return null
}
const fullyFeaturedPlan = plans[plans.length - 1]
const { billing, redirectPath, timeRemainingInSeconds, timeTotalInSeconds } = useValues(billingLogic)
const { width, ref: planComparisonRef } = useResizeObserver()
const { reportBillingUpgradeClicked, reportBillingDowngradeClicked } = useActions(eventUsageLogic)
const currentPlanIndex = plans.findIndex((plan) => plan.current_plan)
const { surveyID, comparisonModalHighlightedFeatureKey, billingProductLoading } = useValues(
billingProductLogic({ product })
)
@ -131,6 +123,15 @@ export const PlanComparison = ({
)
const { featureFlags } = useValues(featureFlagLogic)
const plans = product.plans?.filter(
(plan) => !plan.included_if || plan.included_if == 'has_subscription' || plan.current_plan
)
if (plans?.length === 0) {
return null
}
const currentPlanIndex = plans.findIndex((plan) => plan.current_plan)
const fullyFeaturedPlan = plans[plans.length - 1]
const ctaAction = billing?.subscription_level === 'custom' ? 'Subscribe' : 'Upgrade'
const upgradeButtons = plans?.map((plan, i) => {
return (

View File

@ -620,6 +620,7 @@ function UsageTab({ featureFlag }: { id: string; featureFlag: FeatureFlagType })
let dashboard: DashboardType<QueryBasedInsightModel> | null = null
if (dashboardId) {
// FIXME: Refactor out into <ConnectedDashboard />, as React hooks under conditional branches are no good
// eslint-disable-next-line react-hooks/rules-of-hooks
const dashboardLogicValues = useValues(
dashboardLogic({ id: dashboardId, placement: DashboardPlacement.FeatureFlag })
)

View File

@ -11,15 +11,14 @@ import { teamLogic } from 'scenes/teamLogic'
import { urls } from 'scenes/urls'
import { cohortsModel } from '~/models/cohortsModel'
import { groupsModel } from '~/models/groupsModel'
import { FeatureFlagType, OrganizationFeatureFlag } from '~/types'
import { groupsModel, type Noun } from '~/models/groupsModel'
import { CohortType, FeatureFlagType, OrganizationFeatureFlag, OrganizationType } from '~/types'
import { organizationLogic } from '../organizationLogic'
import { featureFlagLogic } from './featureFlagLogic'
import { groupFilters } from './FeatureFlags'
function checkHasStaticCohort(featureFlag: FeatureFlagType): boolean {
const { cohorts } = useValues(cohortsModel)
function checkHasStaticCohort(featureFlag: FeatureFlagType, cohorts: CohortType[]): boolean {
const staticCohorts = new Set()
cohorts.forEach((cohort) => {
if (cohort.is_static) {
@ -37,11 +36,15 @@ function checkHasStaticCohort(featureFlag: FeatureFlagType): boolean {
return false
}
const getColumns = (): LemonTableColumns<OrganizationFeatureFlag> => {
const { currentTeamId } = useValues(teamLogic)
const { currentOrganization } = useValues(organizationLogic)
const { aggregationLabel } = useValues(groupsModel)
const getColumns = ({
aggregationLabel,
currentTeamId,
currentOrganization,
}: {
aggregationLabel: (groupTypeIndex: number | null | undefined, deferToUserWording?: boolean) => Noun
currentTeamId: number | null
currentOrganization: OrganizationType | null
}): LemonTableColumns<OrganizationFeatureFlag> => {
return [
{
title: 'Project',
@ -133,8 +136,9 @@ function FeatureFlagCopySection(): JSX.Element {
const { setCopyDestinationProject, copyFlag } = useActions(featureFlagLogic)
const { currentOrganization } = useValues(organizationLogic)
const { currentTeam } = useValues(teamLogic)
const { cohorts } = useValues(cohortsModel)
const hasStaticCohort = checkHasStaticCohort(featureFlag)
const hasStaticCohort = checkHasStaticCohort(featureFlag, cohorts)
const hasMultipleProjects = (currentOrganization?.teams?.length ?? 0) > 1
return hasMultipleProjects && featureFlag.can_edit ? (
@ -198,6 +202,9 @@ function FeatureFlagCopySection(): JSX.Element {
export default function FeatureFlagProjects(): JSX.Element {
const { projectsWithCurrentFlag } = useValues(featureFlagLogic)
const { loadProjectsWithCurrentFlag } = useActions(featureFlagLogic)
const { currentTeamId } = useValues(teamLogic)
const { currentOrganization } = useValues(organizationLogic)
const { aggregationLabel } = useValues(groupsModel)
useEffect(() => {
loadProjectsWithCurrentFlag()
@ -210,7 +217,7 @@ export default function FeatureFlagProjects(): JSX.Element {
<LemonTable
loading={false}
dataSource={projectsWithCurrentFlag}
columns={getColumns()}
columns={getColumns({ currentTeamId, currentOrganization, aggregationLabel })}
emptyState="This feature flag is not being used in any other project."
/>
</div>

View File

@ -45,6 +45,9 @@ export function AggregationSelect({
const { querySource } = useValues(insightVizDataLogic(insightProps))
const { updateQuerySource } = useActions(insightVizDataLogic(insightProps))
const { groupTypes, aggregationLabel } = useValues(groupsModel)
const { needsUpgradeForGroups, canStartUsingGroups } = useValues(groupsAccessLogic)
if (!isInsightQueryNode(querySource)) {
return null
}
@ -64,8 +67,6 @@ export function AggregationSelect({
updateQuerySource({ aggregation_group_type_index: groupIndex } as FunnelsQuery)
}
}
const { groupTypes, aggregationLabel } = useValues(groupsModel)
const { needsUpgradeForGroups, canStartUsingGroups } = useValues(groupsAccessLogic)
const baseValues = [UNIQUE_USERS]
const optionSections: LemonSelectSection<string>[] = [

View File

@ -145,6 +145,8 @@ const cleanBreakdownParams = (cleanedParams: Partial<FilterType>, filters: Parti
// For the map, make sure we are breaking down by country
// Support automatic switching to country code breakdown both from no breakdown and from country name breakdown
cleanedParams['breakdown'] = '$geoip_country_code'
// this isn't a react hook
// eslint-disable-next-line react-hooks/rules-of-hooks
useMostRelevantBreakdownType(cleanedParams, filters)
return
}

View File

@ -112,10 +112,12 @@ export function PersonDisplay({
) : (
<Popover
overlay={
<PersonPreview
distinctId={person?.distinct_id || person?.distinct_ids?.[0]}
onClose={() => setVisible(false)}
/>
person?.distinct_id || person?.distinct_ids?.[0] ? (
<PersonPreview
distinctId={person?.distinct_id || person?.distinct_ids?.[0]}
onClose={() => setVisible(false)}
/>
) : null
}
visible={visible}
onClickOutside={() => setVisible(false)}

View File

@ -21,7 +21,7 @@ export function PersonPreview(props: PersonPreviewProps): JSX.Element | null {
if (!props.distinctId) {
return null
}
// eslint-disable-next-line react-hooks/rules-of-hooks
const { person, personLoading } = useValues(personLogic({ id: props.distinctId }))
if (personLoading) {

View File

@ -262,6 +262,7 @@ function pluginMenuItems(node: PluginBasedNode): LemonMenuItem[] {
}
export function pipelineNodeMenuCommonItems(node: Transformation | SiteApp | ImportApp | Destination): LemonMenuItem[] {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { canConfigurePlugins } = useValues(pipelineAccessLogic)
const items: LemonMenuItem[] = [
@ -295,6 +296,7 @@ export function pipelinePluginBackedNodeMenuCommonItems(
loadPluginConfigs: any,
inOverview?: boolean
): LemonMenuItem[] {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { canConfigurePlugins } = useValues(pipelineAccessLogic)
return [

View File

@ -176,7 +176,8 @@ const MenuActions = (): JSX.Element => {
useActions(sessionRecordingPlayerLogic)
const { fetchSimilarRecordings } = useActions(sessionRecordingDataLogic(logicProps))
const hasMobileExport = window.IMPERSONATED_SESSION || useFeatureFlag('SESSION_REPLAY_EXPORT_MOBILE_DATA')
const hasMobileExportFlag = useFeatureFlag('SESSION_REPLAY_EXPORT_MOBILE_DATA')
const hasMobileExport = window.IMPERSONATED_SESSION || hasMobileExportFlag
const hasSimilarRecordings = useFeatureFlag('REPLAY_SIMILAR_RECORDINGS')
const onDelete = (): void => {

View File

@ -145,14 +145,14 @@ export function Members(): JSX.Element | null {
const { preflight } = useValues(preflightLogic)
const { user } = useValues(userLogic)
if (!user) {
return null
}
useEffect(() => {
ensureAllMembersLoaded()
}, [])
if (!user) {
return null
}
const columns: LemonTableColumns<OrganizationMemberType> = [
{
key: 'user_profile_picture',

View File

@ -95,7 +95,8 @@ export function ToolbarInfoMenu(): JSX.Element | null {
const { visibleMenu, isDragging, menuProperties, minimized, isBlurred } = useValues(toolbarLogic)
const { setMenu } = useActions(toolbarLogic)
const { isAuthenticated } = useValues(toolbarConfigLogic)
const showExperiments = inStorybook() || inStorybookTestRunner() ? true : useToolbarFeatureFlag('web-experiments')
const showExperimentsFlag = useToolbarFeatureFlag('web-experiments')
const showExperiments = inStorybook() || inStorybookTestRunner() ? true : showExperimentsFlag
const content = minimized ? null : visibleMenu === 'flags' ? (
<FlagsToolbarMenu />
) : visibleMenu === 'heatmap' ? (
@ -153,7 +154,8 @@ export function Toolbar(): JSX.Element | null {
const { setVisibleMenu, toggleMinimized, onMouseOrTouchDown, setElement, setIsBlurred } = useActions(toolbarLogic)
const { isAuthenticated, userIntent } = useValues(toolbarConfigLogic)
const { authenticate } = useActions(toolbarConfigLogic)
const showExperiments = inStorybook() || inStorybookTestRunner() ? true : useToolbarFeatureFlag('web-experiments')
const showExperimentsFlag = useToolbarFeatureFlag('web-experiments')
const showExperiments = inStorybook() || inStorybookTestRunner() ? true : showExperimentsFlag
useEffect(() => {
setElement(ref.current)