1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

fix: avoid erasing previous environments data on refetch (#990)

* refactor: avoid duplicate useLoading call

* fix: avoid erasing previous environments data on refetch

* refactor: keep mutataion logic within useEnvironments
This commit is contained in:
olav 2022-05-18 11:26:38 +02:00 committed by GitHub
parent 159c54ed37
commit 98b6214c28
3 changed files with 85 additions and 84 deletions

View File

@ -26,7 +26,8 @@ const EnvironmentList = () => {
enabled: true, enabled: true,
protected: false, protected: false,
}; };
const { environments, refetchEnvironments } = useEnvironments(); const { environments, mutateEnvironments, refetchEnvironments } =
useEnvironments();
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
const { refetch: refetchProjectRolePermissions } = const { refetch: refetchProjectRolePermissions } =
useProjectRolePermissions(); useProjectRolePermissions();
@ -52,7 +53,7 @@ const EnvironmentList = () => {
const item = newEnvList.splice(dragIndex, 1)[0]; const item = newEnvList.splice(dragIndex, 1)[0];
newEnvList.splice(hoverIndex, 0, item); newEnvList.splice(hoverIndex, 0, item);
refetchEnvironments({ environments: newEnvList }, false); mutateEnvironments(newEnvList);
return newEnvList; return newEnvList;
}; };

View File

