2021-09-30 10:24:16 +02:00
|
|
|
import { useContext, useState } from 'react';
|
|
|
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
|
|
|
import { useStyles } from './ProjectEnvironment.styles';
|
|
|
|
|
|
|
|
import useLoading from '../../../hooks/useLoading';
|
|
|
|
import PageContent from '../../common/PageContent';
|
|
|
|
import AccessContext from '../../../contexts/AccessContext';
|
|
|
|
import HeaderTitle from '../../common/HeaderTitle';
|
|
|
|
import { UPDATE_PROJECT } from '../../AccessProvider/permissions';
|
|
|
|
|
|
|
|
import ApiError from '../../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';
|
|
|
|
import { FormControlLabel, FormGroup, Switch } from '@material-ui/core';
|
|
|
|
import useProjectApi from '../../../hooks/api/actions/useProjectApi/useProjectApi';
|
|
|
|
import EnvironmentDisableConfirm from './EnvironmentDisableConfirm/EnvironmentDisableConfirm';
|
2021-10-07 12:44:46 +02:00
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
import { Alert } from '@material-ui/lab';
|
|
|
|
|
2021-09-30 10:24:16 +02:00
|
|
|
|
|
|
|
export interface ProjectEnvironment {
|
|
|
|
name: string;
|
|
|
|
enabled: boolean;
|
|
|
|
}
|
|
|
|
|
2021-10-01 12:15:02 +02:00
|
|
|
interface ProjectEnvironmentListProps {
|
|
|
|
projectId: string;
|
|
|
|
}
|
|
|
|
|
2021-10-08 11:23:29 +02:00
|
|
|
const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => {
|
2021-09-30 10:24:16 +02:00
|
|
|
const { hasAccess } = useContext(AccessContext);
|
|
|
|
|
|
|
|
// api state
|
|
|
|
const { toast, setToastData } = useToast();
|
|
|
|
const { uiConfig } = useUiConfig();
|
2021-10-08 11:23:29 +02:00
|
|
|
const {
|
|
|
|
environments,
|
|
|
|
loading,
|
|
|
|
error,
|
|
|
|
refetch: refetchEnvs,
|
|
|
|
} = 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();
|
|
|
|
|
2021-09-30 10:24:16 +02:00
|
|
|
// local state
|
|
|
|
const [selectedEnv, setSelectedEnv] = useState<ProjectEnvironment>();
|
|
|
|
const [confirmName, setConfirmName] = useState('');
|
|
|
|
const ref = useLoading(loading);
|
|
|
|
const styles = useStyles();
|
|
|
|
|
2021-10-07 12:44:46 +02:00
|
|
|
|
2021-09-30 10:24:16 +02:00
|
|
|
const refetch = () => {
|
|
|
|
refetchEnvs();
|
|
|
|
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
|
|
|
|
|
|
|
const toggleEnv = async (env: ProjectEnvironment) => {
|
2021-10-08 11:23:29 +02:00
|
|
|
if (env.enabled) {
|
2021-09-30 10:24:16 +02:00
|
|
|
setSelectedEnv(env);
|
|
|
|
} else {
|
|
|
|
try {
|
2021-10-01 12:15:02 +02:00
|
|
|
await addEnvironmentToProject(projectId, env.name);
|
2021-10-08 11:23:29 +02:00
|
|
|
setToastData({
|
|
|
|
text: 'Environment successfully enabled.',
|
|
|
|
type: 'success',
|
|
|
|
show: true,
|
|
|
|
});
|
2021-09-30 10:24:16 +02:00
|
|
|
} catch (error) {
|
2021-10-08 11:23:29 +02:00
|
|
|
setToastData({
|
|
|
|
text: errorMsg(true),
|
|
|
|
type: 'error',
|
|
|
|
show: 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({
|
|
|
|
text: 'Environment successfully disabled.',
|
|
|
|
type: 'success',
|
|
|
|
show: true,
|
|
|
|
});
|
2021-09-30 10:24:16 +02:00
|
|
|
} catch (e) {
|
2021-10-08 11:23:29 +02:00
|
|
|
setToastData({
|
|
|
|
text: errorMsg(false),
|
|
|
|
type: 'error',
|
|
|
|
show: true,
|
|
|
|
});
|
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
|
|
|
|
|
|
|
const envs = environments.map(e => ({
|
|
|
|
name: e.name,
|
2021-10-08 11:23:29 +02:00
|
|
|
enabled: project?.environments.includes(e.name),
|
2021-09-30 10:24:16 +02:00
|
|
|
}));
|
|
|
|
|
2021-10-01 12:15:02 +02:00
|
|
|
const hasPermission = hasAccess(UPDATE_PROJECT, projectId);
|
2021-09-30 10:24:16 +02:00
|
|
|
|
|
|
|
const genLabel = (env: ProjectEnvironment) => (
|
|
|
|
<>
|
2021-10-08 11:23:29 +02:00
|
|
|
<code>{env.name}</code> environment is{' '}
|
|
|
|
<strong>{env.enabled ? 'enabled' : 'disabled'}</strong>
|
2021-09-30 10:24:16 +02:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
|
|
|
|
const renderEnvironments = () => {
|
2021-10-08 11:23:29 +02:00
|
|
|
if (!uiConfig.flags.E) {
|
|
|
|
return <p>Feature not enabled.</p>;
|
2021-09-30 10:24:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<FormGroup>
|
|
|
|
{envs.map(env => (
|
2021-10-08 11:23:29 +02:00
|
|
|
<FormControlLabel
|
|
|
|
key={env.name}
|
|
|
|
label={genLabel(env)}
|
|
|
|
control={
|
|
|
|
<Switch
|
|
|
|
size="medium"
|
|
|
|
disabled={!hasPermission}
|
|
|
|
checked={env.enabled}
|
|
|
|
onChange={toggleEnv.bind(this, env)}
|
|
|
|
/>
|
|
|
|
}
|
2021-09-30 10:24:16 +02:00
|
|
|
/>
|
|
|
|
))}
|
|
|
|
</FormGroup>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div ref={ref}>
|
|
|
|
<PageContent
|
|
|
|
headerContent={
|
|
|
|
<HeaderTitle
|
|
|
|
title={`Configure environments for "${project?.name}"`}
|
2021-10-07 12:44:46 +02:00
|
|
|
/>}
|
2021-09-30 10:24:16 +02:00
|
|
|
>
|
2021-10-07 12:44:46 +02:00
|
|
|
<Alert severity="info">
|
2021-10-08 13:49:55 +02:00
|
|
|
<b>Important!</b> In order for your application to retrieve feature toggle 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 {' '}
|
2021-10-07 12:44:46 +02:00
|
|
|
<Link
|
|
|
|
to='/admin/api'
|
|
|
|
>
|
|
|
|
here.
|
|
|
|
</Link>{' '}
|
|
|
|
<br/>
|
|
|
|
<br/>
|
|
|
|
Your administrator can configure an environment-specific API key and add it to your SDK if you can't find it on the list.
|
|
|
|
If you are an administrator you can create a new API key {' '}
|
|
|
|
<Link
|
|
|
|
to='/admin/api'
|
|
|
|
>
|
|
|
|
here.
|
|
|
|
</Link>{' '}
|
|
|
|
</Alert>
|
|
|
|
<br/>
|
2021-09-30 10:24:16 +02:00
|
|
|
<ConditionallyRender condition={error} show={renderError()} />
|
|
|
|
<div className={styles.container}>
|
|
|
|
<ConditionallyRender
|
|
|
|
condition={environments.length < 1 && !loading}
|
|
|
|
show={<div>No environments available.</div>}
|
|
|
|
elseShow={renderEnvironments()}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<EnvironmentDisableConfirm
|
|
|
|
env={selectedEnv}
|
|
|
|
open={!!selectedEnv}
|
|
|
|
handleDisableEnvironment={handleDisableEnvironment}
|
2021-10-08 11:23:29 +02:00
|
|
|
handleCancelDisableEnvironment={
|
|
|
|
handleCancelDisableEnvironment
|
|
|
|
}
|
2021-09-30 10:24:16 +02:00
|
|
|
confirmName={confirmName}
|
|
|
|
setConfirmName={setConfirmName}
|
|
|
|
/>
|
|
|
|
{toast}
|
|
|
|
</PageContent>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default ProjectEnvironmentList;
|