Created providers list view

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2020-08-04 15:59:19 +02:00
parent 8575995080
commit a1592c9626
10 changed files with 250 additions and 11 deletions

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
// TODO : Temporary baseline alignment
const ListBaselineAlignment = styled.div`
padding-top: 3px;
`;
export default ListBaselineAlignment;

View File

@ -0,0 +1,35 @@
import React from 'react';
import { CustomRow } from '@buffetjs/styles';
import { IconLinks, Text } from '@buffetjs/core';
import PropTypes from 'prop-types';
import PrefixedIcon from '../PrefixedIcon';
const ListRow = ({ icon, name, onClick, links, children }) => {
return (
<CustomRow onClick={onClick}>
<td>
<PrefixedIcon icon={icon} name={name} />
</td>
{children}
<td>
<IconLinks links={links} />
</td>
</CustomRow>
);
};
ListRow.defaultProps = {
children: null,
onClick: () => {},
links: [],
};
ListRow.propTypes = {
children: PropTypes.node,
icon: PropTypes.array.isRequired,
links: PropTypes.array,
name: PropTypes.string.isRequired,
onClick: PropTypes.func,
};
export default ListRow;

View File

@ -0,0 +1,27 @@
import React from 'react';
import { Flex, Padded, Text } from '@buffetjs/core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { upperFirst } from 'lodash';
import PropTypes from 'prop-types';
const PrefixedIcon = ({ icon, name }) => {
return (
<Flex>
<div>
<FontAwesomeIcon icon={icon} />
</div>
<Padded left size="md">
<Text fontWeight="semiBold" lineHeight="18px">
{upperFirst(name)}
</Text>
</Padded>
</Flex>
);
};
PrefixedIcon.propTypes = {
icon: PropTypes.array.isRequired,
name: PropTypes.string.isRequired,
};
export default PrefixedIcon;

View File

