mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-06 00:07:44 +01:00
eeda7ab5e4
* feat: create segmentation structure and list * feat: remove unused deps and change route * feat: change header style and add renderNoSegments * fix: style table header * feat: create useSegments hook * feat: add segmentApi hook * feat: create segment * fix: errors * feat: add contextfields list * fix: remove user from create segment api * feat: add form structure * feat: add SegmentFormStepOne * fix: tests and routes * feat: add constraint view * feat: UI to match the sketch * feat: add constraint on context select * fix: duplication * fix adding constraints Co-authored-by: olav <mail@olav.io> * fix: input date not showing up in constraint view Co-authored-by: olav <mail@olav.io> * fix: minor bugs Co-authored-by: olav <mail@olav.io> * fix: create context modal in segment page Co-authored-by: olav <mail@olav.io> * fix: validate constraint before create segment Co-authored-by: olav <mail@olav.io> * feat: create useSegment hook Co-authored-by: olav <mail@olav.io> * feat: create edit component Co-authored-by: olav <mail@olav.io> * refactor: move constraint validation endpoint * refactor: add missing route snapshot * refactor: fix segment constraints unsaved/editing state * refactor: remove create segment from mobile header menu * refactor: update segments form description * refactor: extract SegmentFormStepList component * refactor: add an optional FormTemplate docs link label * refactor: fix update segment payload * feat: finish edit component Co-authored-by: olav <mail@olav.io> * refactor: move step list above segment form * fix: update PR based on feedback Co-authored-by: olav <mail@olav.io> * refactor: fix constraint validation endpoint path * refactor: improve constraint state field name * refactor: extract AutocompleteBox component * feat: add strategy segment selection * refactor: add strategy segment previews * refactor: fix double section separator line * feat: disable deleting a usable segment * refactor: warn about segments without constraints * refactor: update text in delete segment dialogue * refactur: improve arg names * refactor: improve index var name * refactor: clarify steps list logic * refactor: use a required prop for the segment name * refactor: use ConditionallyRender for segment deletion * refactor: fix segments refetch * refactor: improve CreateUnleashContext component names * refactor: adjust segment form styles * refactor: adjust text * refactor: fix info icon tooltip hover target * refactor: add missing aria attrs to preview button * refactor: add strat name to delete segment modal * refactor: fix segment chip text alighment * refactor: use bulk endpoint for strategy segments * refactor: fix imports after merge Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com> Co-authored-by: olav <mail@olav.io>
182 lines
5.6 KiB
TypeScript
182 lines
5.6 KiB
TypeScript
import { useStyles } from './FormTemplate.styles';
|
|
import MenuBookIcon from '@material-ui/icons/MenuBook';
|
|
import Codebox from '../Codebox/Codebox';
|
|
import { Collapse, IconButton, useMediaQuery } from '@material-ui/core';
|
|
import { FileCopy, Info } from '@material-ui/icons';
|
|
import ConditionallyRender from '../ConditionallyRender';
|
|
import Loader from '../Loader/Loader';
|
|
import copy from 'copy-to-clipboard';
|
|
import useToast from 'hooks/useToast';
|
|
import React, { useState } from 'react';
|
|
import classNames from 'classnames';
|
|
import { ReactComponent as MobileGuidanceBG } from 'assets/img/mobileGuidanceBg.svg';
|
|
import { useCommonStyles } from 'common.styles';
|
|
|
|
interface ICreateProps {
|
|
title: string;
|
|
description: string;
|
|
documentationLink: string;
|
|
documentationLinkLabel?: string;
|
|
loading?: boolean;
|
|
modal?: boolean;
|
|
formatApiCode: () => string;
|
|
}
|
|
|
|
const FormTemplate: React.FC<ICreateProps> = ({
|
|
title,
|
|
description,
|
|
children,
|
|
documentationLink,
|
|
documentationLinkLabel,
|
|
loading,
|
|
modal,
|
|
formatApiCode,
|
|
}) => {
|
|
const { setToastData } = useToast();
|
|
const styles = useStyles();
|
|
const commonStyles = useCommonStyles();
|
|
const smallScreen = useMediaQuery(`(max-width:${1099}px)`);
|
|
|
|
const copyCommand = () => {
|
|
if (copy(formatApiCode())) {
|
|
setToastData({
|
|
title: 'Successfully copied the command',
|
|
text: 'The command should now be automatically copied to your clipboard',
|
|
autoHideDuration: 6000,
|
|
type: 'success',
|
|
show: true,
|
|
});
|
|
} else {
|
|
setToastData({
|
|
title: 'Could not copy the command',
|
|
text: 'Sorry, but we could not copy the command.',
|
|
autoHideDuration: 6000,
|
|
type: 'error',
|
|
show: true,
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<section
|
|
className={classNames(styles.container, modal && styles.modal)}
|
|
>
|
|
<ConditionallyRender
|
|
condition={smallScreen}
|
|
show={
|
|
<div className={commonStyles.relative}>
|
|
<MobileGuidance
|
|
description={description}
|
|
documentationLink={documentationLink}
|
|
documentationLinkLabel={documentationLinkLabel}
|
|
/>
|
|
</div>
|
|
}
|
|
/>
|
|
<div className={styles.formContent}>
|
|
<ConditionallyRender
|
|
condition={loading || false}
|
|
show={<Loader />}
|
|
elseShow={
|
|
<>
|
|
<h2 className={styles.title}>{title}</h2>
|
|
{children}
|
|
</>
|
|
}
|
|
/>{' '}
|
|
</div>
|
|
<ConditionallyRender
|
|
condition={!smallScreen}
|
|
show={
|
|
<Guidance
|
|
description={description}
|
|
documentationLink={documentationLink}
|
|
documentationLinkLabel={documentationLinkLabel}
|
|
>
|
|
<h3 className={styles.subtitle}>
|
|
API Command{' '}
|
|
<IconButton onClick={copyCommand}>
|
|
<FileCopy className={styles.icon} />
|
|
</IconButton>
|
|
</h3>
|
|
<Codebox text={formatApiCode()} />
|
|
</Guidance>
|
|
}
|
|
/>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
interface IMobileGuidance {
|
|
description: string;
|
|
documentationLink: string;
|
|
documentationLinkLabel?: string;
|
|
}
|
|
|
|
const MobileGuidance = ({
|
|
description,
|
|
documentationLink,
|
|
documentationLinkLabel,
|
|
}: IMobileGuidance) => {
|
|
const [open, setOpen] = useState(false);
|
|
const styles = useStyles();
|
|
|
|
return (
|
|
<>
|
|
<div className={styles.mobileGuidanceBgContainer}>
|
|
<MobileGuidanceBG className={styles.mobileGuidanceBackground} />
|
|
</div>
|
|
<IconButton
|
|
className={styles.mobileGuidanceButton}
|
|
onClick={() => setOpen(prev => !prev)}
|
|
>
|
|
<Info className={styles.infoIcon} />
|
|
</IconButton>
|
|
<Collapse in={open} timeout={500}>
|
|
<Guidance
|
|
description={description}
|
|
documentationLink={documentationLink}
|
|
documentationLinkLabel={documentationLinkLabel}
|
|
/>
|
|
</Collapse>
|
|
</>
|
|
);
|
|
};
|
|
|
|
interface IGuidanceProps {
|
|
description: string;
|
|
documentationLink: string;
|
|
documentationLinkLabel?: string;
|
|
}
|
|
|
|
const Guidance: React.FC<IGuidanceProps> = ({
|
|
description,
|
|
children,
|
|
documentationLink,
|
|
documentationLinkLabel = 'Learn more',
|
|
}) => {
|
|
const styles = useStyles();
|
|
|
|
return (
|
|
<aside className={styles.sidebar}>
|
|
<p className={styles.description}>{description}</p>
|
|
|
|
<div className={styles.linkContainer}>
|
|
<MenuBookIcon className={styles.linkIcon} />
|
|
<a
|
|
className={styles.documentationLink}
|
|
href={documentationLink}
|
|
rel="noopener noreferrer"
|
|
target="_blank"
|
|
>
|
|
{documentationLinkLabel}
|
|
</a>
|
|
</div>
|
|
|
|
{children}
|
|
</aside>
|
|
);
|
|
};
|
|
|
|
export default FormTemplate;
|