mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-27 13:49:10 +02:00
feat: add link ui (#9918)
This commit is contained in:
parent
eb238f502a
commit
36c8efceae
@ -0,0 +1,71 @@
|
||||
import { type FC, useState } from 'react';
|
||||
import { Box, styled, TextField } from '@mui/material';
|
||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||
import { useFeatureLinkApi } from 'hooks/api/actions/useFeatureLinkApi/useFeatureLinkApi';
|
||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
|
||||
interface IAddLinkDialogueProps {
|
||||
project: string;
|
||||
featureId: string;
|
||||
showAddLinkDialogue: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const StyledTextField = styled(TextField)(({ theme }) => ({
|
||||
width: '100%',
|
||||
marginTop: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1),
|
||||
}));
|
||||
|
||||
export const AddLinkDialogue: FC<IAddLinkDialogueProps> = ({
|
||||
showAddLinkDialogue,
|
||||
onClose,
|
||||
project,
|
||||
featureId,
|
||||
}) => {
|
||||
const [url, setUrl] = useState('');
|
||||
const [title, setTitle] = useState('');
|
||||
const { addLink, loading } = useFeatureLinkApi(project, featureId);
|
||||
const { refetchFeature } = useFeature(project, featureId);
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
|
||||
return (
|
||||
<Dialogue
|
||||
open={showAddLinkDialogue}
|
||||
title='Add link'
|
||||
onClose={onClose}
|
||||
disabledPrimaryButton={url.trim() === '' || loading}
|
||||
onClick={async () => {
|
||||
try {
|
||||
await addLink({ url, title: title ?? null });
|
||||
setToastData({ text: 'Link added', type: 'success' });
|
||||
onClose();
|
||||
refetchFeature();
|
||||
setTitle('');
|
||||
setUrl('');
|
||||
} catch (error) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
}}
|
||||
primaryButtonText='Add'
|
||||
secondaryButtonText='Cancel'
|
||||
>
|
||||
<Box>
|
||||
<StyledTextField
|
||||
label='Link'
|
||||
variant='outlined'
|
||||
value={url}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
/>
|
||||
<StyledTextField
|
||||
label='Title (optional)'
|
||||
variant='outlined'
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
</Dialogue>
|
||||
);
|
||||
};
|
@ -30,6 +30,9 @@ import AddIcon from '@mui/icons-material/Add';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { Badge } from 'component/common/Badge/Badge';
|
||||
import LinkIcon from '@mui/icons-material/Link';
|
||||
import { UPDATE_FEATURE } from '../../../../providers/AccessProvider/permissions';
|
||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||
import { AddLinkDialogue } from './AddLinkDialogue';
|
||||
|
||||
const StyledMetaDataContainer = styled('div')(({ theme }) => ({
|
||||
padding: theme.spacing(3),
|
||||
@ -91,7 +94,13 @@ type FeatureOverviewMetaDataProps = {
|
||||
onChange: () => void;
|
||||
};
|
||||
|
||||
const FeatureLinks: FC<{ links: FeatureLink[] }> = ({ links }) => {
|
||||
const FeatureLinks: FC<{
|
||||
links: FeatureLink[];
|
||||
project: string;
|
||||
feature: string;
|
||||
}> = ({ links, project, feature }) => {
|
||||
const [showAddLinkDialogue, setShowAddLinkDialogue] = useState(false);
|
||||
|
||||
return links.length === 0 ? (
|
||||
<StyledMetaDataContainer>
|
||||
<StyledTitle>
|
||||
@ -105,6 +114,18 @@ const FeatureLinks: FC<{ links: FeatureLink[] }> = ({ links }) => {
|
||||
trackers, code repositories or analytics tooling
|
||||
</StyledMetaDataItem>
|
||||
<div>
|
||||
<PermissionButton
|
||||
size='small'
|
||||
startIcon={<AddIcon />}
|
||||
permission={UPDATE_FEATURE}
|
||||
projectId={project}
|
||||
variant='text'
|
||||
onClick={() => {
|
||||
setShowAddLinkDialogue(true);
|
||||
}}
|
||||
>
|
||||
Add parent flag
|
||||
</PermissionButton>
|
||||
<Button
|
||||
size='small'
|
||||
variant='text'
|
||||
@ -150,11 +171,17 @@ const FeatureLinks: FC<{ links: FeatureLink[] }> = ({ links }) => {
|
||||
size='small'
|
||||
variant='text'
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => {}}
|
||||
onClick={() => setShowAddLinkDialogue(true)}
|
||||
>
|
||||
Add link
|
||||
</Button>
|
||||
</div>
|
||||
<AddLinkDialogue
|
||||
project={project}
|
||||
featureId={feature}
|
||||
showAddLinkDialogue={showAddLinkDialogue}
|
||||
onClose={() => setShowAddLinkDialogue(false)}
|
||||
/>
|
||||
</StyledMetaDataContainer>
|
||||
);
|
||||
};
|
||||
@ -181,7 +208,11 @@ const FeatureOverviewMetaData: FC<FeatureOverviewMetaDataProps> = ({
|
||||
return (
|
||||
<>
|
||||
{featureLinksEnabled ? (
|
||||
<FeatureLinks links={feature.links || []} />
|
||||
<FeatureLinks
|
||||
links={feature.links || []}
|
||||
project={feature.project}
|
||||
feature={feature.name}
|
||||
/>
|
||||
) : null}
|
||||
<StyledMetaDataContainer>
|
||||
<div>
|
||||
|
@ -0,0 +1,35 @@
|
||||
import useAPI from '../useApi/useApi';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useFeatureLinkApi = (project: string, feature: string) => {
|
||||
const { makeRequest, createRequest, errors, loading } = useAPI({
|
||||
propagateErrors: true,
|
||||
});
|
||||
|
||||
const addLink = async (linkSchema: {
|
||||
url: string;
|
||||
title: string | null;
|
||||
}) => {
|
||||
const req = createRequest(
|
||||
`/api/admin/projects/${project}/features/${feature}/link`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(linkSchema),
|
||||
},
|
||||
);
|
||||
await makeRequest(req.caller, req.id);
|
||||
};
|
||||
|
||||
const callbackDeps = [
|
||||
createRequest,
|
||||
makeRequest,
|
||||
formatUnknownError,
|
||||
project,
|
||||
];
|
||||
return {
|
||||
addLink: useCallback(addLink, callbackDeps),
|
||||
errors,
|
||||
loading,
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user