1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-04 00:18:01 +01:00

refactor: application-view to ApplicationView with useApplication hook

This commit is contained in:
Youssef 2022-02-04 07:56:17 +01:00
parent 7344f47635
commit 38e549d879
4 changed files with 144 additions and 37 deletions

View File

@ -1,6 +1,5 @@
import React from 'react'; import { useContext } from 'react';
import { Link } from 'react-router-dom'; import { Link, useParams } from 'react-router-dom';
import PropTypes from 'prop-types';
import { import {
Grid, Grid,
List, List,
@ -9,8 +8,13 @@ import {
ListItemAvatar, ListItemAvatar,
Typography, Typography,
} from '@material-ui/core'; } from '@material-ui/core';
import { Report, Extension, Timeline, FlagRounded } from '@material-ui/icons'; import {
Report,
Extension,
Timeline,
FlagRounded,
SvgIconComponent,
} from '@material-ui/icons';
import { shorten } from '../common'; import { shorten } from '../common';
import { import {
CREATE_FEATURE, CREATE_FEATURE,
@ -18,21 +22,30 @@ import {
} from '../providers/AccessProvider/permissions'; } from '../providers/AccessProvider/permissions';
import ConditionallyRender from '../common/ConditionallyRender/ConditionallyRender'; import ConditionallyRender from '../common/ConditionallyRender/ConditionallyRender';
import { getTogglePath } from '../../utils/route-path-helpers'; import { getTogglePath } from '../../utils/route-path-helpers';
function ApplicationView({ import useApplication from '../../hooks/api/getters/useApplication/useApplication';
seenToggles, import AccessContext from '../../contexts/AccessContext';
hasAccess, import { formatFullDateTimeWithLocale } from '../common/util';
strategies, const ApplicationView = () => {
instances, const { hasAccess } = useContext(AccessContext);
formatFullDateTime, const { name } = useParams<{ name: string }>();
}) { const { application } = useApplication(name);
const notFoundListItem = ({ createUrl, name, permission }) => ( const { instances, strategies, seenToggles } = application;
const notFoundListItem = ({
createUrl,
name,
permission,
}: {
createUrl: string;
name: string;
permission: string;
}) => (
<ConditionallyRender <ConditionallyRender
key={`not_found_conditional_${name}`} key={`not_found_conditional_${name}`}
condition={hasAccess(permission)} condition={hasAccess(permission)}
show={ show={
<ListItem key={`not_found_${name}`}> <ListItem key={`not_found_${name}`}>
<ListItemAvatar> <ListItemAvatar>
<Report style={{color: 'red'}} /> <Report style={{ color: 'red' }} />
</ListItemAvatar> </ListItemAvatar>
<ListItemText <ListItemText
primary={<Link to={`${createUrl}`}>{name}</Link>} primary={<Link to={`${createUrl}`}>{name}</Link>}
@ -54,13 +67,18 @@ function ApplicationView({
/> />
); );
// eslint-disable-next-line react/prop-types
const foundListItem = ({ const foundListItem = ({
viewUrl, viewUrl,
name, name,
description, description,
Icon, Icon,
i, i,
}: {
viewUrl: string;
name: string;
description: string;
Icon: SvgIconComponent;
i: number;
}) => ( }) => (
<ListItem key={`found_${name}-${i}`}> <ListItem key={`found_${name}-${i}`}>
<ListItemAvatar> <ListItemAvatar>
@ -83,10 +101,7 @@ function ApplicationView({
<hr /> <hr />
<List> <List>
{seenToggles.map( {seenToggles.map(
( ({ name, description, notFound, project }, i) => (
{ name, description, notFound, project },
i
) => (
<ConditionallyRender <ConditionallyRender
key={`toggle_conditional_${name}`} key={`toggle_conditional_${name}`}
condition={notFound} condition={notFound}
@ -97,7 +112,7 @@ function ApplicationView({
i, i,
})} })}
elseShow={foundListItem({ elseShow={foundListItem({
viewUrl: getTogglePath(project, name), viewUrl: getTogglePath(project, name, true),
name, name,
description, description,
Icon: FlagRounded, Icon: FlagRounded,
@ -143,7 +158,17 @@ function ApplicationView({
<hr /> <hr />
<List> <List>
{instances.map( {instances.map(
({ instanceId, clientIp, lastSeen, sdkVersion }) => ( ({
instanceId,
clientIp,
lastSeen,
sdkVersion,
}: {
instanceId: string;
clientIp: string;
lastSeen: string;
sdkVersion: string;
}) => (
<ListItem key={`${instanceId}`}> <ListItem key={`${instanceId}`}>
<ListItemAvatar> <ListItemAvatar>
<Timeline /> <Timeline />
@ -152,16 +177,18 @@ function ApplicationView({
primary={ primary={
<ConditionallyRender <ConditionallyRender
key={`${instanceId}_conditional`} key={`${instanceId}_conditional`}
condition={sdkVersion} condition={Boolean(sdkVersion)}
show={`${instanceId} (${sdkVersion})`} show={<span>{instanceId} {(sdkVersion)}</span>}
elseShow={instanceId} elseShow={<span>{instanceId}</span>}
/> />
} }
secondary={ secondary={
<span> <span>
{clientIp} last seen at{' '} {clientIp} last seen at{' '}
<small> <small>
{formatFullDateTime(lastSeen)} {formatFullDateTimeWithLocale(
lastSeen
)}
</small> </small>
</span> </span>
} }
@ -173,17 +200,6 @@ function ApplicationView({
</Grid> </Grid>
</Grid> </Grid>
); );
}
ApplicationView.propTypes = {
createUrl: PropTypes.string,
name: PropTypes.string,
permission: PropTypes.string,
instances: PropTypes.array.isRequired,
seenToggles: PropTypes.array.isRequired,
strategies: PropTypes.array.isRequired,
hasAccess: PropTypes.func.isRequired,
formatFullDateTime: PropTypes.func.isRequired,
}; };
export default ApplicationView; export default ApplicationView;

View File

@ -19,7 +19,7 @@ import {
formatDateWithLocale, formatDateWithLocale,
} from '../common/util'; } from '../common/util';
import { UPDATE_APPLICATION } from '../providers/AccessProvider/permissions'; import { UPDATE_APPLICATION } from '../providers/AccessProvider/permissions';
import ApplicationView from './application-view'; import ApplicationView from './ApplicationView';
import ApplicationUpdate from './application-update'; import ApplicationUpdate from './application-update';
import TabNav from '../common/TabNav/TabNav'; import TabNav from '../common/TabNav/TabNav';
import Dialogue from '../common/Dialogue'; import Dialogue from '../common/Dialogue';

View File

@ -0,0 +1,50 @@
import useSWR, { mutate, SWRConfiguration } from 'swr';
import { useState, useEffect } from 'react';
import { formatApiPath } from '../../../../utils/format-path';
import handleErrorResponses from '../httpErrorResponseHandler';
const useApplication = (name: string, options: SWRConfiguration = {}) => {
const fetcher = async () => {
const path = formatApiPath(`api/admin/metrics/applications/${name}`);
return fetch(path, {
method: 'GET',
})
.then(handleErrorResponses('Application'))
.then(res => res.json());
};
const FEATURE_CACHE_KEY = `api/admin/metrics/applications/${name}`;
const { data, error } = useSWR(FEATURE_CACHE_KEY, fetcher, {
...options,
});
const [loading, setLoading] = useState(!error && !data);
const refetchApplication = () => {
mutate(FEATURE_CACHE_KEY);
};
useEffect(() => {
setLoading(!error && !data);
}, [data, error]);
return {
application: data || {
appName: name,
color: null,
createdAt: '2022-02-02T21:04:00.268Z',
descriotion: '',
instances: [],
strategies: [],
seenToggles: [],
url: '',
},
error,
loading,
refetchApplication,
FEATURE_CACHE_KEY,
};
};
export default useApplication;

View File

@ -0,0 +1,41 @@
import useSWR, { mutate, SWRConfiguration } from 'swr';
import { useState, useEffect } from 'react';
import { formatApiPath } from '../../../../utils/format-path';
import handleErrorResponses from '../httpErrorResponseHandler';
const useApplications = (options: SWRConfiguration = {}) => {
const fetcher = async () => {
const path = formatApiPath('api/admin/metrics/applications');
return fetch(path, {
method: 'GET',
})
.then(handleErrorResponses('Context data'))
.then(res => res.json());
};
const FEATURE_CACHE_KEY = 'api/admin/metrics/applications';
const { data, error } = useSWR(FEATURE_CACHE_KEY, fetcher, {
...options,
});
const [loading, setLoading] = useState(!error && !data);
const refetchApplications = () => {
mutate(FEATURE_CACHE_KEY);
};
useEffect(() => {
setLoading(!error && !data);
}, [data, error]);
return {
applications: data?.applications || {},
error,
loading,
refetchApplications,
FEATURE_CACHE_KEY,
};
};
export default useApplications;