1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-18 11:14:57 +02:00

fix: encode application name (#10671)

This commit is contained in:
Mateusz Kwasniewski 2025-09-19 11:24:17 +02:00 committed by GitHub
parent bcbe3eb0ba
commit 7d70f8fc55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 13 additions and 136 deletions

View File

@ -78,7 +78,7 @@ export const Application = () => {
const { setToastData, setToastApiError } = useToast();
const { pathname } = useLocation();
const basePath = `/applications/${name}`;
const basePath = `/applications/${encodeURIComponent(name)}`;
const [showDialog, setShowDialog] = useState(false);

View File

@ -109,7 +109,7 @@ export const PaginatedApplicationList = () => {
}: any) => (
<LinkCell
title={appName}
to={`/applications/${appName}`}
to={`/applications/${encodeURIComponent(appName)}`}
subtitle={description}
/>
),

View File

@ -1,111 +0,0 @@
import { type ChangeEvent, useMemo, useState } from 'react';
import { Grid, TextField, styled } from '@mui/material';
import { useThemeStyles } from 'themes/themeStyles';
import icons from 'component/application/iconNames';
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
import useApplicationsApi from 'hooks/api/actions/useApplicationsApi/useApplicationsApi';
import useToast from 'hooks/useToast';
import type { IApplication } from 'interfaces/application';
import useApplication from 'hooks/api/getters/useApplication/useApplication';
import { formatUnknownError } from 'utils/formatUnknownError';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
interface IApplicationUpdateProps {
application: IApplication;
}
const StyledSelectContainer = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(1),
}));
export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
const { storeApplicationMetaData } = useApplicationsApi();
const { appName, icon, url, description } = application;
const { refetchApplication } = useApplication(appName);
const [localUrl, setLocalUrl] = useState(url || '');
const [localDescription, setLocalDescription] = useState(description || '');
const { setToastData, setToastApiError } = useToast();
const { classes: themeStyles } = useThemeStyles();
const onChange = async (
field: string,
value: string,
event?: ChangeEvent,
) => {
event?.preventDefault();
try {
await storeApplicationMetaData(appName, field, value);
refetchApplication();
setToastData({
type: 'success',
text: 'Updated Successfully',
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
};
const options = useMemo(() => icons.map((v) => ({ key: v, label: v })), []);
return (
<Grid container style={{ marginTop: '1rem' }}>
<Grid item sm={12} xs={12} className={themeStyles.contentSpacingY}>
<Grid item>
<StyledSelectContainer>
<GeneralSelect
name='iconSelect'
id='selectIcon'
label='Icon'
options={options}
value={icon || 'apps'}
onChange={(key) => onChange('icon', key)}
/>
<HelpIcon
htmlTooltip
tooltip={
<>
<p>Unleash is using Material Icons</p>
<br />
<a
href='https://mui.com/material-ui/material-icons/'
target='_blank'
rel='noreferrer'
>
Preview icons on MUI.com
</a>
</>
}
/>
</StyledSelectContainer>
</Grid>
<Grid item>
<TextField
value={localUrl}
onChange={(e) => setLocalUrl(e.target.value)}
label='Application URL'
placeholder='https://example.com'
type='url'
variant='outlined'
size='small'
onBlur={(e) => onChange('url', localUrl, e)}
/>
</Grid>
<Grid item>
<TextField
value={localDescription}
label='Description'
variant='outlined'
size='small'
rows={2}
onChange={(e) => setLocalDescription(e.target.value)}
onBlur={(e) =>
onChange('description', localDescription, e)
}
/>
</Grid>
</Grid>
</Grid>
);
};

View File

@ -99,7 +99,9 @@ export const ProjectApplications = () => {
title={row.original.name}
onClick={() => {
trackProjectApplicationClick();
navigate(`/applications/${row.original.name}`);
navigate(
`/applications/${encodeURIComponent(row.original.name)}`,
);
}}
/>
),

View File

@ -7,22 +7,6 @@ const useApplicationsApi = () => {
const URI = 'api/admin/metrics/applications';
const storeApplicationMetaData = async (
appName: string,
key: string,
value: string,
) => {
const data: { [key: string]: any } = {};
data[key] = value;
const path = `${URI}/${appName}`;
const req = createRequest(path, {
method: 'POST',
body: JSON.stringify(data),
});
return makeRequest(req.caller, req.id);
};
const deleteApplication = async (appName: string) => {
const path = `${URI}/${encodeURIComponent(appName)}`;
const req = createRequest(path, { method: 'DELETE' });
@ -31,7 +15,6 @@ const useApplicationsApi = () => {
};
return {
storeApplicationMetaData,
deleteApplication,
errors,
loading,

View File

@ -16,7 +16,8 @@ const useApplication = (
name: string,
options: SWRConfiguration = {},
): IUseApplicationOutput => {
const path = formatApiPath(`api/admin/metrics/applications/${name}`);
const encodedName = encodeURIComponent(name);
const path = formatApiPath(`api/admin/metrics/applications/${encodedName}`);
const fetcher = async () => {
return fetch(path, {
@ -26,7 +27,7 @@ const useApplication = (
.then((res) => res.json());
};
const APPLICATION_CACHE_KEY = `api/admin/metrics/applications/${name}`;
const APPLICATION_CACHE_KEY = `api/admin/metrics/applications/${encodedName}`;
const { data, error } = useSWR(APPLICATION_CACHE_KEY, fetcher, {
...options,
@ -44,7 +45,7 @@ const useApplication = (
return {
application: data || {
appName: name,
appName: encodedName,
color: '',
createdAt: '2022-02-02T21:04:00.268Z',
description: '',

View File

@ -15,8 +15,9 @@ export const useApplicationOverview = (
application: string,
options: SWRConfiguration = {},
) => {
const encodedApplication = encodeURIComponent(application);
const path = formatApiPath(
`api/admin/metrics/applications/${application}/overview`,
`api/admin/metrics/applications/${encodedApplication}/overview`,
);
const { data, error } = useSWR<ApplicationOverviewSchema>(
path,

View File

@ -17,8 +17,9 @@ export const useConnectedInstances = (
environment?: string,
options: SWRConfiguration = {},
) => {
const encodedApplication = encodeURIComponent(application);
const path = formatApiPath(
`api/admin/metrics/instances/${application}/environment/${environment}`,
`api/admin/metrics/instances/${encodedApplication}/environment/${environment}`,
);
const { data, error } = useConditionalSWR<ConnectedInstancesSchema>(
Boolean(environment),