From ad293912f946d1b5930e356ba3657ce152345655 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Tue, 20 Jan 2026 10:15:50 -0300 Subject: [PATCH 1/2] fix(frontend): add skip conditions for undefined environment ID queries RTK Query hooks were making API requests with undefined/empty environment IDs, causing 404 errors like: - GET /api/v1/environments/undefined/edge-identities/ - GET /api/v1/environments//featurestates/ Added skip conditions to prevent queries from executing when required parameters are missing: - IdentitySelect: skip useGetIdentitiesQuery when environmentId is undefined - CompareIdentities: skip useGetProjectFlagsQuery when envId or projectId is missing, and skip useGetIdentityFeatureStatesAllQuery when environmentId is undefined Fixes #6534 Fixes FLAGSMITH-FRONTEND-2FM Co-Authored-By: Claude Opus 4.5 --- frontend/web/components/CompareIdentities.tsx | 16 ++++++++++------ frontend/web/components/IdentitySelect.tsx | 15 ++++++++++----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/frontend/web/components/CompareIdentities.tsx b/frontend/web/components/CompareIdentities.tsx index e0aaf3630f0d..8481e0253e59 100644 --- a/frontend/web/components/CompareIdentities.tsx +++ b/frontend/web/components/CompareIdentities.tsx @@ -59,10 +59,14 @@ const CompareIdentities: FC = ({ }) => { const [leftId, setLeftId] = useState() const [rightId, setRightId] = useState() - const { data: projectFlags, refetch } = useGetProjectFlagsQuery({ - environment: ProjectStore.getEnvironmentIdFromKey(_environmentId), - project: projectId, - }) + const envId = ProjectStore.getEnvironmentIdFromKey(_environmentId) + const { data: projectFlags, refetch } = useGetProjectFlagsQuery( + { + environment: envId, + project: projectId, + }, + { skip: !envId || !projectId }, + ) const [environmentId, setEnvironmentId] = useState(_environmentId) const [showArchived, setShowArchived] = useState(false) @@ -74,11 +78,11 @@ const CompareIdentities: FC = ({ const { data: leftUser } = useGetIdentityFeatureStatesAllQuery( { environment: environmentId, user: `${leftId?.value}` }, - { skip: !leftId }, + { skip: !leftId || !environmentId }, ) const { data: rightUser } = useGetIdentityFeatureStatesAllQuery( { environment: environmentId, user: `${rightId?.value}` }, - { skip: !rightId }, + { skip: !rightId || !environmentId }, ) const [createCloneIdentityFeatureStates] = useCreateCloneIdentityFeatureStatesMutation() diff --git a/frontend/web/components/IdentitySelect.tsx b/frontend/web/components/IdentitySelect.tsx index 0a828f0c93b7..3557f66d377e 100644 --- a/frontend/web/components/IdentitySelect.tsx +++ b/frontend/web/components/IdentitySelect.tsx @@ -28,11 +28,16 @@ const IdentitySelect: FC = ({ const { data, isLoading, loadMore, searchItems } = useInfiniteScroll< Req['getIdentities'], Res['identities'] - >(useGetIdentitiesQuery, { - environmentId, - isEdge, - page_size: 10, - }) + >( + useGetIdentitiesQuery, + { + environmentId, + isEdge, + page_size: 10, + }, + 500, + { skip: !environmentId }, + ) const identityOptions = useMemo(() => { return filter( data?.results, From 49292834e72aa9a14115c57902fa30f761c58224 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Tue, 20 Jan 2026 10:20:42 -0300 Subject: [PATCH 2/2] fix(frontend): add guard in CompareEnvironments fetch for empty environment The fetch() method was being called from componentDidUpdate even when environmentRight was empty, causing API requests like: - GET /api/v1/environments//featurestates/?page_size=999 Added early return in fetch() when either environment is not selected. Co-Authored-By: Claude Opus 4.5 --- .../web/components/CompareEnvironments.js | 137 ++++++++++-------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/frontend/web/components/CompareEnvironments.js b/frontend/web/components/CompareEnvironments.js index 73f26916e178..a0dbe32ca2fa 100644 --- a/frontend/web/components/CompareEnvironments.js +++ b/frontend/web/components/CompareEnvironments.js @@ -44,6 +44,9 @@ class CompareEnvironments extends Component { } fetch = () => { + if (!this.state.environmentLeft || !this.state.environmentRight) { + return + } this.setState({ isLoading: true }) return Promise.all([ data.get( @@ -66,70 +69,76 @@ class CompareEnvironments extends Component { data.get( `${Project.api}environments/${this.state.environmentRight}/featurestates/?page_size=999`, ), - ]).then( - ([ - environmentLeftProjectFlags, - environmentRightProjectFlags, - environmentLeftFlags, - environmentRightFlags, - ]) => { - const changes = [] - const same = [] - _.each( - _.sortBy(environmentLeftProjectFlags.results, (p) => p.name), - (projectFlagLeft) => { - const projectFlagRight = environmentRightProjectFlags.results?.find( - (projectFlagRight) => projectFlagRight.id === projectFlagLeft.id, - ) - const leftSide = environmentLeftFlags.results.find( - (v) => v.feature === projectFlagLeft.id, - ) - const rightSide = environmentRightFlags.results.find( - (v) => v.feature === projectFlagLeft.id, - ) - const change = { - leftEnabled: leftSide.enabled, - leftEnvironmentFlag: leftSide, - leftValue: leftSide.feature_state_value, - projectFlagLeft, - projectFlagRight, - rightEnabled: rightSide.enabled, - rightEnvironmentFlag: rightSide, - rightValue: rightSide.feature_state_value, - } - change.enabledChanged = change.rightEnabled !== change.leftEnabled - change.valueChanged = change.rightValue !== change.leftValue - if ( - change.enabledChanged || - change.valueChanged || - projectFlagLeft.num_identity_overrides || - projectFlagLeft.num_segment_overrides || - projectFlagRight.num_identity_overrides || - projectFlagRight.num_segment_overrides - ) { - changes.push(change) - } else { - same.push(change) - } - }, - ) - this.setState({ - changes, - environmentLeftFlags: _.keyBy( - environmentLeftFlags.results, - 'feature', - ), - environmentRightFlags: _.keyBy( - environmentRightFlags.results, - 'feature', - ), - isLoading: false, - projectFlagsLeft: environmentLeftProjectFlags.results, - projectFlagsRight: environmentLeftProjectFlags.results, - same, - }) - }, - ) + ]) + .then( + ([ + environmentLeftProjectFlags, + environmentRightProjectFlags, + environmentLeftFlags, + environmentRightFlags, + ]) => { + const changes = [] + const same = [] + _.each( + _.sortBy(environmentLeftProjectFlags.results, (p) => p.name), + (projectFlagLeft) => { + const projectFlagRight = + environmentRightProjectFlags.results?.find( + (projectFlagRight) => + projectFlagRight.id === projectFlagLeft.id, + ) + const leftSide = environmentLeftFlags.results.find( + (v) => v.feature === projectFlagLeft.id, + ) + const rightSide = environmentRightFlags.results.find( + (v) => v.feature === projectFlagLeft.id, + ) + const change = { + leftEnabled: leftSide.enabled, + leftEnvironmentFlag: leftSide, + leftValue: leftSide.feature_state_value, + projectFlagLeft, + projectFlagRight, + rightEnabled: rightSide.enabled, + rightEnvironmentFlag: rightSide, + rightValue: rightSide.feature_state_value, + } + change.enabledChanged = change.rightEnabled !== change.leftEnabled + change.valueChanged = change.rightValue !== change.leftValue + if ( + change.enabledChanged || + change.valueChanged || + projectFlagLeft.num_identity_overrides || + projectFlagLeft.num_segment_overrides || + projectFlagRight.num_identity_overrides || + projectFlagRight.num_segment_overrides + ) { + changes.push(change) + } else { + same.push(change) + } + }, + ) + this.setState({ + changes, + environmentLeftFlags: _.keyBy( + environmentLeftFlags.results, + 'feature', + ), + environmentRightFlags: _.keyBy( + environmentRightFlags.results, + 'feature', + ), + isLoading: false, + projectFlagsLeft: environmentLeftProjectFlags.results, + projectFlagsRight: environmentLeftProjectFlags.results, + same, + }) + }, + ) + .catch(() => { + this.setState({ isLoading: false }) + }) } onSave = () => this.fetch()