2022-02-25 10:55:39 +01:00
|
|
|
import { useEffect, useState } from 'react';
|
2022-05-02 12:52:33 +02:00
|
|
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
2021-09-30 10:24:16 +02:00
|
|
|
import { useStyles } from './ProjectEnvironment.styles';
|
|
|
|
|
2022-03-28 10:49:59 +02:00
|
|
|
import useLoading from 'hooks/useLoading';
|
2022-05-09 14:38:12 +02:00
|
|
|
import { PageContent } from 'component/common/PageContent/PageContent';
|
|
|
|
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
2022-03-28 10:49:59 +02:00
|
|
|
import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions';
|
2021-09-30 10:24:16 +02:00
|
|
|
|
2022-03-28 10:49:59 +02:00
|
|
|
import ApiError from 'component/common/ApiError/ApiError';
|
|
|
|
import useToast from 'hooks/useToast';
|
|
|
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
|
|
|
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
|
|
|
|
import useProject from 'hooks/api/getters/useProject/useProject';
|
2022-05-02 15:52:41 +02:00
|
|
|
import { FormControlLabel, FormGroup } from '@mui/material';
|
2022-03-28 10:49:59 +02:00
|
|
|
import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi';
|
2021-09-30 10:24:16 +02:00
|
|
|
import EnvironmentDisableConfirm from './EnvironmentDisableConfirm/EnvironmentDisableConfirm';
|
2021-10-07 12:44:46 +02:00
|
|
|
import { Link } from 'react-router-dom';
|
2022-05-02 15:52:41 +02:00
|
|
|
import { Alert } from '@mui/material';
|
2022-03-28 10:49:59 +02:00
|
|
|
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
|
|
|
|
import { IProjectEnvironment } from 'interfaces/environments';
|
2021-11-04 14:24:36 +01:00
|
|
|
import { getEnabledEnvs } from './helpers';
|
2022-03-11 13:46:00 +01:00
|
|
|
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
|
2022-05-02 15:52:41 +02:00
|
|
|
import { useThemeStyles } from 'themes/themeStyles';
|
2021-09-30 10:24:16 +02:00
|
|
|
|
2022-04-26 10:53:46 +02:00
|
|
|
interface IProjectEnvironmentListProps {
|
2021-10-01 12:15:02 +02:00
|
|
|
projectId: string;
|
|
|
|
}
|
|
|
|
|
2022-04-26 10:53:46 +02:00
|
|
|
const ProjectEnvironmentList = ({
|
|
|
|
projectId,
|
|
|
|
}: IProjectEnvironmentListProps) => {
|
2021-09-30 10:24:16 +02:00
|
|
|
// api state
|
2022-02-25 10:55:39 +01:00
|
|
|
const [envs, setEnvs] = useState<IProjectEnvironment[]>([]);
|
2022-01-14 15:50:02 +01:00
|
|
|
const { setToastData, setToastApiError } = useToast();
|
2021-09-30 10:24:16 +02:00
|
|
|
const { uiConfig } = useUiConfig();
|
2022-03-23 12:55:00 +01:00
|
|
|
const { environments, loading, error, refetchEnvironments } =
|
|
|
|
useEnvironments();
|
2021-10-01 12:15:02 +02:00
|
|
|
const { project, refetch: refetchProject } = useProject(projectId);
|
2021-10-08 11:23:29 +02:00
|
|
|
const { removeEnvironmentFromProject, addEnvironmentToProject } =
|
|
|
|
useProjectApi();
|
2022-05-02 15:52:41 +02:00
|
|
|
const { classes: themeStyles } = useThemeStyles();
|
2021-10-08 11:23:29 +02:00
|
|
|
|
2021-09-30 10:24:16 +02:00
|
|
|
// local state
|
2021-11-04 14:24:36 +01:00
|
|
|
const [selectedEnv, setSelectedEnv] = useState<IProjectEnvironment>();
|
2021-09-30 10:24:16 +02:00
|
|
|
const [confirmName, setConfirmName] = useState('');
|
|
|
|
const ref = useLoading(loading);
|
2022-05-02 15:52:41 +02:00
|
|
|
const { classes: styles } = useStyles();
|
2021-09-30 10:24:16 +02:00
|
|
|
|
2021-11-04 14:24:36 +01:00
|
|
|
useEffect(() => {
|
|
|
|
const envs = environments.map(e => ({
|
|
|
|
name: e.name,
|
|
|
|
enabled: project?.environments.includes(e.name),
|
|
|
|
}));
|
|
|
|
|
|
|
|
setEnvs(envs);
|
|
|
|
}, [environments, project?.environments]);
|
|
|
|
|
2021-09-30 10:24:16 +02:00
|
|
|
const refetch = () => {
|
2022-03-23 12:55:00 +01:00
|
|
|
refetchEnvironments();
|
2021-09-30 10:24:16 +02:00
|
|
|
refetchProject();
|
2021-10-08 11:23:29 +02:00
|
|
|
};
|
2021-09-30 10:24:16 +02:00
|
|
|
|
|
|
|
const renderError = () => {
|
|
|
|
return (
|
|
|
|
<ApiError
|
|
|
|
onClick={refetch}
|
|
|
|
className={styles.apiError}
|
|
|
|
text="Error fetching environments"
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const errorMsg = (enable: boolean): string => {
|
2021-10-08 11:23:29 +02:00
|
|
|
return `Got an API error when trying to ${
|
|
|
|
enable ? 'enable' : 'disable'
|
|
|
|
} the environment.`;
|
|
|
|
};
|
2021-09-30 10:24:16 +02:00
|
|
|
|
2022-02-25 10:55:39 +01:00
|
|
|
const toggleEnv = async (env: IProjectEnvironment) => {
|
2021-10-08 11:23:29 +02:00
|
|
|
if (env.enabled) {
|
2021-11-04 14:24:36 +01:00
|
|
|
const enabledEnvs = getEnabledEnvs(envs);
|
|
|
|
|
|
|
|
if (enabledEnvs > 1) {
|
|
|
|
setSelectedEnv(env);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
setToastData({
|
2022-01-14 15:50:02 +01:00
|
|
|
title: 'One environment must be active',
|
2021-11-04 15:36:29 +01:00
|
|
|
text: 'You must always have at least one active environment per project',
|
2021-11-04 14:24:36 +01:00
|
|
|
type: 'error',
|
|
|
|
});
|
2021-09-30 10:24:16 +02:00
|
|
|
} else {
|
|
|
|
try {
|
2021-10-01 12:15:02 +02:00
|
|
|
await addEnvironmentToProject(projectId, env.name);
|
2021-10-08 11:23:29 +02:00
|
|
|
setToastData({
|
2022-01-14 15:50:02 +01:00
|
|
|
title: 'Environment enabled',
|
|
|
|
text: 'Environment successfully enabled. You can now use it to segment strategies in your feature toggles.',
|
2021-10-08 11:23:29 +02:00
|
|
|
type: 'success',
|
|
|
|
});
|
2021-09-30 10:24:16 +02:00
|
|
|
} catch (error) {
|
2022-01-14 15:50:02 +01:00
|
|
|
setToastApiError(errorMsg(true));
|
2021-09-30 10:24:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
refetch();
|
2021-10-08 11:23:29 +02:00
|
|
|
};
|
2021-09-30 10:24:16 +02:00
|
|
|
|
|
|
|
const handleDisableEnvironment = async () => {
|
2021-10-08 11:23:29 +02:00
|
|
|
if (selectedEnv && confirmName === selectedEnv.name) {
|
2021-09-30 10:24:16 +02:00
|
|
|
try {
|
2021-10-01 12:15:02 +02:00
|
|
|
await removeEnvironmentFromProject(projectId, selectedEnv.name);
|
2021-09-30 10:24:16 +02:00
|
|
|
setSelectedEnv(undefined);
|
|
|
|
setConfirmName('');
|
2021-10-08 11:23:29 +02:00
|
|
|
setToastData({
|
2022-01-14 15:50:02 +01:00
|
|
|
title: 'Environment disabled',
|
2021-10-08 11:23:29 +02:00
|
|
|
text: 'Environment successfully disabled.',
|
|
|
|
type: 'success',
|
|
|
|
});
|
2021-09-30 10:24:16 +02:00
|
|
|
} catch (e) {
|
2022-01-14 15:50:02 +01:00
|
|
|
setToastApiError(errorMsg(false));
|
2021-09-30 10:24:16 +02:00
|
|
|
}
|
2021-10-08 11:23:29 +02:00
|
|
|
|
2021-09-30 10:24:16 +02:00
|
|
|
refetch();
|
2021-10-08 11:23:29 +02:00
|
|
|
}
|
|
|
|
};
|
2021-09-30 10:24:16 +02:00
|
|
|
|
|
|
|
const handleCancelDisableEnvironment = () => {
|
|
|
|
setSelectedEnv(undefined);
|
|
|
|
setConfirmName('');
|
2021-10-08 11:23:29 +02:00
|
|
|
};
|
2021-09-30 10:24:16 +02:00
|
|
|
|
2022-02-25 10:55:39 +01:00
|
|
|
const genLabel = (env: IProjectEnvironment) => (
|
2022-05-02 15:52:41 +02:00
|
|
|
<div className={themeStyles.flexRow}>
|
2022-03-11 13:46:00 +01:00
|
|
|
<code>
|
|
|
|
<StringTruncator
|
|
|
|
text={env.name}
|
|
|
|
maxLength={50}
|
|
|
|
maxWidth="150"
|
|
|
|
/>
|
|
|
|
</code>
|
|
|
|
{/* This is ugly - but regular {" "} doesn't work here*/}
|
|
|
|
<p>
|
|
|
|
environment is{' '}
|
|
|
|
<strong>{env.enabled ? 'enabled' : 'disabled'}</strong>
|
|
|
|
</p>
|
|
|
|
</div>
|
2021-09-30 10:24:16 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
const renderEnvironments = () => {
|
|
|
|
return (
|
|
|
|
<FormGroup>
|
|
|
|
{envs.map(env => (
|
2021-10-08 11:23:29 +02:00
|
|
|
<FormControlLabel
|
|
|
|
key={env.name}
|
|
|
|
label={genLabel(env)}
|
|
|
|
control={
|
2021-10-21 13:25:39 +02:00
|
|
|
<PermissionSwitch
|
2021-11-04 14:24:36 +01:00
|
|
|
tooltip={`${
|
|
|
|
env.enabled ? 'Disable' : 'Enable'
|
|
|
|
} environment`}
|
2021-10-08 11:23:29 +02:00
|
|
|
size="medium"
|
2021-10-21 13:25:39 +02:00
|
|
|
projectId={projectId}
|
|
|
|
permission={UPDATE_PROJECT}
|
2021-10-08 11:23:29 +02:00
|
|
|
checked={env.enabled}
|
2021-11-04 14:24:36 +01:00
|
|
|
onChange={() => toggleEnv(env)}
|
2021-10-08 11:23:29 +02:00
|
|
|
/>
|
|
|
|
}
|
2021-09-30 10:24:16 +02:00
|
|
|
/>
|
|
|
|
))}
|
|
|
|
</FormGroup>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div ref={ref}>
|
|
|
|
<PageContent
|
2022-05-09 14:38:12 +02:00
|
|
|
header={
|
|
|
|
<PageHeader
|
2021-10-14 19:58:57 +02:00
|
|
|
title={`Configure environments for "${project?.name}" project`}
|
2021-10-19 13:08:25 +02:00
|
|
|
/>
|
|
|
|
}
|
2021-09-30 10:24:16 +02:00
|
|
|
>
|
2021-10-19 13:08:25 +02:00
|
|
|
<ConditionallyRender
|
|
|
|
condition={uiConfig.flags.E}
|
|
|
|
show={
|
|
|
|
<div className={styles.container}>
|
|
|
|
<ConditionallyRender
|
|
|
|
condition={error}
|
|
|
|
show={renderError()}
|
|
|
|
/>
|
|
|
|
<Alert
|
|
|
|
severity="info"
|
|
|
|
style={{ marginBottom: '20px' }}
|
2021-10-14 19:58:57 +02:00
|
|
|
>
|
2021-10-19 13:08:25 +02:00
|
|
|
<b>Important!</b> In order for your application
|
|
|
|
to retrieve configured activation strategies for
|
|
|
|
a specific environment, the application
|
|
|
|
<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 />
|
|
|
|
Your administrator can configure an
|
|
|
|
environment-specific API key to be used in the
|
|
|
|
SDK. If you are an administrator you can{' '}
|
|
|
|
<Link to="/admin/api">
|
|
|
|
create a new API key.
|
|
|
|
</Link>
|
|
|
|
</Alert>
|
|
|
|
<ConditionallyRender
|
|
|
|
condition={environments.length < 1 && !loading}
|
|
|
|
show={<div>No environments available.</div>}
|
|
|
|
elseShow={renderEnvironments()}
|
|
|
|
/>
|
|
|
|
<EnvironmentDisableConfirm
|
|
|
|
env={selectedEnv}
|
2022-05-02 12:52:33 +02:00
|
|
|
open={Boolean(selectedEnv)}
|
2021-10-19 13:08:25 +02:00
|
|
|
handleDisableEnvironment={
|
|
|
|
handleDisableEnvironment
|
|
|
|
}
|
|
|
|
handleCancelDisableEnvironment={
|
|
|
|
handleCancelDisableEnvironment
|
|
|
|
}
|
|
|
|
confirmName={confirmName}
|
|
|
|
setConfirmName={setConfirmName}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
elseShow={
|
|
|
|
<Alert security="success">
|
|
|
|
This feature has not been Unleashed for you yet.
|
2021-10-14 19:58:57 +02:00
|
|
|
</Alert>
|
2021-10-19 13:08:25 +02:00
|
|
|
}
|
|
|
|
/>
|
2021-09-30 10:24:16 +02:00
|
|
|
</PageContent>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default ProjectEnvironmentList;
|