1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: connect project overview table to search api (#5237)

This commit is contained in:
Mateusz Kwasniewski 2023-11-01 12:05:42 +01:00 committed by GitHub
parent 598d022a5a
commit d074254b61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 18 deletions

View File

@ -72,6 +72,7 @@ interface IProjectFeatureTogglesProps {
features: IProject['features'];
environments: IProject['environments'];
loading: boolean;
onChange: () => void;
}
const staticColumns = ['Select', 'Actions', 'name', 'favorite'];
@ -84,6 +85,7 @@ export const ProjectFeatureToggles = ({
features,
loading,
environments: newEnvironments = [],
onChange,
}: IProjectFeatureTogglesProps) => {
const { classes: styles } = useStyles();
const theme = useTheme();
@ -118,7 +120,6 @@ export const ProjectFeatureToggles = ({
? [{ environment: 'a' }, { environment: 'b' }, { environment: 'c' }]
: newEnvironments,
);
const { refetch } = useProject(projectId);
const { isFavoritesPinned, sortTypes, onChangeIsFavoritePinned } =
usePinnedFavorites(
searchParams.has('favorites')
@ -140,9 +141,9 @@ export const ProjectFeatureToggles = ({
} else {
await favorite(projectId, feature.name);
}
refetch();
onChange();
},
[projectId, refetch],
[projectId, onChange],
);
const showTagsColumn = useMemo(
@ -263,7 +264,7 @@ export const ProjectFeatureToggles = ({
projectId,
name,
isChangeRequestEnabled,
refetch,
onChange,
onFeatureToggle,
);
@ -617,16 +618,14 @@ export const ProjectFeatureToggles = ({
isOpen={Boolean(featureStaleDialogState.featureId)}
onClose={() => {
setFeatureStaleDialogState({});
refetch();
onChange();
}}
featureId={featureStaleDialogState.featureId || ''}
projectId={projectId}
/>
<FeatureArchiveDialog
isOpen={Boolean(featureArchiveState)}
onConfirm={() => {
refetch();
}}
onConfirm={onChange}
onClose={() => {
setFeatureArchiveState(undefined);
}}

View File

@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import useProject, {
useProjectNameOrId,
} from 'hooks/api/getters/useProject/useProject';
@ -12,6 +12,7 @@ import { useLastViewedProject } from 'hooks/useLastViewedProject';
import { ProjectStats } from './ProjectStats/ProjectStats';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useUiFlag } from 'hooks/useUiFlag';
import { useFeatureSearch } from '../../../hooks/api/getters/useFeatureSearch/useFeatureSearch';
const refreshInterval = 15 * 1000;
@ -34,10 +35,50 @@ const StyledContentContainer = styled(Box)(() => ({
minWidth: 0,
}));
const InfiniteProjectOverview = () => {
const projectId = useRequiredPathParam('projectId');
const { project, loading: projectLoading } = useProject(projectId, {
refreshInterval,
});
const [nextCursor, setNextCursor] = useState('');
const {
features: searchFeatures,
refetch,
loading,
} = useFeatureSearch(nextCursor, projectId, { refreshInterval });
const { members, features, health, description, environments, stats } =
project;
return (
<StyledContainer>
<ProjectInfo
id={projectId}
description={description}
memberCount={members}
health={health}
features={features}
stats={stats}
/>
<StyledContentContainer>
<ProjectStats stats={project.stats} />
<StyledProjectToggles>
<ProjectFeatureToggles
key={loading ? 'loading' : 'ready'}
features={searchFeatures.features}
environments={environments}
loading={loading}
onChange={refetch}
/>
</StyledProjectToggles>
</StyledContentContainer>
</StyledContainer>
);
};
const ProjectOverview = () => {
const projectId = useRequiredPathParam('projectId');
const projectName = useProjectNameOrId(projectId);
const { project, loading } = useProject(projectId, {
const { project, loading, refetch } = useProject(projectId, {
refreshInterval,
});
const { members, features, health, description, environments, stats } =
@ -45,11 +86,14 @@ const ProjectOverview = () => {
usePageTitle(`Project overview ${projectName}`);
const { setLastViewed } = useLastViewedProject();
const featureSwitchRefactor = useUiFlag('featureSwitchRefactor');
const featureSearchFrontend = useUiFlag('featureSearchFrontend');
useEffect(() => {
setLastViewed(projectId);
}, [projectId, setLastViewed]);
if (featureSearchFrontend) return <InfiniteProjectOverview />;
return (
<StyledContainer>
<ProjectInfo
@ -71,6 +115,7 @@ const ProjectOverview = () => {
features={features}
environments={environments}
loading={loading}
onChange={refetch}
/>
)}
elseShow={() => (

View File

@ -13,14 +13,18 @@ interface IUseFeatureSearchOutput {
refetch: () => void;
}
const fallbackFeatures: { features: IFeatureToggleListItem[] } = {
const fallbackFeatures: { features: IFeatureToggleListItem[]; total: number } =
{
features: [],
total: 0,
};
export const useFeatureSearch = (
cursor: string,
projectId = '',
options: SWRConfiguration = {},
): IUseFeatureSearchOutput => {
const { KEY, fetcher } = getFeatureSearchFetcher();
const { KEY, fetcher } = getFeatureSearchFetcher(projectId, cursor);
const { data, error, mutate } = useSWR<IFeatureSearchResponse>(
KEY,
fetcher,
@ -39,9 +43,11 @@ export const useFeatureSearch = (
};
};
const getFeatureSearchFetcher = () => {
const getFeatureSearchFetcher = (projectId: string, cursor: string) => {
const KEY = `api/admin/search/features?projectId=${projectId}&cursor=${cursor}`;
const fetcher = () => {
const path = formatApiPath(`api/admin/search/features`);
const path = formatApiPath(KEY);
return fetch(path, {
method: 'GET',
})
@ -49,8 +55,6 @@ const getFeatureSearchFetcher = () => {
.then((res) => res.json());
};
const KEY = `api/admin/search/features`;
return {
fetcher,
KEY,

View File

@ -71,6 +71,8 @@ export type UiFlags = {
playgroundImprovements?: boolean;
featureSwitchRefactor?: boolean;
scheduledConfigurationChanges?: boolean;
featureSearchAPI?: boolean;
featureSearchFrontend?: boolean;
};
export interface IVersionInfo {

View File

@ -86,6 +86,7 @@ exports[`should create default config 1`] = `
"embedProxyFrontend": true,
"featureNamingPattern": false,
"featureSearchAPI": false,
"featureSearchFrontend": false,
"featureSwitchRefactor": false,
"featuresExportImport": true,
"filterInvalidClientMetrics": false,

View File

@ -36,6 +36,7 @@ export type IFlagKey =
| 'playgroundImprovements'
| 'featureSwitchRefactor'
| 'featureSearchAPI'
| 'featureSearchFrontend'
| 'scheduledConfigurationChanges';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
@ -168,6 +169,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_API,
false,
),
featureSearchFrontend: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FRONTEND,
false,
),
scheduledConfigurationChanges: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_SCHEDULED_CONFIGURATION_CHANGES,
false,

View File

@ -49,6 +49,7 @@ process.nextTick(async () => {
playgroundImprovements: true,
featureSwitchRefactor: true,
featureSearchAPI: true,
featureSearchFrontend: false,
},
},
authentication: {