diff --git a/frontend/src/app.css b/frontend/src/app.css index d72c55a6ec..a988c73e9f 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -16,6 +16,7 @@ body { .MuiButton-root { border-radius: 3px; text-transform: none; + font-size: 16px; } .skeleton { diff --git a/frontend/src/component/common/Dialogue/Dialogue.jsx b/frontend/src/component/common/Dialogue/Dialogue.jsx index 23c78205c2..89ac22840c 100644 --- a/frontend/src/component/common/Dialogue/Dialogue.jsx +++ b/frontend/src/component/common/Dialogue/Dialogue.jsx @@ -16,8 +16,11 @@ const Dialogue = ({ onClick, onClose, title, + style, primaryButtonText, + disabledPrimaryButton = false, secondaryButtonText, + maxWidth = 'sm', fullWidth = false, }) => { const styles = useStyles(); @@ -28,6 +31,7 @@ const Dialogue = ({ fullWidth={fullWidth} aria-labelledby={'simple-modal-title'} aria-describedby={'simple-modal-description'} + maxWidth={maxWidth} > <DialogTitle className={styles.dialogTitle}>{title}</DialogTitle> <ConditionallyRender @@ -48,6 +52,7 @@ const Dialogue = ({ variant="contained" onClick={onClick} autoFocus + disabled={disabledPrimaryButton} > {primaryButtonText || "Yes, I'm sure"} </Button> diff --git a/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNew.tsx b/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNew.tsx index 786de58387..bb5ae6ec57 100644 --- a/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNew.tsx +++ b/frontend/src/component/feature/FeatureToggleListNew/FeatureToggleListNew.tsx @@ -84,7 +84,7 @@ const FeatureToggleListNew = ({ )} align="left" > - <span data-loading>name</span> + <span data-loading>Name</span> </TableCell> <TableCell className={classnames( @@ -94,7 +94,7 @@ const FeatureToggleListNew = ({ )} align="left" > - <span data-loading>type</span> + <span data-loading>Type</span> </TableCell> {getEnvironments().map((env: any) => { return ( @@ -109,7 +109,7 @@ const FeatureToggleListNew = ({ > <span data-loading> {env.name === ':global:' - ? 'status' + ? 'Status' : env.name} </span> </TableCell> diff --git a/frontend/src/component/feature/strategy/AddStrategy/AddStrategy.jsx b/frontend/src/component/feature/strategy/AddStrategy/AddStrategy.jsx index fcf12ddecb..aad4357377 100644 --- a/frontend/src/component/feature/strategy/AddStrategy/AddStrategy.jsx +++ b/frontend/src/component/feature/strategy/AddStrategy/AddStrategy.jsx @@ -1,19 +1,12 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { - Button, - Dialog, - DialogContent, - DialogTitle, - DialogActions, - Typography, -} from '@material-ui/core'; +import { Typography } from '@material-ui/core'; import CreateStrategyCard from './AddStrategyCard/AddStrategyCard'; import { useStyles } from './AddStrategy.styles'; import ConditionallyRender from '../../../common/ConditionallyRender'; import { resolveDefaultParamValue } from './utils'; import { getHumanReadbleStrategy } from '../../../../utils/strategy-names'; +import Dialogue from '../../../common/Dialogue'; const AddStrategy = ({ strategies, @@ -98,49 +91,39 @@ const AddStrategy = ({ )); return ( - <Dialog + <Dialogue open={showCreateStrategy} + title="Add a new strategy" aria-labelledby="form-dialog-title" - fullWidth + onClose={() => setShowCreateStrategy(false)} + secondaryButtonText="Cancel" maxWidth="md" + fullWidth > - <DialogTitle id="form-dialog-title">Add a new strategy</DialogTitle> + <Typography variant="subtitle1" className={styles.subTitle}> + Built in strategies + </Typography> + <div className={styles.createStrategyCardContainer}> + {renderBuiltInStrategies()} + </div> - <DialogContent> - <Typography variant="subtitle1" className={styles.subTitle}> - Built in strategies - </Typography> - <div className={styles.createStrategyCardContainer}> - {renderBuiltInStrategies()} - </div> - - <ConditionallyRender - condition={customStrategies.length > 0} - show={ - <> - <Typography - variant="subtitle1" - className={styles.subTitle} - > - Custom strategies - </Typography> - <div className={styles.createStrategyCardContainer}> - {renderCustomStrategies()} - </div> - </> - } - /> - </DialogContent> - - <DialogActions> - <Button - color="secondary" - onClick={() => setShowCreateStrategy(false)} - > - Cancel - </Button> - </DialogActions> - </Dialog> + <ConditionallyRender + condition={customStrategies.length > 0} + show={ + <> + <Typography + variant="subtitle1" + className={styles.subTitle} + > + Custom strategies + </Typography> + <div className={styles.createStrategyCardContainer}> + {renderCustomStrategies()} + </div> + </> + } + /> + </Dialogue> ); }; diff --git a/frontend/src/component/feature/strategy/EditStrategyModal/EditStrategyModal.jsx b/frontend/src/component/feature/strategy/EditStrategyModal/EditStrategyModal.jsx index bf90bd4d7e..d90692eb11 100644 --- a/frontend/src/component/feature/strategy/EditStrategyModal/EditStrategyModal.jsx +++ b/frontend/src/component/feature/strategy/EditStrategyModal/EditStrategyModal.jsx @@ -1,12 +1,5 @@ -import React from 'react'; +import { useState } from 'react'; import PropTypes from 'prop-types'; -import { - Button, - Dialog, - DialogContent, - DialogTitle, - DialogActions, -} from '@material-ui/core'; import FlexibleStrategy from './FlexibleStrategy'; import DefaultStrategy from './default-strategy'; @@ -15,6 +8,7 @@ import GeneralStrategy from './general-strategy'; import StrategyConstraints from '../StrategyConstraint/StrategyConstraintInput'; import { getHumanReadbleStrategyName } from '../../../../utils/strategy-names'; +import Dialogue from '../../../common/Dialogue'; const EditStrategyModal = ({ onCancel, @@ -24,6 +18,8 @@ const EditStrategyModal = ({ strategyDefinition, context, }) => { + const [constraintError, setConstraintError] = useState({}); + const updateParameters = parameters => { const updatedStrategy = { ...strategy, parameters }; updateStrategy(updatedStrategy); @@ -57,47 +53,66 @@ const EditStrategyModal = ({ const { parameters } = strategy; + const disabledPrimaryButton = Object.keys(constraintError).some(key => { + return constraintError[key]; + }); + + const save = () => { + const { constraints } = strategy; + let valid = true; + + constraints.forEach((constraint, index) => { + const { values } = constraint; + + if (values.length === 0) { + setConstraintError(prev => ({ + ...prev, + [`${constraint.contextName}-${index}`]: + 'You need to specify at least one value', + })); + valid = false; + } + }); + + if (valid) { + saveStrategy(); + } + }; + return ( - <Dialog + <Dialogue open={!!strategy} aria-labelledby="form-dialog-title" fullWidth + onClose={onCancel} + onClick={save} + title={`Configure ${getHumanReadbleStrategyName( + strategy.name + )} strategy`} + primaryButtonText="Save" + secondaryButtonText="Cancel" maxWidth="md" + disabledPrimaryButton={disabledPrimaryButton} > - <DialogTitle id="form-dialog-title"> - Configure {getHumanReadbleStrategyName(strategy.name)} strategy - </DialogTitle> - <DialogContent> - <div> - <StrategyConstraints - updateConstraints={updateConstraints} - constraints={strategy.constraints || []} - /> - </div> - - <br /> - <br /> - <Type - parameters={parameters} - updateParameter={updateParameter} - strategyDefinition={strategyDefinition} - editable - context={context} + <div> + <StrategyConstraints + updateConstraints={updateConstraints} + constraints={strategy.constraints || []} + constraintError={constraintError} + setConstraintError={setConstraintError} /> - </DialogContent> - <DialogActions> - <Button onClick={onCancel} color="secondary"> - Cancel - </Button> - <Button - onClick={saveStrategy} - color="primary" - variant="contained" - > - Save - </Button> - </DialogActions> - </Dialog> + </div> + + <br /> + <br /> + <Type + parameters={parameters} + updateParameter={updateParameter} + strategyDefinition={strategyDefinition} + editable + context={context} + /> + </Dialogue> ); }; diff --git a/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInput/StrategyConstraintInput.jsx b/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInput/StrategyConstraintInput.jsx index f977349557..005dbfc7a5 100644 --- a/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInput/StrategyConstraintInput.jsx +++ b/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInput/StrategyConstraintInput.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Tooltip, Typography } from '@material-ui/core'; +import { Button, Tooltip, Typography } from '@material-ui/core'; import { Info } from '@material-ui/icons'; import StrategyConstraintInputField from '../StrategyConstraintInputField'; @@ -12,6 +12,8 @@ const StrategyConstraintInput = ({ contextNames, contextFields, enabled, + constraintError, + setConstraintError, }) => { const commonStyles = useCommonStyles(); const addConstraint = evt => { @@ -71,18 +73,21 @@ const StrategyConstraintInput = ({ contextFields={contextFields} updateConstraint={updateConstraint(index)} removeConstraint={removeConstraint(index)} + constraintError={constraintError} + setConstraintError={setConstraintError} /> ))} </tbody> </table> <small> - <a - href="#add-constraint" + <Button title="Add constraint" + variant="contained" + color="primary" onClick={addConstraint} > Add constraint - </a> + </Button> </small> </div> ); diff --git a/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.jsx b/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.jsx index 1671b20409..c58e3ff678 100644 --- a/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.jsx +++ b/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useEffect } from 'react'; import PropTypes from 'prop-types'; import { IconButton, TextField } from '@material-ui/core'; import { Autocomplete } from '@material-ui/lab'; @@ -20,27 +20,47 @@ const StrategyConstraintInputField = ({ updateConstraint, removeConstraint, contextFields, + id, + constraintError, + setConstraintError, }) => { - const [error, setError] = useState(); - const commonStyles = useCommonStyles(); - const styles = useStyles(); - const onBlur = evt => { - evt.preventDefault(); + useEffect(() => { + return () => { + resetError(); + }; + /*eslint-disable-next-line */ + }, []); + + const checkError = () => { const values = constraint.values; const filtered = values.filter(v => v).map(v => v.trim()); if (filtered.length !== values.length) { updateConstraint(filtered, 'values'); } if (filtered.length === 0) { - setError('You need to specify at least one value'); + setConstraintError(prev => ({ + ...prev, + [id]: 'You need to specify at least one value', + })); } else { - setError(undefined); + resetError(); } }; + const resetError = () => + setConstraintError(prev => ({ ...prev, [id]: undefined })); + + const commonStyles = useCommonStyles(); + const styles = useStyles(); + const onBlur = evt => { + evt.preventDefault(); + checkError(); + }; + const handleChangeValue = selectedOptions => { const values = selectedOptions ? selectedOptions.map(o => o.value) : []; updateConstraint(values, 'values'); + checkError(); }; const constraintContextNames = contextFields.map(f => ({ @@ -59,9 +79,11 @@ const StrategyConstraintInputField = ({ : undefined; const values = constraint.values.map(v => ({ value: v, label: v })); + const error = constraintError[id]; + return ( <tr className={commonStyles.contentSpacingY}> - <td> + <td className={styles.tableCell}> <MySelect name="contextName" label="Context Field" @@ -73,7 +95,7 @@ const StrategyConstraintInputField = ({ className={styles.contextField} /> </td> - <td> + <td className={styles.tableCell}> <MySelect name="operator" label="Operator" @@ -85,52 +107,74 @@ const StrategyConstraintInputField = ({ className={styles.operator} /> </td> - <td style={{ width: '100%' }}> + <td className={styles.tableCell} style={{ width: '100%' }}> <ConditionallyRender condition={options} show={ - <Autocomplete - multiple - size="small" - options={options} - value={values || []} - getOptionLabel={option => option.label} - getOptionSelected={(option, value) => - option.value === value.value - } - filterSelectedOptions - filterOptions={options => - options.filter( - o => !values.some(v => v.value === o.value) - ) - } - onChange={(evt, values) => - handleChangeValue(values) - } - renderInput={params => ( - <TextField - {...params} - variant="outlined" - label="Values" - /> - )} - /> + <div className={styles.inputContainer}> + <Autocomplete + multiple + size="small" + options={options} + value={values || []} + getOptionLabel={option => option.label} + onBlur={onBlur} + onFocus={() => resetError()} + getOptionSelected={(option, value) => + option.value === value.value + } + filterSelectedOptions + filterOptions={options => + options.filter( + o => + !values.some( + v => v.value === o.value + ) + ) + } + onChange={(evt, values) => + handleChangeValue(values) + } + renderInput={params => ( + <TextField + {...params} + variant="outlined" + label={'Values'} + error={Boolean(error)} + helperText={error} + FormHelperTextProps={{ + classes: { + root: styles.helperText, + }, + }} + /> + )} + /> + </div> } elseShow={ - <InputListField - name="values" - error={error} - onBlur={onBlur} - values={constraint.values} - label="Values (v1, v2, v3)" - updateValues={values => - updateConstraint(values, 'values') - } - /> + <div className={styles.inputContainer}> + <InputListField + name="values" + error={Boolean(error)} + onBlur={onBlur} + values={constraint.values} + label="Values (v1, v2, v3)" + updateValues={values => + updateConstraint(values, 'values') + } + helperText={error} + FormHelperTextProps={{ + classes: { + root: styles.helperText, + }, + }} + /> + </div> } /> </td> - <td> + <td className={styles.tableCell}> <IconButton onClick={removeConstraint}> <Delete /> </IconButton> diff --git a/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.styles.js b/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.styles.js index 6bbfae29da..8a604270ff 100644 --- a/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.styles.js +++ b/frontend/src/component/feature/strategy/StrategyConstraint/StrategyConstraintInputField/StrategyConstraintInputField.styles.js @@ -7,4 +7,21 @@ export const useStyles = makeStyles({ operator: { minWidth: '105px', }, + inputContainer: { + position: 'relative', + }, + inputError: { + position: 'absolute', + fontSize: '0.9rem', + color: 'red', + top: '10px', + left: '12px', + }, + tableCell: { + paddingBottom: '1.25rem', + }, + helperText: { + position: 'absolute', + top: '35px', + }, }); diff --git a/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx b/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx index b857026722..90d210aff8 100644 --- a/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx +++ b/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx @@ -187,6 +187,8 @@ const AddVariant = ({ primaryButtonText="Save" secondaryButtonText="Cancel" title={title} + fullWidth + maxWidth="md" > <form onSubmit={submit} className={commonStyles.contentSpacingY}> <p style={{ color: 'red' }}>{error.general}</p> @@ -195,6 +197,7 @@ const AddVariant = ({ name="name" placeholder="" className={commonStyles.fullWidth} + style={{ maxWidth: '350px' }} helperText={error.name} value={data.name || ''} error={Boolean(error.name)} @@ -250,11 +253,17 @@ const AddVariant = ({ title="Passed to the variant object. Can be anything (json, value, csv)" > - <Info style={{ width: '18.5px', height: '18.5px' }} /> + <Info + style={{ + width: '18.5px', + height: '18.5px', + color: 'grey', + }} + /> </Tooltip> </p> <Grid container> - <Grid item md={3}> + <Grid item md={2} sm={2} xs={4}> <MySelect name="type" label="Type" @@ -262,10 +271,10 @@ const AddVariant = ({ value={payload.type} options={payloadOptions} onChange={onPayload} - style={{ minWidth: '100px' }} + style={{ minWidth: '100px', width: '100%' }} /> </Grid> - <Grid item md={9}> + <Grid item md={8} sm={8} xs={6}> <TextField rows={1} label="Value" @@ -281,13 +290,14 @@ const AddVariant = ({ <ConditionallyRender condition={overrides.length > 0} show={ - <p style={{ marginBottom: '.5rem' }}> + <p style={{ marginBottom: '1rem' }}> <strong>Overrides </strong> <Tooltip title="Here you can specify which users should get this variant."> <Info style={{ width: '18.5px', height: '18.5px', + color: 'grey', }} /> </Tooltip> @@ -301,7 +311,13 @@ const AddVariant = ({ updateOverrideValues={updateOverrideValues} updateValues={updateOverrideValues} /> - <Button onClick={onAddOverride}>Add override</Button>{' '} + <Button + onClick={onAddOverride} + variant="contained" + color="primary" + > + Add override + </Button>{' '} </form> </Dialog> ); diff --git a/frontend/src/component/feature/variant/AddVariant/OverrideConfig/OverrideConfig.jsx b/frontend/src/component/feature/variant/AddVariant/OverrideConfig/OverrideConfig.jsx index c72eb9677f..a02790b3b5 100644 --- a/frontend/src/component/feature/variant/AddVariant/OverrideConfig/OverrideConfig.jsx +++ b/frontend/src/component/feature/variant/AddVariant/OverrideConfig/OverrideConfig.jsx @@ -41,7 +41,13 @@ const OverrideConfig = ({ return ( <Grid container key={`override=${i}`} alignItems="center"> - <Grid item md={3} className={styles.contextFieldSelect}> + <Grid + item + md={3} + sm={3} + xs={3} + className={styles.contextFieldSelect} + > <MySelect name="contextName" label="Context Field" @@ -53,7 +59,7 @@ const OverrideConfig = ({ onChange={updateOverrideType(i)} /> </Grid> - <Grid md={7} item> + <Grid md={7} sm={7} xs={6} item> <ConditionallyRender condition={legalValues && legalValues.length > 0} show={ @@ -68,6 +74,7 @@ const OverrideConfig = ({ getOptionLabel={option => option} defaultValue={o.values} value={o.values} + style={{ width: '100%' }} filterSelectedOptions size="small" renderInput={params => ( @@ -75,6 +82,7 @@ const OverrideConfig = ({ {...params} variant="outlined" label="Legal values" + style={{ width: '100%' }} /> )} /> diff --git a/frontend/src/component/menu/Footer/Footer.jsx b/frontend/src/component/menu/Footer/Footer.jsx index f643d6721f..197d54e803 100644 --- a/frontend/src/component/menu/Footer/Footer.jsx +++ b/frontend/src/component/menu/Footer/Footer.jsx @@ -16,255 +16,253 @@ export const Footer = () => { <Grid item md={4} xs={12}> <ShowApiDetailsContainer /> </Grid> - <Grid item xs="12" md="auto"> - <Grid container spacing={7} direction="row" > - <Grid item> - <section title="Unleash SDK"> - <h4>Server SDKs</h4> - <List className={styles.list} dense> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/node_sdk" - className={styles.link} - target="_blank" - > - Node.js - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/java_sdk" - className={styles.link} - target="_blank" - > - Java - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/go_sdk" - className={styles.link} - target="_blank" - > - Go - </a> - } - /> - </ListItem>{' '} - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/ruby_sdk" - className={styles.link} - target="_blank" - > - Ruby - </a> - } - /> - </ListItem>{' '} - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/python_sdk" - className={styles.link} - target="_blank" - > - Python - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/dot_net_sdk" - className={styles.link} - target="_blank" - > - .NET - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/php_sdk" - className={styles.link} - target="_blank" - > - PHP - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks" - className={styles.link} - target="_blank" - > - All SDKs - </a> - } - /> - </ListItem> - </List> - </section> - </Grid> - <Grid item justifyContent="center"> - <section title="Unleash SDK"> - <h4>Frontend SDKs</h4> - <List className={styles.list} dense> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/unleash-proxy" - className={styles.link} - target="_blank" - > - Unleash Proxy - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/proxy-javascript" - className={styles.link} - target="_blank" - > - JavaScript SDK - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/proxy-react" - className={styles.link} - target="_blank" - > - React SDK - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/proxy-ios" - className={styles.link} - target="_blank" - > - iOS SDK - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://docs.getunleash.io/sdks/android_proxy_sdk" - className={styles.link} - target="_blank" - > - Android SDK - </a> - } - /> - </ListItem> - </List> - </section> - </Grid> - <Grid item> - <section> - <h4>About</h4> - <List className={styles.list} dense> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://www.getunleash.io/" - className={styles.link} - target="_blank" - > - getunleash.io - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://twitter.com/getunleash" - className={styles.link} - target="_blank" - > - Twitter - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://www.linkedin.com/company/getunleash" - className={styles.link} - target="_blank" - > - LinkedIn - </a> - } - /> - </ListItem> - <ListItem className={styles.listItem}> - <ListItemText - primary={ - <a - href="https://github.com/Unleash/unleash" - className={styles.link} - target="_blank" - > - GitHub - </a> - } - /> - </ListItem> - </List> - </section> + <Grid item xs={12} md="auto"> + <Grid container spacing={7} direction="row"> + <Grid item> + <section title="Unleash SDK"> + <h4>Server SDKs</h4> + <List className={styles.list} dense> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/node_sdk" + className={styles.link} + target="_blank" + > + Node.js + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/java_sdk" + className={styles.link} + target="_blank" + > + Java + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/go_sdk" + className={styles.link} + target="_blank" + > + Go + </a> + } + /> + </ListItem>{' '} + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/ruby_sdk" + className={styles.link} + target="_blank" + > + Ruby + </a> + } + /> + </ListItem>{' '} + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/python_sdk" + className={styles.link} + target="_blank" + > + Python + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/dot_net_sdk" + className={styles.link} + target="_blank" + > + .NET + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/php_sdk" + className={styles.link} + target="_blank" + > + PHP + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks" + className={styles.link} + target="_blank" + > + All SDKs + </a> + } + /> + </ListItem> + </List> + </section> + </Grid> + <Grid item> + <section title="Unleash SDK"> + <h4>Frontend SDKs</h4> + <List className={styles.list} dense> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/unleash-proxy" + className={styles.link} + target="_blank" + > + Unleash Proxy + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/proxy-javascript" + className={styles.link} + target="_blank" + > + JavaScript SDK + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/proxy-react" + className={styles.link} + target="_blank" + > + React SDK + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/proxy-ios" + className={styles.link} + target="_blank" + > + iOS SDK + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://docs.getunleash.io/sdks/android_proxy_sdk" + className={styles.link} + target="_blank" + > + Android SDK + </a> + } + /> + </ListItem> + </List> + </section> + </Grid> + <Grid item> + <section> + <h4>About</h4> + <List className={styles.list} dense> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://www.getunleash.io/" + className={styles.link} + target="_blank" + > + getunleash.io + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://twitter.com/getunleash" + className={styles.link} + target="_blank" + > + Twitter + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://www.linkedin.com/company/getunleash" + className={styles.link} + target="_blank" + > + LinkedIn + </a> + } + /> + </ListItem> + <ListItem className={styles.listItem}> + <ListItemText + primary={ + <a + href="https://github.com/Unleash/unleash" + className={styles.link} + target="_blank" + > + GitHub + </a> + } + /> + </ListItem> + </List> + </section> + </Grid> + </Grid> </Grid> </Grid> - </Grid> - </Grid> - - </footer> ); }; diff --git a/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap index 09ae63ad5c..ffd6e7d91c 100644 --- a/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap +++ b/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap @@ -199,7 +199,6 @@ exports[`should render DrawerMenu 1`] = ` </div> <div className="MuiGrid-root MuiGrid-item" - justifyContent="center" > <section title="Unleash SDK" @@ -602,7 +601,6 @@ exports[`should render DrawerMenu with "features" selected 1`] = ` </div> <div className="MuiGrid-root MuiGrid-item" - justifyContent="center" > <section title="Unleash SDK"