@ -1,28 +1,23 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './ProjectEnvironment.styles'; import { useStyles } from './ProjectEnvironment.styles';
import useLoading from 'hooks/useLoading';
import { PageContent } from 'component/common/PageContent/PageContent'; import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader'; import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions'; import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions';
import ApiError from 'component/common/ApiError/ApiError'; import ApiError from 'component/common/ApiError/ApiError';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments'; import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
import useProject from 'hooks/api/getters/useProject/useProject'; import useProject from 'hooks/api/getters/useProject/useProject';
import { FormControlLabel, FormGroup } from '@mui/material'; import { FormControlLabel, FormGroup, Alert } from '@mui/material';
import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi';
import EnvironmentDisableConfirm from './EnvironmentDisableConfirm/EnvironmentDisableConfirm'; import EnvironmentDisableConfirm from './EnvironmentDisableConfirm/EnvironmentDisableConfirm';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Alert } from '@mui/material';
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch'; import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
import { IProjectEnvironment } from 'interfaces/environments'; import { IProjectEnvironment } from 'interfaces/environments';
import { getEnabledEnvs } from './helpers'; import { getEnabledEnvs } from './helpers';
import StringTruncator from 'component/common/StringTruncator/StringTruncator'; import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { useThemeStyles } from 'themes/themeStyles'; import { useThemeStyles } from 'themes/themeStyles';
import { isDescendantOrSelf } from '@testing-library/user-event/dist/types/utils';
interface IProjectEnvironmentListProps { interface IProjectEnvironmentListProps {
projectId: string; projectId: string;
@ -45,7 +40,6 @@ const ProjectEnvironmentList = ({
// local state // local state
const [selectedEnv, setSelectedEnv] = useState<IProjectEnvironment>(); const [selectedEnv, setSelectedEnv] = useState<IProjectEnvironment>();
const [confirmName, setConfirmName] = useState(''); const [confirmName, setConfirmName] = useState('');
const ref = useLoading(loading);
const { classes: styles } = useStyles(); const { classes: styles } = useStyles();
const { isOss } = useUiConfig(); const { isOss } = useUiConfig();
@ -179,40 +173,35 @@ const ProjectEnvironmentList = ({
}; };
return ( return (
<div ref={ref}>
<PageContent <PageContent
header={ header={
<PageHeader <PageHeader
title={`Configure environments for "${project?.name}" project`} title={`Configure environments for "${project?.name}" project`}
/> />
} }
isLoading={loading}
> >
<ConditionallyRender <ConditionallyRender
condition={uiConfig.flags.E} condition={uiConfig.flags.E}
show={ show={
<div className={styles.container}> <div className={styles.container}>
<ConditionallyRender <ConditionallyRender
condition={error} condition={Boolean(error)}
show={renderError()} show={renderError()}
/> />
<Alert <Alert severity="info" style={{ marginBottom: '20px' }}>
severity="info" <b>Important!</b> In order for your application to
style={{ marginBottom: '20px' }} retrieve configured activation strategies for a
> specific environment, the application
<b>Important!</b> In order for your application <br /> must use an environment specific API key. You
to retrieve configured activation strategies for can look up the environment-specific API keys{' '}
a specific environment, the application <Link to="/admin/api">here.</Link>
<br /> must use an environment specific API key.
You can look up the environment-specific API
keys <Link to="/admin/api">here.</Link>
<br /> <br />
<br /> <br />
Your administrator can configure an Your administrator can configure an
environment-specific API key to be used in the environment-specific API key to be used in the SDK.
SDK. If you are an administrator you can{' '} If you are an administrator you can{' '}
<Link to="/admin/api"> <Link to="/admin/api">create a new API key.</Link>
create a new API key.
</Link>
</Alert> </Alert>
<ConditionallyRender <ConditionallyRender
condition={environments.length < 1 && !loading} condition={environments.length < 1 && !loading}
@ -222,9 +211,7 @@ const ProjectEnvironmentList = ({
<EnvironmentDisableConfirm <EnvironmentDisableConfirm
env={selectedEnv} env={selectedEnv}
open={Boolean(selectedEnv)} open={Boolean(selectedEnv)}
handleDisableEnvironment={ handleDisableEnvironment={handleDisableEnvironment}
handleDisableEnvironment
}
handleCancelDisableEnvironment={ handleCancelDisableEnvironment={
handleCancelDisableEnvironment handleCancelDisableEnvironment
} }
@ -240,7 +227,6 @@ const ProjectEnvironmentList = ({
} }
/> />
</PageContent> </PageContent>
</div>
); );
}; };

View File

@ -1,35 +1,49 @@
import useSWR, { mutate } from 'swr'; import useSWR from 'swr';
import { useCallback, useMemo } from 'react'; import { useMemo, useCallback } from 'react';
import { IEnvironmentResponse } from 'interfaces/environments'; import { IEnvironmentResponse, IEnvironment } from 'interfaces/environments';
import { formatApiPath } from 'utils/formatPath'; import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler'; import handleErrorResponses from '../httpErrorResponseHandler';
const PATH = formatApiPath(`api/admin/environments`); interface IUseEnvironmentsOutput {
environments: IEnvironment[];
loading: boolean;
error?: Error;
mutateEnvironments: (environments: IEnvironment[]) => Promise<void>;
refetchEnvironments: () => Promise<void>;
}
export const useEnvironments = () => { export const useEnvironments = (): IUseEnvironmentsOutput => {
const { data, error } = useSWR<IEnvironmentResponse>(PATH, fetcher); const { data, error, mutate } = useSWR<IEnvironmentResponse>(
formatApiPath(`api/admin/environments`),
const refetchEnvironments = useCallback( fetcher
(data?: IEnvironmentResponse, revalidate?: boolean) => {
mutate(PATH, data, revalidate).catch(console.warn);
},
[]
); );
const environments = useMemo(() => { const environments = useMemo(() => {
return data?.environments || []; return data?.environments || [];
}, [data]); }, [data]);
const refetchEnvironments = useCallback(async () => {
await mutate();
}, [mutate]);
const mutateEnvironments = useCallback(
async (environments: IEnvironment[]) => {
await mutate({ environments }, false);
},
[mutate]
);
return { return {
environments, environments,
refetchEnvironments, refetchEnvironments,
mutateEnvironments,
loading: !error && !data, loading: !error && !data,
error, error,
}; };
}; };
const fetcher = (): Promise<IEnvironmentResponse> => { const fetcher = (path: string): Promise<IEnvironmentResponse> => {
return fetch(PATH) return fetch(path)
.then(handleErrorResponses('Environments')) .then(handleErrorResponses('Environments'))
.then(res => res.json()); .then(res => res.json());
}; };