@ -1,5 +1,6 @@
import React from 'react';
import { useIntl } from 'react-intl';
import { Header } from '@buffetjs/custom';
import { SettingsPageTitle } from 'strapi-helper-plugin';
import getTrad from '../../utils/getTrad';
@ -10,7 +11,9 @@ const AdvancedSettingsPage = () => {
return (
<>
<SettingsPageTitle name={pageTitle} />
<div>Advanced settings</div>
<div>
<Header title={{ label: pageTitle }} />
</div>
</>
);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import React, { useMemo } from 'react';
import { useIntl } from 'react-intl';
import { Header } from '@buffetjs/custom';
import { SettingsPageTitle } from 'strapi-helper-plugin';
import getTrad from '../../utils/getTrad';
@ -10,7 +11,9 @@ const EmailTemplatesPage = () => {
return (
<>
<SettingsPageTitle name={pageTitle} />
<div>Email</div>
<div>
<Header title={{ label: pageTitle }} />
</div>
</>
);
};

View File

@ -1,16 +1,122 @@
import React from 'react';
import React, { useEffect, useMemo, useReducer } from 'react';
import { useIntl } from 'react-intl';
import { SettingsPageTitle } from 'strapi-helper-plugin';
import getTrad from '../../utils/getTrad';
import { Header, List } from '@buffetjs/custom';
import { Text } from '@buffetjs/core';
import { Pencil } from '@buffetjs/icons';
import { SettingsPageTitle, useUserPermissions, request } from 'strapi-helper-plugin';
import pluginPermissions from '../../permissions';
import { getRequestURL, getTrad } from '../../utils';
import ListBaselineAlignment from '../../components/ListBaselineAlignment';
import ListRow from '../../components/ListRow';
import reducer, { initialState } from './reducer';
const ProvidersPage = () => {
const { formatMessage } = useIntl();
const pageTitle = formatMessage({ id: getTrad('HeaderNav.link.providers') });
const updatePermissions = useMemo(() => {
return { update: pluginPermissions.updateProviders };
}, [pluginPermissions]);
const {
isLoading: isLoadingForPermissions,
allowedActions: { canUpdate },
} = useUserPermissions(updatePermissions);
const [{ isLoading, providers }, dispatch] = useReducer(reducer, initialState);
const enabledProvidersCount = useMemo(
() => providers.filter(provider => provider.enabled).length,
[providers]
);
const disabledProvidersCount = useMemo(() => {
return providers.length - enabledProvidersCount;
}, [providers, enabledProvidersCount]);
const listTitle = useMemo(() => {
const enabledMessage = formatMessage(
{
id: getTrad(
`List.title.providers.enabled.${enabledProvidersCount > 1 ? 'plural' : 'singular'}`
),
},
{ number: enabledProvidersCount }
);
const disabledMessage = formatMessage(
{
id: getTrad(
`List.title.providers.disabled.${disabledProvidersCount > 1 ? 'plural' : 'singular'}`
),
},
{ number: disabledProvidersCount }
);
return `${enabledMessage} ${disabledMessage}`;
}, [formatMessage, enabledProvidersCount]);
useEffect(() => {
const getData = async () => {
try {
dispatch({
type: 'GET_DATA',
});
const data = await request(getRequestURL('providers'), { method: 'GET' });
console.log({ data });
dispatch({
type: 'GET_DATA_SUCCEEDED',
data,
});
} catch (err) {
dispatch({
type: 'GET_DATA_ERROR',
});
console.error(err);
strapi.notification.error('notification.error');
}
};
if (!isLoadingForPermissions) {
getData();
}
}, [isLoadingForPermissions]);
return (
<>
<SettingsPageTitle name={pageTitle} />
<div>Providers</div>
<div>
<Header title={{ label: pageTitle }} isLoading={isLoadingForPermissions || isLoading} />
<ListBaselineAlignment />
<List
title={listTitle}
items={providers}
isLoading={isLoading}
customRowComponent={provider => (
<ListRow
{...provider}
onClick={() => {
console.log(`Will edit ${provider.name}`);
}}
links={[
{
icon: canUpdate ? <Pencil fill="#0e1622" /> : null,
onClick: () => {
console.log(`Will edit ${provider.name}`);
},
},
]}
>
<td key="enabled">
<Text
fontWeight="semiBold"
lineHeight="18px"
color={provider.enabled ? 'green' : 'lightOrange'}
>
{provider.enabled ? 'Enabled' : 'Disabled'}
</Text>
</td>
</ListRow>
)}
/>
</div>
</>
);
};

View File

@ -0,0 +1,49 @@
import produce from 'immer';
import { sortBy } from 'lodash';
const initialState = {
isLoading: true,
data: {},
providers: [],
};
const reducer = (state, action) =>
// eslint-disable-next-line consistent-return
produce(state, draftState => {
switch (action.type) {
case 'GET_DATA': {
draftState.isLoading = true;
break;
}
case 'GET_DATA_SUCCEEDED': {
draftState.isLoading = false;
draftState.data = action.data;
draftState.providers = sortBy(
Object.keys(action.data).reduce((acc, current) => {
const { icon: iconName, enabled } = action.data[current];
const icon = iconName === 'envelope' ? ['fas', 'envelope'] : ['fab', iconName];
acc.push({ name: current, icon, enabled });
return acc;
}, []),
'name'
);
break;
}
case 'GET_DATA_ERROR': {
drafState.isLoading = true;
break;
}
case 'RESET_PROPS':
return initialState;
default: {
return draftState;
}
}
});
export default reducer;
export { initialState };

View File

@ -44,10 +44,7 @@
"List.button.roles": "Add New Role",
"List.title.emailTemplates.plural": "{number} email templates are available",
"List.title.emailTemplates.singular": "{number} email template is available",
"List.title.providers.disabled.plural": "{number} are disabled",
"List.title.providers.disabled.singular": "{number} is disabled",
"List.title.providers.enabled.plural": "{number} providers are enabled and",
"List.title.providers.enabled.singular": "{number} provider is enabled and",
"List.title.roles.plural": "{number} roles are available",
"List.title.roles.singular": "{number} role is available",
"ListRow.disabled": "Disabled",
@ -113,6 +110,10 @@
"HeaderNav.link.emailTemplates": "Email templates",
"HeaderNav.link.providers": "Providers",
"HeaderNav.link.roles": "Roles",
"List.title.providers.disabled.plural": "{number} are disabled",
"List.title.providers.disabled.singular": "{number} is disabled",
"List.title.providers.enabled.plural": "{number} providers are enabled and",
"List.title.providers.enabled.singular": "{number} provider is enabled and",
"plugin.description.long": "Protect your API with a full authentication process based on JWT. This plugin comes also with an ACL strategy that allows you to manage the permissions between the groups of users.",
"plugin.description.short": "Protect your API with a full authentication process based on JWT",
"plugin.name": "Users & Permissions Plugin"

View File

@ -0,0 +1,5 @@
import pluginId from '../pluginId';
const getRequestURL = endPoint => `/${pluginId}/${endPoint}`;
export default getRequestURL;

View File

@ -0,0 +1,2 @@
export { default as getRequestURL } from './getRequestURL';
export { default as getTrad } from './getTrad';