mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
fix: avoid constraint accordion close on focus (#907)
* fix: avoid constraint accordion close on focus * refactor: fix mutate cache key mismatch
This commit is contained in:
parent
1fd6f2a60a
commit
49a63173f8
@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import { useRequiredQueryParam } from 'hooks/useRequiredQueryParam';
|
||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||
import { FeatureStrategyForm } from 'component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm';
|
||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
@ -23,6 +22,7 @@ import { CREATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/perm
|
||||
import { ISegment } from 'interfaces/segment';
|
||||
import { useSegmentsApi } from 'hooks/api/actions/useSegmentsApi/useSegmentsApi';
|
||||
import { formatStrategyName } from 'utils/strategyNames';
|
||||
import { useFeatureImmutable } from 'hooks/api/getters/useFeature/useFeatureImmutable';
|
||||
|
||||
export const FeatureStrategyCreate = () => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
@ -35,12 +35,16 @@ export const FeatureStrategyCreate = () => {
|
||||
|
||||
const { addStrategyToFeature, loading } = useFeatureStrategyApi();
|
||||
const { setStrategySegments } = useSegmentsApi();
|
||||
const { feature, refetchFeature } = useFeature(projectId, featureId);
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { uiConfig } = useUiConfig();
|
||||
const { unleashUrl } = uiConfig;
|
||||
const { push } = useHistory();
|
||||
|
||||
const { feature, refetchFeature } = useFeatureImmutable(
|
||||
projectId,
|
||||
featureId
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Fill in the default values once the strategies have been fetched.
|
||||
setStrategy(getStrategyObject(strategies, strategyName, featureId));
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||
import { FeatureStrategyForm } from 'component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm';
|
||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
@ -15,6 +14,7 @@ import { ISegment } from 'interfaces/segment';
|
||||
import { useSegmentsApi } from 'hooks/api/actions/useSegmentsApi/useSegmentsApi';
|
||||
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
|
||||
import { formatStrategyName } from 'utils/strategyNames';
|
||||
import { useFeatureImmutable } from 'hooks/api/getters/useFeature/useFeatureImmutable';
|
||||
|
||||
export const FeatureStrategyEdit = () => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
@ -25,13 +25,17 @@ export const FeatureStrategyEdit = () => {
|
||||
const [strategy, setStrategy] = useState<Partial<IFeatureStrategy>>({});
|
||||
const [segments, setSegments] = useState<ISegment[]>([]);
|
||||
const { updateStrategyOnFeature, loading } = useFeatureStrategyApi();
|
||||
const { feature, refetchFeature } = useFeature(projectId, featureId);
|
||||
const { setStrategySegments } = useSegmentsApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { uiConfig } = useUiConfig();
|
||||
const { unleashUrl } = uiConfig;
|
||||
const { push } = useHistory();
|
||||
|
||||
const { feature, refetchFeature } = useFeatureImmutable(
|
||||
projectId,
|
||||
featureId
|
||||
);
|
||||
|
||||
const {
|
||||
segments: savedStrategySegments,
|
||||
refetchSegments: refetchSavedStrategySegments,
|
||||
|
@ -1,11 +1,11 @@
|
||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||
import useSWR, { SWRConfiguration } from 'swr';
|
||||
import { useCallback } from 'react';
|
||||
import { emptyFeature } from './emptyFeature';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import { IFeatureToggle } from 'interfaces/featureToggle';
|
||||
|
||||
interface IUseFeatureOutput {
|
||||
export interface IUseFeatureOutput {
|
||||
feature: IFeatureToggle;
|
||||
refetchFeature: () => void;
|
||||
loading: boolean;
|
||||
@ -13,7 +13,7 @@ interface IUseFeatureOutput {
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
interface IFeatureResponse {
|
||||
export interface IFeatureResponse {
|
||||
status: number;
|
||||
body?: IFeatureToggle;
|
||||
}
|
||||
@ -23,19 +23,17 @@ export const useFeature = (
|
||||
featureId: string,
|
||||
options?: SWRConfiguration
|
||||
): IUseFeatureOutput => {
|
||||
const path = formatApiPath(
|
||||
`api/admin/projects/${projectId}/features/${featureId}`
|
||||
);
|
||||
const path = formatFeatureApiPath(projectId, featureId);
|
||||
|
||||
const { data, error } = useSWR<IFeatureResponse>(
|
||||
path,
|
||||
() => fetcher(path),
|
||||
const { data, error, mutate } = useSWR<IFeatureResponse>(
|
||||
['useFeature', path],
|
||||
() => featureFetcher(path),
|
||||
options
|
||||
);
|
||||
|
||||
const refetchFeature = useCallback(() => {
|
||||
mutate(path).catch(console.warn);
|
||||
}, [path]);
|
||||
mutate().catch(console.warn);
|
||||
}, [mutate]);
|
||||
|
||||
return {
|
||||
feature: data?.body || emptyFeature,
|
||||
@ -46,7 +44,9 @@ export const useFeature = (
|
||||
};
|
||||
};
|
||||
|
||||
const fetcher = async (path: string): Promise<IFeatureResponse> => {
|
||||
export const featureFetcher = async (
|
||||
path: string
|
||||
): Promise<IFeatureResponse> => {
|
||||
const res = await fetch(path);
|
||||
|
||||
if (res.status === 404) {
|
||||
@ -62,3 +62,12 @@ const fetcher = async (path: string): Promise<IFeatureResponse> => {
|
||||
body: await res.json(),
|
||||
};
|
||||
};
|
||||
|
||||
export const formatFeatureApiPath = (
|
||||
projectId: string,
|
||||
featureId: string
|
||||
): string => {
|
||||
return formatApiPath(
|
||||
`api/admin/projects/${projectId}/features/${featureId}`
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,36 @@
|
||||
import useSWRImmutable from 'swr/immutable';
|
||||
import { useCallback } from 'react';
|
||||
import { emptyFeature } from './emptyFeature';
|
||||
import {
|
||||
IUseFeatureOutput,
|
||||
IFeatureResponse,
|
||||
featureFetcher,
|
||||
formatFeatureApiPath,
|
||||
} from 'hooks/api/getters/useFeature/useFeature';
|
||||
|
||||
// useFeatureImmutable is like useFeature, except it won't refetch data on
|
||||
// focus/reconnect/remount. Useful for <form>s that need a stable copy of
|
||||
// the data. In particular, the lastSeenAt field may often change.
|
||||
export const useFeatureImmutable = (
|
||||
projectId: string,
|
||||
featureId: string
|
||||
): IUseFeatureOutput => {
|
||||
const path = formatFeatureApiPath(projectId, featureId);
|
||||
|
||||
const { data, error, mutate } = useSWRImmutable<IFeatureResponse>(
|
||||
['useFeatureImmutable', path],
|
||||
() => featureFetcher(path)
|
||||
);
|
||||
|
||||
const refetchFeature = useCallback(() => {
|
||||
mutate().catch(console.warn);
|
||||
}, [mutate]);
|
||||
|
||||
return {
|
||||
feature: data?.body || emptyFeature,
|
||||
refetchFeature,
|
||||
loading: !error && !data,
|
||||
status: data?.status,
|
||||
error,
|
||||
};
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||
import useSWR, { SWRConfiguration } from 'swr';
|
||||
import { useCallback } from 'react';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
@ -17,15 +17,15 @@ export const useFeatureEvents = (
|
||||
featureName: string,
|
||||
options?: SWRConfiguration
|
||||
): IUseEventsOutput => {
|
||||
const { data, error } = useSWR<{ events: IEvent[] }>(
|
||||
const { data, error, mutate } = useSWR<{ events: IEvent[] }>(
|
||||
[PATH, featureName],
|
||||
() => fetchFeatureEvents(featureName),
|
||||
options
|
||||
);
|
||||
|
||||
const refetchEvents = useCallback(() => {
|
||||
mutate(PATH).catch(console.warn);
|
||||
}, []);
|
||||
mutate().catch(console.warn);
|
||||
}, [mutate]);
|
||||
|
||||
return {
|
||||
events: data?.events || [],
|
||||
|
Loading…
Reference in New Issue
Block a user