mirror of
https://github.com/strapi/strapi.git
synced 2025-09-26 08:52:26 +00:00
Created providers list view
Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
parent
8575995080
commit
a1592c9626
@ -0,0 +1,8 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
// TODO : Temporary baseline alignment
|
||||||
|
const ListBaselineAlignment = styled.div`
|
||||||
|
padding-top: 3px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default ListBaselineAlignment;
|
@ -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;
|
@ -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;
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
import { Header } from '@buffetjs/custom';
|
||||||
import { SettingsPageTitle } from 'strapi-helper-plugin';
|
import { SettingsPageTitle } from 'strapi-helper-plugin';
|
||||||
import getTrad from '../../utils/getTrad';
|
import getTrad from '../../utils/getTrad';
|
||||||
|
|
||||||
@ -10,7 +11,9 @@ const AdvancedSettingsPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsPageTitle name={pageTitle} />
|
<SettingsPageTitle name={pageTitle} />
|
||||||
<div>Advanced settings</div>
|
<div>
|
||||||
|
<Header title={{ label: pageTitle }} />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
import { Header } from '@buffetjs/custom';
|
||||||
import { SettingsPageTitle } from 'strapi-helper-plugin';
|
import { SettingsPageTitle } from 'strapi-helper-plugin';
|
||||||
import getTrad from '../../utils/getTrad';
|
import getTrad from '../../utils/getTrad';
|
||||||
|
|
||||||
@ -10,7 +11,9 @@ const EmailTemplatesPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsPageTitle name={pageTitle} />
|
<SettingsPageTitle name={pageTitle} />
|
||||||
<div>Email</div>
|
<div>
|
||||||
|
<Header title={{ label: pageTitle }} />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,16 +1,122 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useMemo, useReducer } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { SettingsPageTitle } from 'strapi-helper-plugin';
|
import { Header, List } from '@buffetjs/custom';
|
||||||
import getTrad from '../../utils/getTrad';
|
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 ProvidersPage = () => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const pageTitle = formatMessage({ id: getTrad('HeaderNav.link.providers') });
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsPageTitle name={pageTitle} />
|
<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>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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 };
|
@ -44,10 +44,7 @@
|
|||||||
"List.button.roles": "Add New Role",
|
"List.button.roles": "Add New Role",
|
||||||
"List.title.emailTemplates.plural": "{number} email templates are available",
|
"List.title.emailTemplates.plural": "{number} email templates are available",
|
||||||
"List.title.emailTemplates.singular": "{number} email template is 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.plural": "{number} roles are available",
|
||||||
"List.title.roles.singular": "{number} role is available",
|
"List.title.roles.singular": "{number} role is available",
|
||||||
"ListRow.disabled": "Disabled",
|
"ListRow.disabled": "Disabled",
|
||||||
@ -113,6 +110,10 @@
|
|||||||
"HeaderNav.link.emailTemplates": "Email templates",
|
"HeaderNav.link.emailTemplates": "Email templates",
|
||||||
"HeaderNav.link.providers": "Providers",
|
"HeaderNav.link.providers": "Providers",
|
||||||
"HeaderNav.link.roles": "Roles",
|
"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.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.description.short": "Protect your API with a full authentication process based on JWT",
|
||||||
"plugin.name": "Users & Permissions Plugin"
|
"plugin.name": "Users & Permissions Plugin"
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
import pluginId from '../pluginId';
|
||||||
|
|
||||||
|
const getRequestURL = endPoint => `/${pluginId}/${endPoint}`;
|
||||||
|
|
||||||
|
export default getRequestURL;
|
@ -0,0 +1,2 @@
|
|||||||
|
export { default as getRequestURL } from './getRequestURL';
|
||||||
|
export { default as getTrad } from './getTrad';
|
Loading…
x
Reference in New Issue
Block a user