From 44ed7bea2f3f14842d1172475149d01f7b86c355 Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Wed, 29 Jan 2025 12:37:00 +0100 Subject: [PATCH] Persist insight type filter in Global scope --- .../FilterPanel/IssuesFilter/index.tsx | 23 ++++-- .../FilterPanel/IssuesFilter/types.ts | 1 + .../InsightsCatalog/InsightsPage/index.tsx | 18 +++-- .../Insights/InsightsCatalog/index.tsx | 26 +++++-- .../Insights/Issues/useIssuesFilters.ts | 14 +++- src/components/Insights/index.tsx | 70 +++++++++++++++++-- src/components/Insights/useInsightsData.ts | 6 +- src/store/insights/insightsSlice.ts | 5 ++ 8 files changed, 139 insertions(+), 24 deletions(-) diff --git a/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/index.tsx b/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/index.tsx index 2e8f80bbf..f4c7a6c44 100644 --- a/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/index.tsx +++ b/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/index.tsx @@ -22,8 +22,13 @@ import { trackingEvents } from "./tracking"; export const IssuesFilter = () => { const [isPopupOpen, setIsPopupOpen] = useState(false); - const { filteredInsightTypes, filters, viewMode, search } = - useInsightsSelector(); + const { + filteredInsightTypes: filteredInsightTypesInSpanScope, + filteredInsightTypesInGlobalScope, + filters, + viewMode, + search + } = useInsightsSelector(); const { selectedServices: globallySelectedServices, backendInfo, @@ -32,7 +37,9 @@ export const IssuesFilter = () => { } = useConfigSelector(); const { setSelectedServices: setGloballySelectedServices, - setInsightsFilteredInsightTypes: setFilteredInsightTypes, + setInsightsFilteredInsightTypes: setFilteredInsightTypesInSpanScope, + setInsightsFilteredInsightTypesInGlobalScope: + setFilteredInsightTypesInGlobalScope, setInsightsFilters: setFilters } = useStore.getState(); const [isCriticalOnly, setIsCriticalOnly] = useState( @@ -47,6 +54,9 @@ export const IssuesFilter = () => { const previousEnvironmentId = usePrevious(environmentId); const scopeSpanCodeObjectId = scope?.span?.spanCodeObjectId; const previousScopeSpanCodeObjectId = usePrevious(scopeSpanCodeObjectId); + const filteredInsightTypes = scopeSpanCodeObjectId + ? filteredInsightTypesInSpanScope + : filteredInsightTypesInGlobalScope; const isServicesFilterEnabled = Boolean( getFeatureFlagValue(backendInfo, FeatureFlag.ARE_ISSUES_FILTERS_ENABLED) @@ -141,7 +151,12 @@ export const IssuesFilter = () => { setIsPopupOpen(false); - setFilteredInsightTypes(selectedInsightTypes); + if (scopeSpanCodeObjectId) { + setFilteredInsightTypesInSpanScope(selectedInsightTypes); + } else { + setFilteredInsightTypesInGlobalScope(selectedInsightTypes); + } + setFilters([ ...(isCriticalOnly ? ["criticality"] : []), ...(isUnreadOnly ? ["unread"] : []) diff --git a/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/types.ts b/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/types.ts index 9374aa2e6..c675d5ab0 100644 --- a/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/types.ts +++ b/src/components/Insights/InsightsCatalog/FilterPanel/IssuesFilter/types.ts @@ -12,6 +12,7 @@ export interface IssuesFiltersData { export interface IssuesFilterQuery { issueTypes: string[]; + issueTypesInGlobalScope?: string[]; filters?: InsightFilterType[]; services?: string[]; } diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx b/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx index 69b295ad4..0f56ef2d4 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx +++ b/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx @@ -154,11 +154,22 @@ export const InsightsPage = ({ insightsViewType }: InsightsPageProps) => { const { scope, environment, backendInfo } = useConfigSelector(); - const { viewMode, search, filters, filteredInsightTypes } = - useInsightsSelector(); + const { + viewMode, + search, + filters, + filteredInsightTypes: filteredInsightTypesInSpanScope, + filteredInsightTypesInGlobalScope + } = useInsightsSelector(); const { setInsightsViewMode: setMode } = useStore.getState(); + const isAtSpan = Boolean(scope?.span); + const filteredInsightTypes = isAtSpan + ? filteredInsightTypesInSpanScope + : filteredInsightTypesInGlobalScope; const areAnyFiltersApplied = - filters.length > 0 || filteredInsightTypes.length > 0 || search.length > 0; + (insightsViewType === "Issues" + ? filters.length > 0 || filteredInsightTypes.length > 0 + : 0) || search.length > 0; const [isInsightJiraTicketHintShown, setIsInsightJiraTicketHintShown] = usePersistence( IS_INSIGHT_JIRA_TICKET_HINT_SHOWN_PERSISTENCE_KEY, @@ -166,7 +177,6 @@ export const InsightsPage = ({ ); const listRef = useRef(null); const { goTo } = useHistory(); - const isAtSpan = Boolean(scope?.span); const insightIndexWithJiraHint = getInsightToShowJiraHint(insights); diff --git a/src/components/Insights/InsightsCatalog/index.tsx b/src/components/Insights/InsightsCatalog/index.tsx index af37141b8..1b71fa2d6 100644 --- a/src/components/Insights/InsightsCatalog/index.tsx +++ b/src/components/Insights/InsightsCatalog/index.tsx @@ -56,7 +56,8 @@ export const InsightsCatalog = ({ search: searchInputValue, sorting, filters, - filteredInsightTypes, + filteredInsightTypes: filteredInsightTypesInSpanScope, + filteredInsightTypesInGlobalScope, data, viewMode: mode, insightViewType @@ -82,6 +83,9 @@ export const InsightsCatalog = ({ ); const scopeSpanCodeObjectId = scope?.span?.spanCodeObjectId; const isAtSpan = Boolean(scope?.span); + const filteredInsightTypes = isAtSpan + ? filteredInsightTypesInSpanScope + : filteredInsightTypesInGlobalScope; const theme = useTheme(); const { isMarkingAllAsReadInProgress, markAllAsRead } = useMarkingAllAsRead( scope?.span ?? null @@ -93,12 +97,22 @@ export const InsightsCatalog = ({ const isServicesFilterEnabled = !scopeSpanCodeObjectId; + const isIssuesView = insightViewType === "Issues"; + const appliedFilterCount = - filters.length + - (filteredInsightTypes.length > 0 ? 1 : 0) + - (isServicesFilterEnabled && selectedServices && selectedServices.length > 0 + (isIssuesView + ? filters.length + + (filteredInsightTypes.length > 0 ? 1 : 0) + + (isServicesFilterEnabled && + selectedServices && + selectedServices.length > 0 + ? 1 + : 0) + : 0) + + searchInputValue.length > + 0 ? 1 - : 0); + : 0; const areSpanEnvironmentsEnabled = getFeatureFlagValue( backendInfo, @@ -108,8 +122,6 @@ export const InsightsCatalog = ({ ? insightStats?.spanEnvironments ?? [] : environments?.map((x) => ({ environment: x })) ?? []; - const isIssuesView = insightViewType === "Issues"; - const isDismissalViewModeButtonVisible = isIssuesView && data && (isUndefined(dismissedCount) || dismissedCount > 0); // isUndefined - check for backward compatibility, always show when BE does not return this counter const isMarkingAsReadOptionsEnabled = diff --git a/src/components/Insights/Issues/useIssuesFilters.ts b/src/components/Insights/Issues/useIssuesFilters.ts index 9ebbadc9b..d530e8e3b 100644 --- a/src/components/Insights/Issues/useIssuesFilters.ts +++ b/src/components/Insights/Issues/useIssuesFilters.ts @@ -26,7 +26,8 @@ export const useIssuesFilters = () => { const { issuesFilters: data, search, - filteredInsightTypes, + filteredInsightTypes: filteredInsightTypesInSpanScope, + filteredInsightTypesInGlobalScope, viewMode, filters } = useInsightsSelector(); @@ -37,6 +38,17 @@ export const useIssuesFilters = () => { const { environment, scope, backendInfo } = useConfigSelector(); const environmentId = environment?.id; const spanCodeObjectId = scope?.span?.spanCodeObjectId ?? null; + const filteredInsightTypes = useMemo( + () => + spanCodeObjectId + ? filteredInsightTypesInSpanScope + : filteredInsightTypesInGlobalScope, + [ + spanCodeObjectId, + filteredInsightTypesInSpanScope, + filteredInsightTypesInGlobalScope + ] + ); const query: GetIssuesFiltersQuery = useMemo( () => ({ diff --git a/src/components/Insights/index.tsx b/src/components/Insights/index.tsx index ed8ea7585..42d71779a 100644 --- a/src/components/Insights/index.tsx +++ b/src/components/Insights/index.tsx @@ -55,19 +55,24 @@ export const Insights = ({ insightViewType }: InsightsProps) => { const { setInsightViewType, setInsightsFilteredInsightTypes: setFilteredInsightTypes, + setInsightsFilteredInsightTypesInGlobalScope: + setFilteredInsightTypesInGlobalScope, setInsightsFilters: setFilters, resetInsights: reset } = useStore.getState(); const { insightViewType: storedInsightViewType, - filteredInsightTypes, + filteredInsightTypes: filteredInsightTypesInSpanScope, + filteredInsightTypesInGlobalScope, filters } = useInsightsSelector(); - + const scopeSpanCodeObjectId = scope?.span?.spanCodeObjectId; + const filteredInsightTypes = scopeSpanCodeObjectId + ? filteredInsightTypesInSpanScope + : filteredInsightTypesInGlobalScope; const previousFilteredInsightTypes = usePrevious(filteredInsightTypes); const previousFilters = usePrevious(filters); const previousBackendInfo = usePrevious(backendInfo); - const scopeSpanCodeObjectId = scope?.span?.spanCodeObjectId; const previousScope = usePrevious(scope); const previousScopeSpanCodeObjectId = previousScope?.span?.spanCodeObjectId; const environmentId = environment?.id; @@ -103,6 +108,9 @@ export const Insights = ({ insightViewType }: InsightsProps) => { !isUndefined(persistedFilters) ) { setFilteredInsightTypes(persistedFilters?.issueTypes ?? []); + setFilteredInsightTypesInGlobalScope( + persistedFilters?.issueTypesInGlobalScope ?? [] + ); setFilters(persistedFilters?.filters ?? []); setAreFiltersRehydrated(true); } @@ -110,7 +118,8 @@ export const Insights = ({ insightViewType }: InsightsProps) => { previousPersistedFilters, persistedFilters, setFilters, - setFilteredInsightTypes + setFilteredInsightTypes, + setFilteredInsightTypesInGlobalScope ]); // Persist filters on its change @@ -121,7 +130,16 @@ export const Insights = ({ insightViewType }: InsightsProps) => { areFiltersRehydrated ) { setPersistedFilters({ - issueTypes: filteredInsightTypes, + ...(scopeSpanCodeObjectId + ? { + issueTypes: filteredInsightTypes ?? [], + issueTypesInGlobalScope: + persistedFilters?.issueTypesInGlobalScope ?? [] + } + : { + issueTypes: persistedFilters?.issueTypes ?? [], + issueTypesInGlobalScope: filteredInsightTypes + }), filters }); } @@ -132,7 +150,45 @@ export const Insights = ({ insightViewType }: InsightsProps) => { filters, setPersistedFilters, areFiltersRehydrated, - persistedFilters + persistedFilters, + scopeSpanCodeObjectId + ]); + + // Reset insight type filters (for span and global scopes) on backend instance, environment change + useEffect(() => { + if ( + (areFiltersRehydrated && + Boolean( + previousBackendInfo && + !areBackendInfosEqual(previousBackendInfo, backendInfo) + )) || + Boolean(previousEnvironmentId && previousEnvironmentId !== environmentId) + ) { + setFilteredInsightTypes([]); + setFilteredInsightTypesInGlobalScope([]); + } + }, [ + previousBackendInfo, + backendInfo, + areFiltersRehydrated, + setFilteredInsightTypes, + setFilteredInsightTypesInGlobalScope, + previousEnvironmentId, + environmentId + ]); + + // Reset insight type filter (for span scope) on scope change from span to global and vice versa + useEffect(() => { + if ( + (previousScopeSpanCodeObjectId && !scopeSpanCodeObjectId) || + (!previousScopeSpanCodeObjectId && scopeSpanCodeObjectId) + ) { + setFilteredInsightTypes([]); + } + }, [ + previousScopeSpanCodeObjectId, + scopeSpanCodeObjectId, + setFilteredInsightTypes ]); // Reset filters on backend instance, scope or environment change @@ -148,7 +204,6 @@ export const Insights = ({ insightViewType }: InsightsProps) => { ) || Boolean(previousEnvironmentId && previousEnvironmentId !== environmentId) ) { - setFilteredInsightTypes([]); setFilters([]); } }, [ @@ -160,6 +215,7 @@ export const Insights = ({ insightViewType }: InsightsProps) => { areFiltersRehydrated, persistedFilters, setFilteredInsightTypes, + setFilteredInsightTypesInGlobalScope, setFilters, previousEnvironmentId, environmentId diff --git a/src/components/Insights/useInsightsData.ts b/src/components/Insights/useInsightsData.ts index a1b137ddb..c39d8806d 100644 --- a/src/components/Insights/useInsightsData.ts +++ b/src/components/Insights/useInsightsData.ts @@ -145,7 +145,8 @@ export const useInsightsData = ({ sorting, viewMode, filters, - filteredInsightTypes, + filteredInsightTypes: filteredInsightTypesInSpanScope, + filteredInsightTypesInGlobalScope, isDataLoading: isLoading, insightViewType } = useInsightsSelector(); @@ -162,6 +163,9 @@ export const useInsightsData = ({ [selectedServices] ); const spanCodeObjectId = scope?.span?.spanCodeObjectId ?? null; + const filteredInsightTypes = spanCodeObjectId + ? filteredInsightTypesInSpanScope + : filteredInsightTypesInGlobalScope; const showDismissed = viewMode === ViewMode.OnlyDismissed; const isAppReadyToGetData = useMemo( () => diff --git a/src/store/insights/insightsSlice.ts b/src/store/insights/insightsSlice.ts index 1e6ed00e7..44ffe19fd 100644 --- a/src/store/insights/insightsSlice.ts +++ b/src/store/insights/insightsSlice.ts @@ -21,6 +21,7 @@ interface InsightsState { viewMode: ViewMode; filters: InsightFilterType[]; filteredInsightTypes: string[]; + filteredInsightTypesInGlobalScope: string[]; insightViewType: InsightViewType | null; issuesFilters: IssuesFiltersData | null; areIssuesFiltersLoading: boolean; @@ -38,6 +39,7 @@ const initialState: InsightsState = { viewMode: ViewMode.All, filters: [], filteredInsightTypes: [], + filteredInsightTypesInGlobalScope: [], insightViewType: null, issuesFilters: null, areIssuesFiltersLoading: false @@ -62,6 +64,9 @@ export const insightsSlice = createSlice({ setInsightsFilters: (filters: InsightFilterType[]) => set({ filters }), setInsightsFilteredInsightTypes: (filteredInsightTypes: string[]) => set({ filteredInsightTypes }), + setInsightsFilteredInsightTypesInGlobalScope: ( + filteredInsightTypesInGlobalScope: string[] + ) => set({ filteredInsightTypesInGlobalScope }), setInsightViewType: (insightViewType: InsightViewType) => set({ insightViewType }), setInsightsIssuesFilters: (issuesFilters: IssuesFiltersData) =>