node_modules ignore

This commit is contained in:
2025-05-08 23:43:47 +02:00
parent e19d52f172
commit 4574544c9f
65041 changed files with 10593536 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
dist
rollup.config.mjs

View File

@@ -0,0 +1,17 @@
{
"root": true,
"overrides": [
{
"files": ["admin/**/*"],
"extends": ["custom/front"],
"rules": {
"import/extensions": "off"
}
},
{
"files": ["**/*"],
"excludedFiles": ["admin/**/*"],
"extends": ["custom/back"]
}
]
}

View File

@@ -0,0 +1,37 @@
Copyright (c) 2015-present Strapi Solutions SAS
Portions of the Strapi software are licensed as follows:
* All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined below.
Enterprise License
If you or the company you represent has entered into a written agreement referencing the Enterprise Edition of the Strapi source code available at
https://github.com/strapi/strapi, then such agreement applies to your use of the Enterprise Edition of the Strapi Software. If you or the company you
represent is using the Enterprise Edition of the Strapi Software in connection with a subscription to our cloud offering, then the agreement you have
agreed to with respect to our cloud offering and the licenses included in such agreement apply to your use of the Enterprise Edition of the Strapi Software.
Otherwise, the Strapi Enterprise Software License Agreement (found here https://strapi.io/enterprise-terms) applies to your use of the Enterprise Edition of the Strapi Software.
BY ACCESSING OR USING THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE, YOU ARE AGREEING TO BE BOUND BY THE RELEVANT REFERENCED AGREEMENT.
IF YOU ARE NOT AUTHORIZED TO ACCEPT THESE TERMS ON BEHALF OF THE COMPANY YOU REPRESENT OR IF YOU DO NOT AGREE TO ALL OF THE RELEVANT TERMS AND CONDITIONS REFERENCED AND YOU
HAVE NOT OTHERWISE EXECUTED A WRITTEN AGREEMENT WITH STRAPI, YOU ARE NOT AUTHORIZED TO ACCESS OR USE OR ALLOW ANY USER TO ACCESS OR USE ANY PART OF
THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE. YOUR ACCESS RIGHTS ARE CONDITIONAL ON YOUR CONSENT TO THE RELEVANT REFERENCED TERMS TO THE EXCLUSION OF ALL OTHER TERMS;
IF THE RELEVANT REFERENCED TERMS ARE CONSIDERED AN OFFER BY YOU, ACCEPTANCE IS EXPRESSLY LIMITED TO THE RELEVANT REFERENCED TERMS.
* All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below.
MIT Expat License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1 @@
# Strapi plugin

View File

@@ -0,0 +1,41 @@
const getMethodColor = (verb) => {
switch (verb) {
case 'POST': {
return {
text: 'success600',
border: 'success200',
background: 'success100',
};
}
case 'GET': {
return {
text: 'secondary600',
border: 'secondary200',
background: 'secondary100',
};
}
case 'PUT': {
return {
text: 'warning600',
border: 'warning200',
background: 'warning100',
};
}
case 'DELETE': {
return {
text: 'danger600',
border: 'danger200',
background: 'danger100',
};
}
default: {
return {
text: 'neutral600',
border: 'neutral200',
background: 'neutral100',
};
}
}
};
export default getMethodColor;

View File

@@ -0,0 +1,72 @@
import * as React from 'react';
import { Box, Flex, Typography } from '@strapi/design-system';
import map from 'lodash/map';
import tail from 'lodash/tail';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { styled } from 'styled-components';
import getMethodColor from './getMethodColor';
const MethodBox = styled(Box)`
margin: -1px;
border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};
`;
function BoundRoute({ route }) {
const { formatMessage } = useIntl();
const { method, handler: title, path } = route;
const formattedRoute = path ? tail(path.split('/')) : [];
const [controller = '', action = ''] = title ? title.split('.') : [];
const colors = getMethodColor(route.method);
return (
<Flex direction="column" alignItems="stretch" gap={2}>
<Typography variant="delta" tag="h3">
{formatMessage({
id: 'users-permissions.BoundRoute.title',
defaultMessage: 'Bound route to',
})}
&nbsp;
<span>{controller}</span>
<Typography variant="delta" textColor="primary600">
.{action}
</Typography>
</Typography>
<Flex hasRadius background="neutral0" borderColor="neutral200" gap={0}>
<MethodBox background={colors.background} borderColor={colors.border} padding={2}>
<Typography fontWeight="bold" textColor={colors.text}>
{method}
</Typography>
</MethodBox>
<Box paddingLeft={2} paddingRight={2}>
{map(formattedRoute, (value) => (
<Typography key={value} textColor={value.includes(':') ? 'neutral600' : 'neutral900'}>
/{value}
</Typography>
))}
</Box>
</Flex>
</Flex>
);
}
BoundRoute.defaultProps = {
route: {
handler: 'Nocontroller.error',
method: 'GET',
path: '/there-is-no-path',
},
};
BoundRoute.propTypes = {
route: PropTypes.shape({
handler: PropTypes.string,
method: PropTypes.string,
path: PropTypes.string,
}),
};
export default BoundRoute;

View File

@@ -0,0 +1,124 @@
/**
*
* Input
*
*/
import * as React from 'react';
import { TextInput, Toggle, Field } from '@strapi/design-system';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
const Input = ({
description,
disabled,
intlLabel,
error,
name,
onChange,
placeholder,
providerToEditName,
type,
value,
}) => {
const { formatMessage } = useIntl();
const inputValue =
name === 'noName'
? `${window.strapi.backendURL}/api/connect/${providerToEditName}/callback`
: value;
const label = formatMessage(
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
{ provider: providerToEditName, ...intlLabel.values }
);
const hint = description
? formatMessage(
{ id: description.id, defaultMessage: description.defaultMessage },
{ provider: providerToEditName, ...description.values }
)
: '';
if (type === 'bool') {
return (
<Field.Root hint={hint} name={name}>
<Field.Label>{label}</Field.Label>
<Toggle
aria-label={name}
checked={value}
disabled={disabled}
offLabel={formatMessage({
id: 'app.components.ToggleCheckbox.off-label',
defaultMessage: 'Off',
})}
onLabel={formatMessage({
id: 'app.components.ToggleCheckbox.on-label',
defaultMessage: 'On',
})}
onChange={(e) => {
onChange({ target: { name, value: e.target.checked } });
}}
/>
<Field.Hint />
</Field.Root>
);
}
const formattedPlaceholder = placeholder
? formatMessage(
{ id: placeholder.id, defaultMessage: placeholder.defaultMessage },
{ ...placeholder.values }
)
: '';
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
return (
<Field.Root error={errorMessage} name={name}>
<Field.Label>{label}</Field.Label>
<TextInput
disabled={disabled}
onChange={onChange}
placeholder={formattedPlaceholder}
type={type}
value={inputValue}
/>
<Field.Error />
</Field.Root>
);
};
Input.defaultProps = {
description: null,
disabled: false,
error: '',
placeholder: null,
value: '',
};
Input.propTypes = {
description: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
disabled: PropTypes.bool,
error: PropTypes.string,
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}).isRequired,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
providerToEditName: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
};
export default Input;

View File

@@ -0,0 +1,115 @@
/**
*
* FormModal
*
*/
import * as React from 'react';
import { Button, Flex, Grid, Modal, Breadcrumbs, Crumb } from '@strapi/design-system';
import { Form, Formik } from 'formik';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import Input from './Input';
const FormModal = ({
headerBreadcrumbs,
initialData,
isSubmiting,
layout,
isOpen,
onSubmit,
onToggle,
providerToEditName,
}) => {
const { formatMessage } = useIntl();
return (
<Modal.Root open={isOpen} onOpenChange={onToggle}>
<Modal.Content>
<Modal.Header>
<Breadcrumbs label={headerBreadcrumbs.join(', ')}>
{headerBreadcrumbs.map((crumb, index, arr) => (
<Crumb isCurrent={index === arr.length - 1} key={crumb}>
{crumb}
</Crumb>
))}
</Breadcrumbs>
</Modal.Header>
<Formik
onSubmit={(values) => onSubmit(values)}
initialValues={initialData}
validationSchema={layout.schema}
validateOnChange={false}
>
{({ errors, handleChange, values }) => {
return (
<Form>
<Modal.Body>
<Flex direction="column" alignItems="stretch" gap={1}>
<Grid.Root gap={5}>
{layout.form.map((row) => {
return row.map((input) => {
return (
<Grid.Item
key={input.name}
col={input.size}
xs={12}
direction="column"
alignItems="stretch"
>
<Input
{...input}
error={errors[input.name]}
onChange={handleChange}
value={values[input.name]}
providerToEditName={providerToEditName}
/>
</Grid.Item>
);
});
})}
</Grid.Root>
</Flex>
</Modal.Body>
<Modal.Footer>
<Button variant="tertiary" onClick={onToggle} type="button">
{formatMessage({
id: 'app.components.Button.cancel',
defaultMessage: 'Cancel',
})}
</Button>
<Button type="submit" loading={isSubmiting}>
{formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
</Button>
</Modal.Footer>
</Form>
);
}}
</Formik>
</Modal.Content>
</Modal.Root>
);
};
FormModal.defaultProps = {
initialData: null,
providerToEditName: null,
};
FormModal.propTypes = {
headerBreadcrumbs: PropTypes.arrayOf(PropTypes.string).isRequired,
initialData: PropTypes.object,
layout: PropTypes.shape({
form: PropTypes.arrayOf(PropTypes.array),
schema: PropTypes.object,
}).isRequired,
isOpen: PropTypes.bool.isRequired,
isSubmiting: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
providerToEditName: PropTypes.string,
};
export default FormModal;

View File

@@ -0,0 +1,31 @@
import { Box } from '@strapi/design-system';
import { styled, css } from 'styled-components';
const activeCheckboxWrapperStyles = css`
background: ${(props) => props.theme.colors.primary100};
#cog {
opacity: 1;
}
`;
const CheckboxWrapper = styled(Box)`
display: flex;
justify-content: space-between;
align-items: center;
#cog {
opacity: 0;
path {
fill: ${(props) => props.theme.colors.primary600};
}
}
/* Show active style both on hover and when the action is selected */
${(props) => props.isActive && activeCheckboxWrapperStyles}
&:hover {
${activeCheckboxWrapperStyles}
}
`;
export default CheckboxWrapper;

View File

@@ -0,0 +1,122 @@
import React, { useCallback, useMemo } from 'react';
import { Box, Checkbox, Flex, Typography, Grid, VisuallyHidden } from '@strapi/design-system';
import { Cog } from '@strapi/icons';
import get from 'lodash/get';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { styled } from 'styled-components';
import { useUsersPermissions } from '../../../contexts/UsersPermissionsContext';
import CheckboxWrapper from './CheckboxWrapper';
const Border = styled.div`
flex: 1;
align-self: center;
border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
`;
const SubCategory = ({ subCategory }) => {
const { formatMessage } = useIntl();
const { onChange, onChangeSelectAll, onSelectedAction, selectedAction, modifiedData } =
useUsersPermissions();
const currentScopedModifiedData = useMemo(() => {
return get(modifiedData, subCategory.name, {});
}, [modifiedData, subCategory]);
const hasAllActionsSelected = useMemo(() => {
return Object.values(currentScopedModifiedData).every((action) => action.enabled === true);
}, [currentScopedModifiedData]);
const hasSomeActionsSelected = useMemo(() => {
return (
Object.values(currentScopedModifiedData).some((action) => action.enabled === true) &&
!hasAllActionsSelected
);
}, [currentScopedModifiedData, hasAllActionsSelected]);
const handleChangeSelectAll = useCallback(
({ target: { name } }) => {
onChangeSelectAll({ target: { name, value: !hasAllActionsSelected } });
},
[hasAllActionsSelected, onChangeSelectAll]
);
const isActionSelected = useCallback(
(actionName) => {
return selectedAction === actionName;
},
[selectedAction]
);
return (
<Box>
<Flex justifyContent="space-between" alignItems="center">
<Box paddingRight={4}>
<Typography variant="sigma" textColor="neutral600">
{subCategory.label}
</Typography>
</Box>
<Border />
<Box paddingLeft={4}>
<Checkbox
name={subCategory.name}
checked={hasSomeActionsSelected ? 'indeterminate' : hasAllActionsSelected}
onCheckedChange={(value) =>
handleChangeSelectAll({ target: { name: subCategory.name, value } })
}
>
{formatMessage({ id: 'app.utils.select-all', defaultMessage: 'Select all' })}
</Checkbox>
</Box>
</Flex>
<Flex paddingTop={6} paddingBottom={6}>
<Grid.Root gap={2} style={{ flex: 1 }}>
{subCategory.actions.map((action) => {
const name = `${action.name}.enabled`;
return (
<Grid.Item col={6} key={action.name} direction="column" alignItems="stretch">
<CheckboxWrapper isActive={isActionSelected(action.name)} padding={2} hasRadius>
<Checkbox
checked={get(modifiedData, name, false)}
name={name}
onCheckedChange={(value) => onChange({ target: { name, value } })}
>
{action.label}
</Checkbox>
<button
type="button"
onClick={() => onSelectedAction(action.name)}
style={{ display: 'inline-flex', alignItems: 'center' }}
>
<VisuallyHidden tag="span">
{formatMessage(
{
id: 'app.utils.show-bound-route',
defaultMessage: 'Show bound route for {route}',
},
{
route: action.name,
}
)}
</VisuallyHidden>
<Cog id="cog" cursor="pointer" />
</button>
</CheckboxWrapper>
</Grid.Item>
);
})}
</Grid.Root>
</Flex>
</Box>
);
};
SubCategory.propTypes = {
subCategory: PropTypes.object.isRequired,
};
export default SubCategory;

View File

@@ -0,0 +1,55 @@
import React, { useMemo } from 'react';
import { Box } from '@strapi/design-system';
import sortBy from 'lodash/sortBy';
import PropTypes from 'prop-types';
import SubCategory from './SubCategory';
const PermissionRow = ({ name, permissions }) => {
const subCategories = useMemo(() => {
return sortBy(
Object.values(permissions.controllers).reduce((acc, curr, index) => {
const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;
const actions = sortBy(
Object.keys(curr).reduce((acc, current) => {
return [
...acc,
{
...curr[current],
label: current,
name: `${currentName}.${current}`,
},
];
}, []),
'label'
);
return [
...acc,
{
actions,
label: Object.keys(permissions.controllers)[index],
name: currentName,
},
];
}, []),
'label'
);
}, [name, permissions]);
return (
<Box padding={6}>
{subCategories.map((subCategory) => (
<SubCategory key={subCategory.name} subCategory={subCategory} />
))}
</Box>
);
};
PermissionRow.propTypes = {
name: PropTypes.string.isRequired,
permissions: PropTypes.object.isRequired,
};
export default PermissionRow;

View File

@@ -0,0 +1,47 @@
import React, { useReducer } from 'react';
import { Accordion, Flex } from '@strapi/design-system';
import { useIntl } from 'react-intl';
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
import formatPluginName from '../../utils/formatPluginName';
import init from './init';
import PermissionRow from './PermissionRow';
import { initialState, reducer } from './reducer';
const Permissions = () => {
const { modifiedData } = useUsersPermissions();
const { formatMessage } = useIntl();
const [{ collapses }] = useReducer(reducer, initialState, (state) => init(state, modifiedData));
return (
<Accordion.Root size="M">
<Flex direction="column" alignItems="stretch" gap={1}>
{collapses.map((collapse, index) => (
<Accordion.Item key={collapse.name} value={collapse.name}>
<Accordion.Header variant={index % 2 === 0 ? 'secondary' : undefined}>
<Accordion.Trigger
caretPosition="right"
description={formatMessage(
{
id: 'users-permissions.Plugin.permissions.plugins.description',
defaultMessage: 'Define all allowed actions for the {name} plugin.',
},
{ name: collapse.name }
)}
>
{formatPluginName(collapse.name)}
</Accordion.Trigger>
</Accordion.Header>
<Accordion.Content>
<PermissionRow permissions={modifiedData[collapse.name]} name={collapse.name} />
</Accordion.Content>
</Accordion.Item>
))}
</Flex>
</Accordion.Root>
);
};
export default Permissions;

View File

@@ -0,0 +1,9 @@
const init = (initialState, permissions) => {
const collapses = Object.keys(permissions)
.sort()
.map((name) => ({ name, isOpen: false }));
return { ...initialState, collapses };
};
export default init;

View File

@@ -0,0 +1,27 @@
import { produce } from 'immer';
const initialState = {
collapses: [],
};
const reducer = (state, action) =>
// eslint-disable-next-line consistent-return
produce(state, (draftState) => {
switch (action.type) {
case 'TOGGLE_COLLAPSE': {
draftState.collapses = state.collapses.map((collapse, index) => {
if (index === action.index) {
return { ...collapse, isOpen: !collapse.isOpen };
}
return { ...collapse, isOpen: false };
});
break;
}
default:
return draftState;
}
});
export { initialState, reducer };

View File

@@ -0,0 +1,64 @@
import * as React from 'react';
import { Flex, Grid, Typography } from '@strapi/design-system';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import without from 'lodash/without';
import { useIntl } from 'react-intl';
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
import BoundRoute from '../BoundRoute';
const Policies = () => {
const { formatMessage } = useIntl();
const { selectedAction, routes } = useUsersPermissions();
const path = without(selectedAction.split('.'), 'controllers');
const controllerRoutes = get(routes, path[0]);
const pathResolved = path.slice(1).join('.');
const displayedRoutes = isEmpty(controllerRoutes)
? []
: controllerRoutes.filter((o) => o.handler.endsWith(pathResolved));
return (
<Grid.Item
col={5}
background="neutral150"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
style={{ minHeight: '100%' }}
direction="column"
alignItems="stretch"
>
{selectedAction ? (
<Flex direction="column" alignItems="stretch" gap={2}>
{displayedRoutes.map((route, key) => (
// eslint-disable-next-line react/no-array-index-key
<BoundRoute key={key} route={route} />
))}
</Flex>
) : (
<Flex direction="column" alignItems="stretch" gap={2}>
<Typography variant="delta" tag="h3">
{formatMessage({
id: 'users-permissions.Policies.header.title',
defaultMessage: 'Advanced settings',
})}
</Typography>
<Typography tag="p" textColor="neutral600">
{formatMessage({
id: 'users-permissions.Policies.header.hint',
defaultMessage:
"Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
})}
</Typography>
</Flex>
)}
</Grid.Item>
);
};
export default Policies;

View File

@@ -0,0 +1,103 @@
import React, { forwardRef, memo, useImperativeHandle, useReducer } from 'react';
import { Flex, Grid, Typography } from '@strapi/design-system';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { UsersPermissionsProvider } from '../../contexts/UsersPermissionsContext';
import getTrad from '../../utils/getTrad';
import Permissions from '../Permissions';
import Policies from '../Policies';
import init from './init';
import reducer, { initialState } from './reducer';
const UsersPermissions = forwardRef(({ permissions, routes }, ref) => {
const { formatMessage } = useIntl();
const [state, dispatch] = useReducer(reducer, initialState, (state) =>
init(state, permissions, routes)
);
useImperativeHandle(ref, () => ({
getPermissions() {
return {
permissions: state.modifiedData,
};
},
resetForm() {
dispatch({ type: 'ON_RESET' });
},
setFormAfterSubmit() {
dispatch({ type: 'ON_SUBMIT_SUCCEEDED' });
},
}));
const handleChange = ({ target: { name, value } }) =>
dispatch({
type: 'ON_CHANGE',
keys: name.split('.'),
value: value === 'empty__string_value' ? '' : value,
});
const handleChangeSelectAll = ({ target: { name, value } }) =>
dispatch({
type: 'ON_CHANGE_SELECT_ALL',
keys: name.split('.'),
value,
});
const handleSelectedAction = (actionToSelect) =>
dispatch({
type: 'SELECT_ACTION',
actionToSelect,
});
const providerValue = {
...state,
onChange: handleChange,
onChangeSelectAll: handleChangeSelectAll,
onSelectedAction: handleSelectedAction,
};
return (
<UsersPermissionsProvider value={providerValue}>
<Grid.Root gap={0} shadow="filterShadow" hasRadius background="neutral0">
<Grid.Item
col={7}
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
direction="column"
alignItems="stretch"
>
<Flex direction="column" alignItems="stretch" gap={6}>
<Flex direction="column" alignItems="stretch" gap={2}>
<Typography variant="delta" tag="h2">
{formatMessage({
id: getTrad('Plugins.header.title'),
defaultMessage: 'Permissions',
})}
</Typography>
<Typography tag="p" textColor="neutral600">
{formatMessage({
id: getTrad('Plugins.header.description'),
defaultMessage: 'Only actions bound by a route are listed below.',
})}
</Typography>
</Flex>
<Permissions />
</Flex>
</Grid.Item>
<Policies />
</Grid.Root>
</UsersPermissionsProvider>
);
});
UsersPermissions.propTypes = {
permissions: PropTypes.object.isRequired,
routes: PropTypes.object.isRequired,
};
export default memo(UsersPermissions);

View File

@@ -0,0 +1,10 @@
const init = (state, permissions, routes) => {
return {
...state,
initialData: permissions,
modifiedData: permissions,
routes,
};
};
export default init;

View File

@@ -0,0 +1,62 @@
/* eslint-disable consistent-return */
import { produce } from 'immer';
import get from 'lodash/get';
import set from 'lodash/set';
import take from 'lodash/take';
export const initialState = {
initialData: {},
modifiedData: {},
routes: {},
selectedAction: '',
policies: [],
};
const reducer = (state, action) =>
produce(state, (draftState) => {
switch (action.type) {
case 'ON_CHANGE': {
const keysLength = action.keys.length;
const isChangingCheckbox = action.keys[keysLength - 1] === 'enabled';
if (action.value && isChangingCheckbox) {
const selectedAction = take(action.keys, keysLength - 1).join('.');
draftState.selectedAction = selectedAction;
}
set(draftState, ['modifiedData', ...action.keys], action.value);
break;
}
case 'ON_CHANGE_SELECT_ALL': {
const pathToValue = ['modifiedData', ...action.keys];
const oldValues = get(state, pathToValue, {});
const updatedValues = Object.keys(oldValues).reduce((acc, current) => {
acc[current] = { ...oldValues[current], enabled: action.value };
return acc;
}, {});
set(draftState, pathToValue, updatedValues);
break;
}
case 'ON_RESET': {
draftState.modifiedData = state.initialData;
break;
}
case 'ON_SUBMIT_SUCCEEDED': {
draftState.initialData = state.modifiedData;
break;
}
case 'SELECT_ACTION': {
const { actionToSelect } = action;
draftState.selectedAction = actionToSelect === state.selectedAction ? '' : actionToSelect;
break;
}
default:
return draftState;
}
});
export default reducer;

View File

@@ -0,0 +1,29 @@
export const PERMISSIONS = {
// Roles
accessRoles: [
{ action: 'plugin::users-permissions.roles.create', subject: null },
{ action: 'plugin::users-permissions.roles.read', subject: null },
],
createRole: [{ action: 'plugin::users-permissions.roles.create', subject: null }],
deleteRole: [{ action: 'plugin::users-permissions.roles.delete', subject: null }],
readRoles: [{ action: 'plugin::users-permissions.roles.read', subject: null }],
updateRole: [{ action: 'plugin::users-permissions.roles.update', subject: null }],
// AdvancedSettings
readAdvancedSettings: [
{ action: 'plugin::users-permissions.advanced-settings.read', subject: null },
],
updateAdvancedSettings: [
{ action: 'plugin::users-permissions.advanced-settings.update', subject: null },
],
// Emails
readEmailTemplates: [{ action: 'plugin::users-permissions.email-templates.read', subject: null }],
updateEmailTemplates: [
{ action: 'plugin::users-permissions.email-templates.update', subject: null },
],
// Providers
readProviders: [{ action: 'plugin::users-permissions.providers.read', subject: null }],
updateProviders: [{ action: 'plugin::users-permissions.providers.update', subject: null }],
};

View File

@@ -0,0 +1,18 @@
import React, { createContext, useContext } from 'react';
import PropTypes from 'prop-types';
const UsersPermissions = createContext({});
const UsersPermissionsProvider = ({ children, value }) => {
return <UsersPermissions.Provider value={value}>{children}</UsersPermissions.Provider>;
};
const useUsersPermissions = () => useContext(UsersPermissions);
UsersPermissionsProvider.propTypes = {
children: PropTypes.node.isRequired,
value: PropTypes.object.isRequired,
};
export { UsersPermissions, UsersPermissionsProvider, useUsersPermissions };

View File

@@ -0,0 +1,97 @@
import { strapi as pkgStrapi } from '../../package.json';
import { PERMISSIONS } from './constants';
import getTrad from './utils/getTrad';
import { prefixPluginTranslations } from './utils/prefixPluginTranslations';
const name = pkgStrapi.name;
export default {
register(app) {
// Create the plugin's settings section
app.createSettingSection(
{
id: 'users-permissions',
intlLabel: {
id: getTrad('Settings.section-label'),
defaultMessage: 'Users & Permissions plugin',
},
},
[
{
intlLabel: {
id: 'global.roles',
defaultMessage: 'Roles',
},
id: 'roles',
to: `users-permissions/roles`,
Component: () => import('./pages/Roles'),
permissions: PERMISSIONS.accessRoles,
},
{
intlLabel: {
id: getTrad('HeaderNav.link.providers'),
defaultMessage: 'Providers',
},
id: 'providers',
to: `users-permissions/providers`,
Component: () => import('./pages/Providers'),
permissions: PERMISSIONS.readProviders,
},
{
intlLabel: {
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
},
id: 'email-templates',
to: `users-permissions/email-templates`,
Component: () =>
import('./pages/EmailTemplates').then((mod) => ({
default: mod.ProtectedEmailTemplatesPage,
})),
permissions: PERMISSIONS.readEmailTemplates,
},
{
intlLabel: {
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
},
id: 'advanced-settings',
to: `users-permissions/advanced-settings`,
Component: () =>
import('./pages/AdvancedSettings').then((mod) => ({
default: mod.ProtectedAdvancedSettingsPage,
})),
permissions: PERMISSIONS.readAdvancedSettings,
},
]
);
app.registerPlugin({
id: 'users-permissions',
name,
});
},
bootstrap() {},
async registerTrads({ locales }) {
const importedTrads = await Promise.all(
locales.map((locale) => {
return import(`./translations/${locale}.json`)
.then(({ default: data }) => {
return {
data: prefixPluginTranslations(data, 'users-permissions'),
locale,
};
})
.catch(() => {
return {
data: {},
locale,
};
});
})
);
return Promise.resolve(importedTrads);
},
};

View File

@@ -0,0 +1,214 @@
import * as React from 'react';
import { Box, Button, Flex, Grid, Typography, useNotifyAT } from '@strapi/design-system';
import { Check } from '@strapi/icons';
import {
useAPIErrorHandler,
Page,
Form,
InputRenderer,
useNotification,
useFetchClient,
useRBAC,
Layouts,
} from '@strapi/strapi/admin';
import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { PERMISSIONS } from '../../constants';
import { getTrad } from '../../utils';
import layout from './utils/layout';
import schema from './utils/schema';
const ProtectedAdvancedSettingsPage = () => (
<Page.Protect permissions={PERMISSIONS.readAdvancedSettings}>
<AdvancedSettingsPage />
</Page.Protect>
);
const AdvancedSettingsPage = () => {
const { formatMessage } = useIntl();
const { toggleNotification } = useNotification();
const { notifyStatus } = useNotifyAT();
const queryClient = useQueryClient();
const { get, put } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler();
const {
isLoading: isLoadingForPermissions,
allowedActions: { canUpdate },
} = useRBAC({ update: PERMISSIONS.updateAdvancedSettings });
const { isLoading: isLoadingData, data } = useQuery(
['users-permissions', 'advanced'],
async () => {
const { data } = await get('/users-permissions/advanced');
return data;
},
{
onSuccess() {
notifyStatus(
formatMessage({
id: getTrad('Form.advancedSettings.data.loaded'),
defaultMessage: 'Advanced settings data has been loaded',
})
);
},
onError() {
toggleNotification({
type: 'danger',
message: formatMessage({
id: getTrad('notification.error'),
defaultMessage: 'An error occured',
}),
});
},
}
);
const isLoading = isLoadingForPermissions || isLoadingData;
const submitMutation = useMutation((body) => put('/users-permissions/advanced', body), {
async onSuccess() {
await queryClient.invalidateQueries(['users-permissions', 'advanced']);
toggleNotification({
type: 'success',
message: formatMessage({
id: getTrad('notification.success.saved'),
defaultMessage: 'Saved',
}),
});
},
onError(error) {
toggleNotification({
type: 'danger',
message: formatAPIError(error),
});
},
refetchActive: true,
});
const { isLoading: isSubmittingForm } = submitMutation;
const handleSubmit = async (body) => {
submitMutation.mutate({
...body,
email_confirmation_redirection: body.email_confirmation
? body.email_confirmation_redirection
: '',
});
};
if (isLoading) {
return <Page.Loading />;
}
return (
<Page.Main aria-busy={isSubmittingForm}>
<Page.Title>
{formatMessage(
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
{
name: formatMessage({
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
}),
}
)}
</Page.Title>
<Form onSubmit={handleSubmit} initialValues={data.settings} validationSchema={schema}>
{({ values, isSubmitting, modified }) => {
return (
<>
<Layouts.Header
title={formatMessage({
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
})}
primaryAction={
<Button
loading={isSubmitting}
type="submit"
disabled={!modified || !canUpdate}
startIcon={<Check />}
size="S"
>
{formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
</Button>
}
/>
<Layouts.Content>
<Box
background="neutral0"
hasRadius
shadow="filterShadow"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
>
<Flex direction="column" alignItems="stretch" gap={4}>
<Typography variant="delta" tag="h2">
{formatMessage({
id: 'global.settings',
defaultMessage: 'Settings',
})}
</Typography>
<Grid.Root gap={6}>
{[
{
label: {
id: getTrad('EditForm.inputSelect.label.role'),
defaultMessage: 'Default role for authenticated users',
},
hint: {
id: getTrad('EditForm.inputSelect.description.role'),
defaultMessage:
'It will attach the new authenticated user to the selected role.',
},
options: data.roles.map((role) => ({
label: role.name,
value: role.type,
})),
name: 'default_role',
size: 6,
type: 'enumeration',
},
...layout,
].map(({ size, ...field }) => (
<Grid.Item
key={field.name}
col={size}
direction="column"
alignItems="stretch"
>
<InputRenderer
{...field}
disabled={
field.name === 'email_confirmation_redirection' &&
values.email_confirmation === false
}
label={formatMessage(field.label)}
hint={field.hint ? formatMessage(field.hint) : undefined}
placeholder={
field.placeholder ? formatMessage(field.placeholder) : undefined
}
/>
</Grid.Item>
))}
</Grid.Root>
</Flex>
</Box>
</Layouts.Content>
</>
);
}}
</Form>
</Page.Main>
);
};
export { ProtectedAdvancedSettingsPage, AdvancedSettingsPage };

View File

@@ -0,0 +1,81 @@
import { getTrad } from '../../../utils';
const layout = [
{
label: {
id: getTrad('EditForm.inputToggle.label.email'),
defaultMessage: 'One account per email address',
},
hint: {
id: getTrad('EditForm.inputToggle.description.email'),
defaultMessage:
'Disallow the user to create multiple accounts using the same email address with different authentication providers.',
},
name: 'unique_email',
type: 'boolean',
size: 12,
},
{
label: {
id: getTrad('EditForm.inputToggle.label.sign-up'),
defaultMessage: 'Enable sign-ups',
},
hint: {
id: getTrad('EditForm.inputToggle.description.sign-up'),
defaultMessage:
'When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.',
},
name: 'allow_register',
type: 'boolean',
size: 12,
},
{
label: {
id: getTrad('EditForm.inputToggle.label.email-reset-password'),
defaultMessage: 'Reset password page',
},
hint: {
id: getTrad('EditForm.inputToggle.description.email-reset-password'),
defaultMessage: "URL of your application's reset password page.",
},
placeholder: {
id: getTrad('EditForm.inputToggle.placeholder.email-reset-password'),
defaultMessage: 'ex: https://youtfrontend.com/reset-password',
},
name: 'email_reset_password',
type: 'string',
size: 12,
},
{
label: {
id: getTrad('EditForm.inputToggle.label.email-confirmation'),
defaultMessage: 'Enable email confirmation',
},
hint: {
id: getTrad('EditForm.inputToggle.description.email-confirmation'),
defaultMessage: 'When enabled (ON), new registered users receive a confirmation email.',
},
name: 'email_confirmation',
type: 'boolean',
size: 12,
},
{
label: {
id: getTrad('EditForm.inputToggle.label.email-confirmation-redirection'),
defaultMessage: 'Redirection url',
},
hint: {
id: getTrad('EditForm.inputToggle.description.email-confirmation-redirection'),
defaultMessage: 'After you confirmed your email, choose where you will be redirected.',
},
placeholder: {
id: getTrad('EditForm.inputToggle.placeholder.email-confirmation-redirection'),
defaultMessage: 'ex: https://youtfrontend.com/email-confirmation',
},
name: 'email_confirmation_redirection',
type: 'string',
size: 12,
},
];
export default layout;

View File

@@ -0,0 +1,22 @@
import { translatedErrors } from '@strapi/strapi/admin';
import * as yup from 'yup';
// eslint-disable-next-line prefer-regex-literals
const URL_REGEX = new RegExp('(^$)|((.+:\\/\\/.*)(d*)\\/?(.*))');
const schema = yup.object().shape({
email_confirmation_redirection: yup.mixed().when('email_confirmation', {
is: true,
then: yup.string().matches(URL_REGEX).required(),
otherwise: yup.string().nullable(),
}),
email_reset_password: yup
.string(translatedErrors.string)
.matches(URL_REGEX, {
id: translatedErrors.regex.id,
defaultMessage: 'This is not a valid URL',
})
.nullable(),
});
export default schema;

View File

@@ -0,0 +1,156 @@
import * as React from 'react';
import { Button, Grid, Modal, Breadcrumbs, Crumb, VisuallyHidden } from '@strapi/design-system';
import { Form, InputRenderer } from '@strapi/strapi/admin';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { getTrad } from '../../../utils';
import schema from '../utils/schema';
const EmailForm = ({ template = {}, onToggle, open, onSubmit }) => {
const { formatMessage } = useIntl();
return (
<Modal.Root open={open} onOpenChange={onToggle}>
<Modal.Content>
<Modal.Header>
<Breadcrumbs
label={`${formatMessage({
id: getTrad('PopUpForm.header.edit.email-templates'),
defaultMessage: 'Edit email template',
})}, ${
template.display
? formatMessage({
id: getTrad(template.display),
defaultMessage: template.display,
})
: ''
}`}
>
<Crumb>
{formatMessage({
id: getTrad('PopUpForm.header.edit.email-templates'),
defaultMessage: 'Edit email template',
})}
</Crumb>
<Crumb isCurrent>
{template.display
? formatMessage({ id: getTrad(template.display), defaultMessage: template.display })
: ''}
</Crumb>
</Breadcrumbs>
<VisuallyHidden>
<Modal.Title>
{`${formatMessage({
id: getTrad('PopUpForm.header.edit.email-templates'),
defaultMessage: 'Edit email template',
})}, ${template.display ? formatMessage({ id: getTrad(template.display), defaultMessage: template.display }) : ''}`}
</Modal.Title>
</VisuallyHidden>
</Modal.Header>
<Form onSubmit={onSubmit} initialValues={template} validationSchema={schema}>
{({ isSubmitting }) => {
return (
<>
<Modal.Body>
<Grid.Root gap={5}>
{[
{
label: formatMessage({
id: getTrad('PopUpForm.Email.options.from.name.label'),
defaultMessage: 'Shipper name',
}),
name: 'options.from.name',
size: 6,
type: 'string',
},
{
label: formatMessage({
id: getTrad('PopUpForm.Email.options.from.email.label'),
defaultMessage: 'Shipper email',
}),
name: 'options.from.email',
size: 6,
type: 'string',
},
{
label: formatMessage({
id: getTrad('PopUpForm.Email.options.response_email.label'),
defaultMessage: 'Response email',
}),
name: 'options.response_email',
size: 6,
type: 'string',
},
{
label: formatMessage({
id: getTrad('PopUpForm.Email.options.object.label'),
defaultMessage: 'Subject',
}),
name: 'options.object',
size: 6,
type: 'string',
},
{
label: formatMessage({
id: getTrad('PopUpForm.Email.options.message.label'),
defaultMessage: 'Message',
}),
name: 'options.message',
size: 12,
type: 'text',
},
].map(({ size, ...field }) => (
<Grid.Item
key={field.name}
col={size}
direction="column"
alignItems="stretch"
>
<InputRenderer {...field} />
</Grid.Item>
))}
</Grid.Root>
</Modal.Body>
<Modal.Footer>
<Modal.Close>
<Button variant="tertiary">Cancel</Button>
</Modal.Close>
<Button loading={isSubmitting} type="submit">
Finish
</Button>
</Modal.Footer>
</>
);
}}
</Form>
</Modal.Content>
</Modal.Root>
);
};
EmailForm.defaultProps = {
template: {},
};
EmailForm.propTypes = {
template: PropTypes.shape({
display: PropTypes.string,
icon: PropTypes.string,
options: PropTypes.shape({
from: PropTypes.shape({
name: PropTypes.string,
email: PropTypes.string,
}),
message: PropTypes.string,
object: PropTypes.string,
response_email: PropTypes.string,
}),
}),
open: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
};
export default EmailForm;

View File

@@ -0,0 +1,131 @@
import * as React from 'react';
import {
IconButton,
Table,
Tbody,
Td,
Th,
Thead,
Tr,
Typography,
VisuallyHidden,
Box,
} from '@strapi/design-system';
import { Check, Pencil, ArrowClockwise as Refresh } from '@strapi/icons';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { getTrad } from '../../../utils';
const EmailTable = ({ canUpdate, onEditClick }) => {
const { formatMessage } = useIntl();
return (
<Table colCount={3} rowCount={3}>
<Thead>
<Tr>
<Th width="1%">
<VisuallyHidden>
{formatMessage({
id: getTrad('Email.template.table.icon.label'),
defaultMessage: 'icon',
})}
</VisuallyHidden>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({
id: getTrad('Email.template.table.name.label'),
defaultMessage: 'name',
})}
</Typography>
</Th>
<Th width="1%">
<VisuallyHidden>
{formatMessage({
id: getTrad('Email.template.table.action.label'),
defaultMessage: 'action',
})}
</VisuallyHidden>
</Th>
</Tr>
</Thead>
<Tbody>
<Tr cursor="pointer" onClick={() => onEditClick('reset_password')}>
<Td>
<Box width="3.2rem" height="3.2rem" padding="0.8rem">
<Refresh
aria-label={formatMessage({
id: 'global.reset-password',
defaultMessage: 'Reset password',
})}
/>
</Box>
</Td>
<Td>
<Typography>
{formatMessage({
id: 'global.reset-password',
defaultMessage: 'Reset password',
})}
</Typography>
</Td>
<Td onClick={(e) => e.stopPropagation()}>
<IconButton
onClick={() => onEditClick('reset_password')}
label={formatMessage({
id: getTrad('Email.template.form.edit.label'),
defaultMessage: 'Edit a template',
})}
variant="ghost"
disabled={!canUpdate}
>
<Pencil />
</IconButton>
</Td>
</Tr>
<Tr cursor="pointer" onClick={() => onEditClick('email_confirmation')}>
<Td>
<Box width="3.2rem" height="3.2rem" padding="0.8rem">
<Check
aria-label={formatMessage({
id: getTrad('Email.template.email_confirmation'),
defaultMessage: 'Email address confirmation',
})}
/>
</Box>
</Td>
<Td>
<Typography>
{formatMessage({
id: getTrad('Email.template.email_confirmation'),
defaultMessage: 'Email address confirmation',
})}
</Typography>
</Td>
<Td onClick={(e) => e.stopPropagation()}>
<IconButton
onClick={() => onEditClick('email_confirmation')}
label={formatMessage({
id: getTrad('Email.template.form.edit.label'),
defaultMessage: 'Edit a template',
})}
variant="ghost"
disabled={!canUpdate}
>
<Pencil />
</IconButton>
</Td>
</Tr>
</Tbody>
</Table>
);
};
EmailTable.propTypes = {
canUpdate: PropTypes.bool.isRequired,
onEditClick: PropTypes.func.isRequired,
};
export default EmailTable;

View File

@@ -0,0 +1,148 @@
import * as React from 'react';
import { useTracking } from '@strapi/admin/strapi-admin';
import { useNotifyAT } from '@strapi/design-system';
import {
Page,
useAPIErrorHandler,
useNotification,
useFetchClient,
useRBAC,
Layouts,
} from '@strapi/strapi/admin';
import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { PERMISSIONS } from '../../constants';
import { getTrad } from '../../utils';
import EmailForm from './components/EmailForm';
import EmailTable from './components/EmailTable';
const ProtectedEmailTemplatesPage = () => (
<Page.Protect permissions={PERMISSIONS.readEmailTemplates}>
<EmailTemplatesPage />
</Page.Protect>
);
const EmailTemplatesPage = () => {
const { formatMessage } = useIntl();
const { trackUsage } = useTracking();
const { notifyStatus } = useNotifyAT();
const { toggleNotification } = useNotification();
const queryClient = useQueryClient();
const { get, put } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler();
const [isModalOpen, setIsModalOpen] = React.useState(false);
const [templateToEdit, setTemplateToEdit] = React.useState(null);
const {
isLoading: isLoadingForPermissions,
allowedActions: { canUpdate },
} = useRBAC({ update: PERMISSIONS.updateEmailTemplates });
const { isLoading: isLoadingData, data } = useQuery(
['users-permissions', 'email-templates'],
async () => {
const { data } = await get('/users-permissions/email-templates');
return data;
},
{
onSuccess() {
notifyStatus(
formatMessage({
id: getTrad('Email.template.data.loaded'),
defaultMessage: 'Email templates has been loaded',
})
);
},
onError(error) {
toggleNotification({
type: 'danger',
message: formatAPIError(error),
});
},
}
);
const isLoading = isLoadingForPermissions || isLoadingData;
const handleToggle = () => {
setIsModalOpen((prev) => !prev);
};
const handleEditClick = (template) => {
setTemplateToEdit(template);
handleToggle();
};
const submitMutation = useMutation(
(body) => put('/users-permissions/email-templates', { 'email-templates': body }),
{
async onSuccess() {
await queryClient.invalidateQueries(['users-permissions', 'email-templates']);
toggleNotification({
type: 'success',
message: formatMessage({ id: 'notification.success.saved', defaultMessage: 'Saved' }),
});
trackUsage('didEditEmailTemplates');
handleToggle();
},
onError(error) {
toggleNotification({
type: 'danger',
message: formatAPIError(error),
});
},
refetchActive: true,
}
);
const handleSubmit = (body) => {
trackUsage('willEditEmailTemplates');
const editedTemplates = { ...data, [templateToEdit]: body };
submitMutation.mutate(editedTemplates);
};
if (isLoading) {
return <Page.Loading />;
}
return (
<Page.Main aria-busy={submitMutation.isLoading}>
<Page.Title>
{formatMessage(
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
{
name: formatMessage({
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
}),
}
)}
</Page.Title>
<Layouts.Header
title={formatMessage({
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
})}
/>
<Layouts.Content>
<EmailTable onEditClick={handleEditClick} canUpdate={canUpdate} />
<EmailForm
template={data[templateToEdit]}
onToggle={handleToggle}
open={isModalOpen}
onSubmit={handleSubmit}
/>
</Layouts.Content>
</Page.Main>
);
};
export { ProtectedEmailTemplatesPage, EmailTemplatesPage };

View File

@@ -0,0 +1,34 @@
import { translatedErrors } from '@strapi/strapi/admin';
import * as yup from 'yup';
const schema = yup.object().shape({
options: yup
.object()
.shape({
from: yup
.object()
.shape({
name: yup.string().required({
id: translatedErrors.required.id,
defaultMessage: 'This field is required',
}),
email: yup.string().email(translatedErrors.email).required({
id: translatedErrors.required.id,
defaultMessage: 'This field is required',
}),
})
.required(),
response_email: yup.string().email(translatedErrors.email),
object: yup.string().required({
id: translatedErrors.required.id,
defaultMessage: 'This field is required',
}),
message: yup.string().required({
id: translatedErrors.required.id,
defaultMessage: 'This field is required',
}),
})
.required(translatedErrors.required.id),
});
export default schema;

View File

@@ -0,0 +1,262 @@
import * as React from 'react';
import { useTracking, Layouts } from '@strapi/admin/strapi-admin';
import {
IconButton,
Table,
Tbody,
Td,
Th,
Thead,
Tr,
Typography,
VisuallyHidden,
useCollator,
} from '@strapi/design-system';
import { Pencil } from '@strapi/icons';
import {
Page,
useAPIErrorHandler,
useNotification,
useFetchClient,
useRBAC,
} from '@strapi/strapi/admin';
import upperFirst from 'lodash/upperFirst';
import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import FormModal from '../../components/FormModal';
import { PERMISSIONS } from '../../constants';
import { getTrad } from '../../utils';
import forms from './utils/forms';
export const ProvidersPage = () => {
const { formatMessage, locale } = useIntl();
const queryClient = useQueryClient();
const { trackUsage } = useTracking();
const [isOpen, setIsOpen] = React.useState(false);
const [providerToEditName, setProviderToEditName] = React.useState(null);
const { toggleNotification } = useNotification();
const { get, put } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler();
const formatter = useCollator(locale, {
sensitivity: 'base',
});
const {
isLoading: isLoadingPermissions,
allowedActions: { canUpdate },
} = useRBAC({ update: PERMISSIONS.updateProviders });
const { isLoading: isLoadingData, data } = useQuery(
['users-permissions', 'get-providers'],
async () => {
const { data } = await get('/users-permissions/providers');
return data;
},
{
initialData: {},
}
);
const submitMutation = useMutation((body) => put('/users-permissions/providers', body), {
async onSuccess() {
await queryClient.invalidateQueries(['users-permissions', 'get-providers']);
toggleNotification({
type: 'success',
message: formatMessage({ id: getTrad('notification.success.submit') }),
});
trackUsage('didEditAuthenticationProvider');
handleToggleModal();
},
onError(error) {
toggleNotification({
type: 'danger',
message: formatAPIError(error),
});
},
refetchActive: false,
});
const providers = Object.entries(data)
.reduce((acc, [name, provider]) => {
const { icon, enabled, subdomain } = provider;
acc.push({
name,
icon: icon === 'envelope' ? ['fas', 'envelope'] : ['fab', icon],
enabled,
subdomain,
});
return acc;
}, [])
.sort((a, b) => formatter.compare(a.name, b.name));
const isLoading = isLoadingData || isLoadingPermissions;
const isProviderWithSubdomain = React.useMemo(() => {
if (!providerToEditName) {
return false;
}
const providerToEdit = providers.find((obj) => obj.name === providerToEditName);
return !!providerToEdit?.subdomain;
}, [providers, providerToEditName]);
const layoutToRender = React.useMemo(() => {
if (providerToEditName === 'email') {
return forms.email;
}
if (isProviderWithSubdomain) {
return forms.providersWithSubdomain;
}
return forms.providers;
}, [providerToEditName, isProviderWithSubdomain]);
const handleToggleModal = () => {
setIsOpen((prev) => !prev);
};
const handleClickEdit = (provider) => {
if (canUpdate) {
setProviderToEditName(provider.name);
handleToggleModal();
}
};
const handleSubmit = async (values) => {
trackUsage('willEditAuthenticationProvider');
submitMutation.mutate({ providers: { ...data, [providerToEditName]: values } });
};
if (isLoading) {
return <Page.Loading />;
}
return (
<Layouts.Root>
<Page.Title>
{formatMessage(
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
{
name: formatMessage({
id: getTrad('HeaderNav.link.providers'),
defaultMessage: 'Providers',
}),
}
)}
</Page.Title>
<Page.Main>
<Layouts.Header
title={formatMessage({
id: getTrad('HeaderNav.link.providers'),
defaultMessage: 'Providers',
})}
/>
<Layouts.Content>
<Table colCount={3} rowCount={providers.length + 1}>
<Thead>
<Tr>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: getTrad('Providers.status'), defaultMessage: 'Status' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma">
<VisuallyHidden>
{formatMessage({
id: 'global.settings',
defaultMessage: 'Settings',
})}
</VisuallyHidden>
</Typography>
</Th>
</Tr>
</Thead>
<Tbody>
{providers.map((provider) => (
<Tr
key={provider.name}
onClick={() => (canUpdate ? handleClickEdit(provider) : undefined)}
>
<Td width="45%">
<Typography fontWeight="semiBold" textColor="neutral800">
{provider.name}
</Typography>
</Td>
<Td width="65%">
<Typography
textColor={provider.enabled ? 'success600' : 'danger600'}
data-testid={`enable-${provider.name}`}
>
{provider.enabled
? formatMessage({
id: 'global.enabled',
defaultMessage: 'Enabled',
})
: formatMessage({
id: 'global.disabled',
defaultMessage: 'Disabled',
})}
</Typography>
</Td>
<Td onClick={(e) => e.stopPropagation()}>
{canUpdate && (
<IconButton
onClick={() => handleClickEdit(provider)}
variant="ghost"
label="Edit"
>
<Pencil />
</IconButton>
)}
</Td>
</Tr>
))}
</Tbody>
</Table>
</Layouts.Content>
</Page.Main>
<FormModal
initialData={data[providerToEditName]}
isOpen={isOpen}
isSubmiting={submitMutation.isLoading}
layout={layoutToRender}
headerBreadcrumbs={[
formatMessage({
id: getTrad('PopUpForm.header.edit.providers'),
defaultMessage: 'Edit Provider',
}),
upperFirst(providerToEditName),
]}
onToggle={handleToggleModal}
onSubmit={handleSubmit}
providerToEditName={providerToEditName}
/>
</Layouts.Root>
);
};
const ProtectedProvidersPage = () => (
<Page.Protect permissions={PERMISSIONS.readProviders}>
<ProvidersPage />
</Page.Protect>
);
export default ProtectedProvidersPage;

View File

@@ -0,0 +1,271 @@
import { translatedErrors } from '@strapi/strapi/admin';
import * as yup from 'yup';
import { getTrad } from '../../../utils';
const callbackLabel = {
id: getTrad('PopUpForm.Providers.redirectURL.front-end.label'),
defaultMessage: 'The redirect URL to your front-end app',
};
const callbackPlaceholder = {
id: 'http://www.client-app.com',
defaultMessage: 'http://www.client-app.com',
};
const enabledDescription = {
id: getTrad('PopUpForm.Providers.enabled.description'),
defaultMessage: "If disabled, users won't be able to use this provider.",
};
const enabledLabel = {
id: getTrad('PopUpForm.Providers.enabled.label'),
defaultMessage: 'Enable',
};
const keyLabel = { id: getTrad('PopUpForm.Providers.key.label'), defaultMessage: 'Client ID' };
const hintLabel = {
id: getTrad('PopUpForm.Providers.redirectURL.label'),
defaultMessage: 'The redirect URL to add in your {provider} application configurations',
};
const textPlaceholder = {
id: getTrad('PopUpForm.Providers.key.placeholder'),
defaultMessage: 'TEXT',
};
const secretLabel = {
id: getTrad('PopUpForm.Providers.secret.label'),
defaultMessage: 'Client Secret',
};
const CALLBACK_REGEX = /^$|^[a-z][a-z0-9+.-]*:\/\/[^\s/$.?#](?:[^\s]*[^\s/$.?#])?$/i;
const SUBDOMAIN_REGEX = /^(([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+)(:\d+)?(\/\S*)?$/i;
const forms = {
email: {
form: [
[
{
intlLabel: enabledLabel,
name: 'enabled',
type: 'bool',
description: enabledDescription,
size: 6,
// TODO check if still needed
// validations: {
// required: true,
// },
},
],
],
schema: yup.object().shape({
enabled: yup.bool().required(translatedErrors.required.id),
}),
},
providers: {
form: [
[
{
intlLabel: enabledLabel,
name: 'enabled',
type: 'bool',
description: enabledDescription,
size: 6,
validations: {
required: true,
},
},
],
[
{
intlLabel: keyLabel,
name: 'key',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: secretLabel,
name: 'secret',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: callbackLabel,
placeholder: callbackPlaceholder,
name: 'callback',
type: 'text',
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: hintLabel,
name: 'noName',
type: 'text',
validations: {},
size: 12,
disabled: true,
},
],
],
schema: yup.object().shape({
enabled: yup.bool().required(translatedErrors.required.id),
key: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required.id),
otherwise: yup.string(),
}),
secret: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required.id),
otherwise: yup.string(),
}),
callback: yup.string().when('enabled', {
is: true,
then: yup
.string()
.matches(CALLBACK_REGEX, translatedErrors.regex.id)
.required(translatedErrors.required.id),
otherwise: yup.string(),
}),
}),
},
providersWithSubdomain: {
form: [
[
{
intlLabel: enabledLabel,
name: 'enabled',
type: 'bool',
description: enabledDescription,
size: 6,
validations: {
required: true,
},
},
],
[
{
intlLabel: keyLabel,
name: 'key',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: secretLabel,
name: 'secret',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: {
id: getTrad({ id: 'PopUpForm.Providers.jwksurl.label' }),
defaultMessage: 'JWKS URL',
},
name: 'jwksurl',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: false,
},
},
],
[
{
intlLabel: {
id: getTrad('PopUpForm.Providers.subdomain.label'),
defaultMessage: 'Host URI (Subdomain)',
},
name: 'subdomain',
type: 'text',
placeholder: {
id: getTrad('PopUpForm.Providers.subdomain.placeholder'),
defaultMessage: 'my.subdomain.com',
},
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: callbackLabel,
placeholder: callbackPlaceholder,
name: 'callback',
type: 'text',
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: hintLabel,
name: 'noName',
type: 'text',
validations: {},
size: 12,
disabled: true,
},
],
],
schema: yup.object().shape({
enabled: yup.bool().required(translatedErrors.required.id),
key: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required.id),
otherwise: yup.string(),
}),
secret: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required.id),
otherwise: yup.string(),
}),
subdomain: yup.string().when('enabled', {
is: true,
then: yup
.string()
.matches(SUBDOMAIN_REGEX, translatedErrors.regex.id)
.required(translatedErrors.required.id),
otherwise: yup.string(),
}),
callback: yup.string().when('enabled', {
is: true,
then: yup
.string()
.matches(CALLBACK_REGEX, translatedErrors.regex.id)
.required(translatedErrors.required.id),
otherwise: yup.string(),
}),
}),
},
};
export default forms;

View File

@@ -0,0 +1,7 @@
import { translatedErrors } from '@strapi/strapi/admin';
import * as yup from 'yup';
export const createRoleSchema = yup.object().shape({
name: yup.string().required(translatedErrors.required.id),
description: yup.string().required(translatedErrors.required.id),
});

View File

@@ -0,0 +1,78 @@
import { useEffect } from 'react';
import { useAPIErrorHandler, useNotification, useFetchClient } from '@strapi/strapi/admin';
import { useQueries } from 'react-query';
import { cleanPermissions, getTrad } from '../../../utils';
export const usePlugins = () => {
const { toggleNotification } = useNotification();
const { get } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler(getTrad);
const [
{
data: permissions,
isLoading: isLoadingPermissions,
error: permissionsError,
refetch: refetchPermissions,
},
{ data: routes, isLoading: isLoadingRoutes, error: routesError, refetch: refetchRoutes },
] = useQueries([
{
queryKey: ['users-permissions', 'permissions'],
async queryFn() {
const {
data: { permissions },
} = await get(`/users-permissions/permissions`);
return permissions;
},
},
{
queryKey: ['users-permissions', 'routes'],
async queryFn() {
const {
data: { routes },
} = await get(`/users-permissions/routes`);
return routes;
},
},
]);
const refetchQueries = async () => {
await Promise.all([refetchPermissions(), refetchRoutes()]);
};
useEffect(() => {
if (permissionsError) {
toggleNotification({
type: 'danger',
message: formatAPIError(permissionsError),
});
}
}, [toggleNotification, permissionsError, formatAPIError]);
useEffect(() => {
if (routesError) {
toggleNotification({
type: 'danger',
message: formatAPIError(routesError),
});
}
}, [toggleNotification, routesError, formatAPIError]);
const isLoading = isLoadingPermissions || isLoadingRoutes;
return {
// TODO: these return values need to be memoized, otherwise
// they will create infinite rendering loops when used as
// effect dependencies
permissions: permissions ? cleanPermissions(permissions) : {},
routes: routes ?? {},
getData: refetchQueries,
isLoading,
};
};

View File

@@ -0,0 +1,24 @@
import * as React from 'react';
import { Page } from '@strapi/strapi/admin';
import { Route, Routes } from 'react-router-dom';
import { PERMISSIONS } from '../../constants';
import { ProtectedRolesCreatePage } from './pages/CreatePage';
import { ProtectedRolesEditPage } from './pages/EditPage';
import { ProtectedRolesListPage } from './pages/ListPage';
const Roles = () => {
return (
<Page.Protect permissions={PERMISSIONS.accessRoles}>
<Routes>
<Route index element={<ProtectedRolesListPage />} />
<Route path="new" element={<ProtectedRolesCreatePage />} />
<Route path=":id" element={<ProtectedRolesEditPage />} />
</Routes>
</Page.Protect>
);
};
export default Roles;

View File

@@ -0,0 +1,194 @@
import * as React from 'react';
import {
Button,
Flex,
Grid,
Main,
Textarea,
TextInput,
Typography,
Field,
} from '@strapi/design-system';
import { Check } from '@strapi/icons';
import { Page, useTracking, useNotification, useFetchClient, Layouts } from '@strapi/strapi/admin';
import { Formik, Form } from 'formik';
import { useIntl } from 'react-intl';
import { useMutation } from 'react-query';
import { useNavigate } from 'react-router-dom';
import UsersPermissions from '../../../components/UsersPermissions';
import { PERMISSIONS } from '../../../constants';
import getTrad from '../../../utils/getTrad';
import { createRoleSchema } from '../constants';
import { usePlugins } from '../hooks/usePlugins';
export const CreatePage = () => {
const { formatMessage } = useIntl();
const { toggleNotification } = useNotification();
const navigate = useNavigate();
const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
const { trackUsage } = useTracking();
const permissionsRef = React.useRef();
const { post } = useFetchClient();
const mutation = useMutation((body) => post(`/users-permissions/roles`, body), {
onError() {
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred',
}),
});
},
onSuccess() {
trackUsage('didCreateRole');
toggleNotification({
type: 'success',
message: formatMessage({
id: getTrad('Settings.roles.created'),
defaultMessage: 'Role created',
}),
});
// Forcing redirecting since we don't have the id in the response
navigate(-1);
},
});
const handleCreateRoleSubmit = async (data) => {
// TODO: refactor. Child -> parent component communication is evil;
// We should either move the provider one level up or move the state
// straight into redux.
const permissions = permissionsRef.current.getPermissions();
await mutation.mutate({ ...data, ...permissions, users: [] });
};
return (
<Main>
<Page.Title>
{formatMessage(
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
{ name: 'Roles' }
)}
</Page.Title>
<Formik
enableReinitialize
initialValues={{ name: '', description: '' }}
onSubmit={handleCreateRoleSubmit}
validationSchema={createRoleSchema}
>
{({ handleSubmit, values, handleChange, errors }) => (
<Form noValidate onSubmit={handleSubmit}>
<Layouts.Header
primaryAction={
!isLoadingPlugins && (
<Button type="submit" loading={mutation.isLoading} startIcon={<Check />}>
{formatMessage({
id: 'global.save',
defaultMessage: 'Save',
})}
</Button>
)
}
title={formatMessage({
id: 'Settings.roles.create.title',
defaultMessage: 'Create a role',
})}
subtitle={formatMessage({
id: 'Settings.roles.create.description',
defaultMessage: 'Define the rights given to the role',
})}
/>
<Layouts.Content>
<Flex
background="neutral0"
direction="column"
alignItems="stretch"
gap={7}
hasRadius
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
shadow="filterShadow"
>
<Flex direction="column" alignItems="stretch">
<Typography variant="delta" tag="h2">
{formatMessage({
id: getTrad('EditPage.form.roles'),
defaultMessage: 'Role details',
})}
</Typography>
<Grid.Root gap={4}>
<Grid.Item col={6} direction="column" alignItems="stretch">
<Field.Root
name="name"
error={
errors?.name
? formatMessage({ id: errors.name, defaultMessage: 'Name is required' })
: false
}
required
>
<Field.Label>
{formatMessage({
id: 'global.name',
defaultMessage: 'Name',
})}
</Field.Label>
<TextInput value={values.name || ''} onChange={handleChange} />
<Field.Error />
</Field.Root>
</Grid.Item>
<Grid.Item col={6} direction="column" alignItems="stretch">
<Field.Root
name="description"
error={
errors?.description
? formatMessage({
id: errors.description,
defaultMessage: 'Description is required',
})
: false
}
required
>
<Field.Label>
{formatMessage({
id: 'global.description',
defaultMessage: 'Description',
})}
</Field.Label>
<Textarea value={values.description || ''} onChange={handleChange} />
<Field.Error />
</Field.Root>
</Grid.Item>
</Grid.Root>
</Flex>
{!isLoadingPlugins && (
<UsersPermissions
ref={permissionsRef}
permissions={permissions}
routes={routes}
/>
)}
</Flex>
</Layouts.Content>
</Form>
)}
</Formik>
</Main>
);
};
export const ProtectedRolesCreatePage = () => (
<Page.Protect permissions={PERMISSIONS.createRole}>
<CreatePage />
</Page.Protect>
);

View File

@@ -0,0 +1,215 @@
import * as React from 'react';
import {
Main,
Button,
Flex,
TextInput,
Textarea,
Typography,
Grid,
Field,
} from '@strapi/design-system';
import { Check } from '@strapi/icons';
import {
Page,
BackButton,
useAPIErrorHandler,
useNotification,
useFetchClient,
Layouts,
} from '@strapi/strapi/admin';
import { Formik, Form } from 'formik';
import { useIntl } from 'react-intl';
import { useQuery, useMutation } from 'react-query';
import { useMatch } from 'react-router-dom';
import UsersPermissions from '../../../components/UsersPermissions';
import { PERMISSIONS } from '../../../constants';
import getTrad from '../../../utils/getTrad';
import { createRoleSchema } from '../constants';
import { usePlugins } from '../hooks/usePlugins';
export const EditPage = () => {
const { formatMessage } = useIntl();
const { toggleNotification } = useNotification();
const {
params: { id },
} = useMatch(`/settings/users-permissions/roles/:id`);
const { get } = useFetchClient();
const { isLoading: isLoadingPlugins, routes } = usePlugins();
const {
data: role,
isLoading: isLoadingRole,
refetch: refetchRole,
} = useQuery(['users-permissions', 'role', id], async () => {
// TODO: why doesn't this endpoint follow the admin API conventions?
const {
data: { role },
} = await get(`/users-permissions/roles/${id}`);
return role;
});
const permissionsRef = React.useRef();
const { put } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler();
const mutation = useMutation((body) => put(`/users-permissions/roles/${id}`, body), {
onError(error) {
toggleNotification({
type: 'danger',
message: formatAPIError(error),
});
},
async onSuccess() {
toggleNotification({
type: 'success',
message: formatMessage({
id: getTrad('Settings.roles.created'),
defaultMessage: 'Role edited',
}),
});
await refetchRole();
},
});
const handleEditRoleSubmit = async (data) => {
const permissions = permissionsRef.current.getPermissions();
await mutation.mutate({ ...data, ...permissions, users: [] });
};
if (isLoadingRole) {
return <Page.Loading />;
}
return (
<Main>
<Page.Title>
{formatMessage(
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
{ name: 'Roles' }
)}
</Page.Title>
<Formik
enableReinitialize
initialValues={{ name: role.name, description: role.description }}
onSubmit={handleEditRoleSubmit}
validationSchema={createRoleSchema}
>
{({ handleSubmit, values, handleChange, errors }) => (
<Form noValidate onSubmit={handleSubmit}>
<Layouts.Header
primaryAction={
!isLoadingPlugins ? (
<Button
disabled={role.code === 'strapi-super-admin'}
type="submit"
loading={mutation.isLoading}
startIcon={<Check />}
>
{formatMessage({
id: 'global.save',
defaultMessage: 'Save',
})}
</Button>
) : null
}
title={role.name}
subtitle={role.description}
navigationAction={<BackButton fallback=".." />}
/>
<Layouts.Content>
<Flex
background="neutral0"
direction="column"
alignItems="stretch"
gap={7}
hasRadius
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
shadow="filterShadow"
>
<Flex direction="column" alignItems="stretch" gap={4}>
<Typography variant="delta" tag="h2">
{formatMessage({
id: getTrad('EditPage.form.roles'),
defaultMessage: 'Role details',
})}
</Typography>
<Grid.Root gap={4}>
<Grid.Item col={6} direction="column" alignItems="stretch">
<Field.Root
name="name"
error={
errors?.name
? formatMessage({
id: errors.name,
defaultMessage: 'Name is required',
})
: false
}
required
>
<Field.Label>
{formatMessage({
id: 'global.name',
defaultMessage: 'Name',
})}
</Field.Label>
<TextInput value={values.name || ''} onChange={handleChange} />
<Field.Error />
</Field.Root>
</Grid.Item>
<Grid.Item col={6} direction="column" alignItems="stretch">
<Field.Root
name="description"
error={
errors?.description
? formatMessage({
id: errors.description,
defaultMessage: 'Description is required',
})
: false
}
required
>
<Field.Label>
{formatMessage({
id: 'global.description',
defaultMessage: 'Description',
})}
</Field.Label>
<Textarea value={values.description || ''} onChange={handleChange} />
<Field.Error />
</Field.Root>
</Grid.Item>
</Grid.Root>
</Flex>
{!isLoadingPlugins && (
<UsersPermissions
ref={permissionsRef}
permissions={role.permissions}
routes={routes}
/>
)}
</Flex>
</Layouts.Content>
</Form>
)}
</Formik>
</Main>
);
};
export const ProtectedRolesEditPage = () => (
<Page.Protect permissions={PERMISSIONS.updateRole}>
<EditPage />
</Page.Protect>
);

View File

@@ -0,0 +1,119 @@
import * as React from 'react';
import { Flex, IconButton, Link, Tbody, Td, Tr, Typography } from '@strapi/design-system';
import { Pencil, Trash } from '@strapi/icons';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { useNavigate, NavLink } from 'react-router-dom';
import { styled } from 'styled-components';
const EditLink = styled(Link)`
align-items: center;
height: 3.2rem;
width: 3.2rem;
display: flex;
justify-content: center;
padding: ${({ theme }) => `${theme.spaces[2]}`};
svg {
height: 1.6rem;
width: 1.6rem;
path {
fill: ${({ theme }) => theme.colors.neutral500};
}
}
&:hover,
&:focus {
svg {
path {
fill: ${({ theme }) => theme.colors.neutral800};
}
}
}
`;
const TableBody = ({ sortedRoles, canDelete, canUpdate, setRoleToDelete, onDelete }) => {
const { formatMessage } = useIntl();
const navigate = useNavigate();
const [showConfirmDelete, setShowConfirmDelete] = onDelete;
const checkCanDeleteRole = (role) =>
canDelete && !['public', 'authenticated'].includes(role.type);
const handleClickDelete = (id) => {
setRoleToDelete(id);
setShowConfirmDelete(!showConfirmDelete);
};
return (
<Tbody>
{sortedRoles?.map((role) => (
<Tr cursor="pointer" key={role.name} onClick={() => navigate(role.id.toString())}>
<Td width="20%">
<Typography>{role.name}</Typography>
</Td>
<Td width="50%">
<Typography>{role.description}</Typography>
</Td>
<Td width="30%">
<Typography>
{formatMessage(
{
id: 'Roles.RoleRow.user-count',
defaultMessage: '{number, plural, =0 {# user} one {# user} other {# users}}',
},
{ number: role.nb_users }
)}
</Typography>
</Td>
<Td>
<Flex justifyContent="end" onClick={(e) => e.stopPropagation()}>
{canUpdate ? (
<EditLink
tag={NavLink}
to={role.id.toString()}
aria-label={formatMessage(
{ id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
{ target: `${role.name}` }
)}
>
<Pencil />
</EditLink>
) : null}
{checkCanDeleteRole(role) && (
<IconButton
onClick={() => handleClickDelete(role.id.toString())}
variant="ghost"
label={formatMessage(
{ id: 'global.delete-target', defaultMessage: 'Delete {target}' },
{ target: `${role.name}` }
)}
>
<Trash />
</IconButton>
)}
</Flex>
</Td>
</Tr>
))}
</Tbody>
);
};
export default TableBody;
TableBody.defaultProps = {
canDelete: false,
canUpdate: false,
};
TableBody.propTypes = {
onDelete: PropTypes.array.isRequired,
setRoleToDelete: PropTypes.func.isRequired,
sortedRoles: PropTypes.array.isRequired,
canDelete: PropTypes.bool,
canUpdate: PropTypes.bool,
};

View File

@@ -0,0 +1,266 @@
import React, { useState } from 'react';
import {
Table,
Th,
Thead,
Tr,
Typography,
useNotifyAT,
VisuallyHidden,
EmptyStateLayout,
useCollator,
useFilter,
LinkButton,
Dialog,
} from '@strapi/design-system';
import { Plus } from '@strapi/icons';
import {
ConfirmDialog,
useTracking,
Page,
SearchInput,
useNotification,
useQueryParams,
useFetchClient,
useRBAC,
Layouts,
} from '@strapi/strapi/admin';
import { useIntl } from 'react-intl';
import { useMutation, useQuery } from 'react-query';
import { NavLink } from 'react-router-dom';
import { PERMISSIONS } from '../../../../constants';
import { getTrad } from '../../../../utils';
import TableBody from './components/TableBody';
export const RolesListPage = () => {
const { trackUsage } = useTracking();
const { formatMessage, locale } = useIntl();
const { toggleNotification } = useNotification();
const { notifyStatus } = useNotifyAT();
const [{ query }] = useQueryParams();
const _q = query?._q || '';
const [showConfirmDelete, setShowConfirmDelete] = useState(false);
const [roleToDelete, setRoleToDelete] = useState();
const { del, get } = useFetchClient();
const {
isLoading: isLoadingForPermissions,
allowedActions: { canRead, canDelete, canCreate, canUpdate },
} = useRBAC({
create: PERMISSIONS.createRole,
read: PERMISSIONS.readRoles,
update: PERMISSIONS.updateRole,
delete: PERMISSIONS.deleteRole,
});
const {
isLoading: isLoadingForData,
data: { roles },
isFetching,
refetch,
} = useQuery('get-roles', () => fetchData(toggleNotification, formatMessage, notifyStatus), {
initialData: {},
enabled: canRead,
});
const { contains } = useFilter(locale, {
sensitivity: 'base',
});
/**
* @type {Intl.Collator}
*/
const formatter = useCollator(locale, {
sensitivity: 'base',
});
const isLoading = isLoadingForData || isFetching || isLoadingForPermissions;
const handleShowConfirmDelete = () => {
setShowConfirmDelete(!showConfirmDelete);
};
const deleteData = async (id, formatMessage, toggleNotification) => {
try {
await del(`/users-permissions/roles/${id}`);
} catch (error) {
toggleNotification({
type: 'danger',
message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occured' }),
});
}
};
const fetchData = async (toggleNotification, formatMessage, notifyStatus) => {
try {
const { data } = await get('/users-permissions/roles');
notifyStatus('The roles have loaded successfully');
return data;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),
});
throw new Error(err);
}
};
const emptyLayout = {
roles: {
id: getTrad('Roles.empty'),
defaultMessage: "You don't have any roles yet.",
},
search: {
id: getTrad('Roles.empty.search'),
defaultMessage: 'No roles match the search.',
},
};
const pageTitle = formatMessage({
id: 'global.roles',
defaultMessage: 'Roles',
});
const deleteMutation = useMutation((id) => deleteData(id, formatMessage, toggleNotification), {
async onSuccess() {
await refetch();
},
});
const handleConfirmDelete = async () => {
await deleteMutation.mutateAsync(roleToDelete);
setShowConfirmDelete(!showConfirmDelete);
};
const sortedRoles = (roles || [])
.filter((role) => contains(role.name, _q) || contains(role.description, _q))
.sort(
(a, b) => formatter.compare(a.name, b.name) || formatter.compare(a.description, b.description)
);
const emptyContent = _q && !sortedRoles.length ? 'search' : 'roles';
const colCount = 4;
const rowCount = (roles?.length || 0) + 1;
if (isLoading) {
return <Page.Loading />;
}
return (
<Layouts.Root>
<Page.Title>
{formatMessage(
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
{ name: pageTitle }
)}
</Page.Title>
<Page.Main>
<Layouts.Header
title={formatMessage({
id: 'global.roles',
defaultMessage: 'Roles',
})}
subtitle={formatMessage({
id: 'Settings.roles.list.description',
defaultMessage: 'List of roles',
})}
primaryAction={
canCreate ? (
<LinkButton
to="new"
tag={NavLink}
onClick={() => trackUsage('willCreateRole')}
startIcon={<Plus />}
size="S"
>
{formatMessage({
id: getTrad('List.button.roles'),
defaultMessage: 'Add new role',
})}
</LinkButton>
) : null
}
/>
<Layouts.Action
startActions={
<SearchInput
label={formatMessage({
id: 'app.component.search.label',
defaultMessage: 'Search',
})}
/>
}
/>
<Layouts.Content>
{!canRead && <Page.NoPermissions />}
{canRead && sortedRoles && sortedRoles?.length ? (
<Table colCount={colCount} rowCount={rowCount}>
<Thead>
<Tr>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({
id: 'global.description',
defaultMessage: 'Description',
})}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({
id: 'global.users',
defaultMessage: 'Users',
})}
</Typography>
</Th>
<Th>
<VisuallyHidden>
{formatMessage({
id: 'global.actions',
defaultMessage: 'Actions',
})}
</VisuallyHidden>
</Th>
</Tr>
</Thead>
<TableBody
sortedRoles={sortedRoles}
canDelete={canDelete}
canUpdate={canUpdate}
permissions={PERMISSIONS}
setRoleToDelete={setRoleToDelete}
onDelete={[showConfirmDelete, setShowConfirmDelete]}
/>
</Table>
) : (
<EmptyStateLayout content={formatMessage(emptyLayout[emptyContent])} />
)}
</Layouts.Content>
<Dialog.Root open={showConfirmDelete} onOpenChange={handleShowConfirmDelete}>
<ConfirmDialog onConfirm={handleConfirmDelete} />
</Dialog.Root>
</Page.Main>
</Layouts.Root>
);
};
export const ProtectedRolesListPage = () => {
return (
<Page.Protect permissions={PERMISSIONS.accessRoles}>
<RolesListPage />
</Page.Protect>
);
};

View File

@@ -0,0 +1,5 @@
import { name } from '../../package.json';
const pluginId = name.replace(/^@strapi\/plugin-/i, '');
export default pluginId;

View File

@@ -0,0 +1,40 @@
{
"BoundRoute.title": "Bound route to",
"EditForm.inputSelect.description.role": "سيتم إرفاق المستخدم المصادق الجديد بالدور المحدد.",
"EditForm.inputSelect.label.role": "الدور الافتراضي للمستخدمين المصادقين",
"EditForm.inputToggle.description.email": "عدم السماح للمستخدم بإنشاء حسابات متعددة باستخدام نفس عنوان البريد الإلكتروني مع موفري مصادقة مختلفين.",
"EditForm.inputToggle.description.sign-up": "عند تعطيل (OFF) ، يتم حظر عملية التسجيل. لا أحد يستطيع الاشتراك بعد الآن بغض النظر عن المزود المستخدم.",
"EditForm.inputToggle.label.email": "حساب واحد لكل بريد الاكتروني",
"EditForm.inputToggle.label.sign-up": "تفعيل التسجيل",
"HeaderNav.link.advancedSettings": "إعدادات متقدمة",
"HeaderNav.link.emailTemplates": "قوالب الإيميل",
"HeaderNav.link.providers": "مزودين",
"Plugin.permissions.plugins.description": "حدد جميع الإجراءات المسموح بها للإضافة {name}.",
"Plugins.header.description": "يتم سرد الإجراءات المحددة المرتبطة بالمسار أدناه.",
"Plugins.header.title": "الصلاحيات",
"Policies.header.hint": "حدد إجراءات التطبيق أو إجراءات الإضافة وانقر على رمز الترس لعرض المسار المرتبط",
"Policies.header.title": "إعدادات متقدمة",
"PopUpForm.Email.email_templates.inputDescription": "إذا كنت غير متأكد من كيفية استخدام المتغيرات ، {link}",
"PopUpForm.Email.options.from.email.label": "البريد الإلكتروني للشاحن",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "أسم المورد",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "الرسالة",
"PopUpForm.Email.options.object.label": "موضوع",
"PopUpForm.Email.options.response_email.label": "البريد الإلكتروني للاستجابة",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "في حالة التعطيل ، لن يتمكن المستخدمون من استخدام هذا الموفر.",
"PopUpForm.Providers.enabled.label": "مفعل",
"PopUpForm.Providers.key.label": "معرف العميل",
"PopUpForm.Providers.key.placeholder": "نص",
"PopUpForm.Providers.redirectURL.front-end.label": "عنوان URL لإعادة التوجيه إلى تطبيق الواجهة الأمامية (front-end)",
"PopUpForm.Providers.secret.label": "سر العميل (Client Secret)",
"PopUpForm.Providers.secret.placeholder": "نص",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "تحرير قوالب البريد الإلكتروني",
"notification.success.submit": "تم تحديث الإعدادات",
"plugin.description.long": "حماية الـAPI الخاص بك مع عملية مصادقة كاملة استناداً إلى JWT. يأتي هذا الملحق أيضًا مع إستراتيجية ACL التي تسمح لك بإدارة الأذونات بين مجموعات المستخدمين.",
"plugin.description.short": "حماية الـAPI الخاص بك مع عملية مصادقة كاملة استناداً إلى JWT",
"plugin.name": "الأدوار والصلاحية"
}

View File

@@ -0,0 +1,46 @@
{
"BoundRoute.title": "Spojit adresu s",
"EditForm.inputSelect.description.role": "Připojí nově autentifikovaného uživatele ke svolené roli.",
"EditForm.inputSelect.label.role": "Výchozí role pro autentifikovaného uživatele",
"EditForm.inputToggle.description.email": "Zabránit uživateli vytvářet různé účty se stejným e-mailem a jinými poskytovateli autentifikace.",
"EditForm.inputToggle.description.email-confirmation": "Pokud je tato funkce povolena (ON), nově registrovaní uživatelé dostanou potvrzující e-mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Po potvrzení e-mailu, zvolte kam budete přesměrováni.",
"EditForm.inputToggle.description.email-reset-password": "Adresa stránky obnovení hesla vaší aplikace",
"EditForm.inputToggle.description.sign-up": "Pokud je tato možnost zakázána (OFF), není možno projít registrací. Nikdo se již nemůže připojit, bez ohledu jakého použije poskytovatele.",
"EditForm.inputToggle.label.email": "Jeden účet na e-mail",
"EditForm.inputToggle.label.email-confirmation": "Povolit potvrzení z e-mailu",
"EditForm.inputToggle.label.email-confirmation-redirection": "Adresa pro přesměrování",
"EditForm.inputToggle.label.email-reset-password": "Stránka pro obnovení hesla",
"EditForm.inputToggle.label.sign-up": "Povolit registrace",
"HeaderNav.link.advancedSettings": "Pokročilá nastavení",
"HeaderNav.link.emailTemplates": "E-mailové šablony",
"HeaderNav.link.providers": "Poskytovatelé",
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro zásuvný modul {name}.",
"Plugins.header.description": "Pouze akce spojené s adresou jsou vypsány níže.",
"Plugins.header.title": "Povolení",
"Policies.header.hint": "Vyberte akce aplikace, nebo akce zásuvného modulu a klikněte na ikonku ozubeného kolečka pro zobrazení adresy s nimi spojenou.",
"Policies.header.title": "Pokročilá nastavení",
"PopUpForm.Email.email_templates.inputDescription": "Pokud si nejste jisti jak používat proměnné, {link}",
"PopUpForm.Email.options.from.email.label": "Odesilatelův e-mail",
"PopUpForm.Email.options.from.email.placeholder": "jannovak@gmail.com",
"PopUpForm.Email.options.from.name.label": "Jméno odesilatele",
"PopUpForm.Email.options.from.name.placeholder": "Jan Novák",
"PopUpForm.Email.options.message.label": "Zpráva",
"PopUpForm.Email.options.object.label": "Předmět",
"PopUpForm.Email.options.response_email.label": "Response e-mail",
"PopUpForm.Email.options.response_email.placeholder": "jannovak@gmail.com",
"PopUpForm.Providers.enabled.description": "If disabled, users won't be able to use this provider.",
"PopUpForm.Providers.enabled.label": "Povolit",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "Adresa pro přesměrování na vaši front-end aplikaci",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Upravit e-mailové šablony",
"notification.success.submit": "Nastavení bylo aktualizování",
"plugin.description.long": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT. Tento zásuvný modul obsahuje ACL strategii, která vám umožní spravovat oprávnění mezi skupinami uživatelů.",
"plugin.description.short": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT",
"plugin.name": "Role a oprávnění"
}

View File

@@ -0,0 +1,58 @@
{
"BoundRoute.title": "Pfad gebunden an",
"EditForm.inputSelect.description.role": "Die Rolle, die neu authentifizierten Benutzern automatisch zugewiesen wird.",
"EditForm.inputSelect.label.role": "Standardrolle für authentifizierte Benutzer",
"EditForm.inputToggle.description.email": "Verbiete das Anlegen verschiedener Accounts mit der gleichen E-Mail-Adresse bei unterschiedlichen Anmeldemethoden.",
"EditForm.inputToggle.description.email-confirmation": "Wenn aktiviert (ON) erhalten neu registrierte Benutzer eine Bestätigungs-E-Mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Nachdem Sie die E-Mail bestätigt haben, wähle wohin sie weitergeleitet wird.",
"EditForm.inputToggle.description.email-reset-password": "URL deiner Passwort-Zurücksetzen-Seite deiner Anwendung",
"EditForm.inputToggle.description.sign-up": "Wenn deaktiviert (OFF), wird der Registrationsprozess unterbunden. Niemand kann sich mehr registrieren.",
"EditForm.inputToggle.label.email": "Ein Account pro E-Mail-Adresse",
"EditForm.inputToggle.label.email-confirmation": "Aktiviere E-Mail Benachrichtigungen",
"EditForm.inputToggle.label.email-confirmation-redirection": "Weiterleitungs-URL",
"EditForm.inputToggle.label.email-reset-password": "Passwort-Zurücksetzen-Seite",
"EditForm.inputToggle.label.sign-up": "Registration ermöglichen",
"Email.template.email_confirmation": "Bestätigung der E-Mail-Addresse",
"HeaderNav.link.advancedSettings": "Erweiterte Einstellungen",
"HeaderNav.link.emailTemplates": "E-Mail-Templates",
"HeaderNav.link.providers": "Methoden",
"Plugin.permissions.plugins.description": "Definiere die möglichen Aktionen des {name} Plugins.",
"Plugins.header.description": "Nur Aktionen, die an einen Pfad gebunden sind, werden hier gelistet.",
"Plugins.header.title": "Berechtigungen",
"Policies.header.hint": "Wähle eine Aktion aus und klicke auf das Zahnrad, um den an diese Aktion gebundenen Pfad anzuzeigen",
"Policies.header.title": "Fortgeschrittene Einstellungen",
"PopUpForm.Email.email_templates.inputDescription": "{link} für mehr Informationen",
"PopUpForm.Email.link.documentation": "Lies die Dokumentation",
"PopUpForm.Email.options.from.email.label": "E-Mail-Adresse des Absenders",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Name des Absenders",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Nachricht",
"PopUpForm.Email.options.object.label": "Betreff",
"PopUpForm.Email.options.object.placeholder": "Bitte bestätige deine E-Mail-Adresse für %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Antwort E-Mail-Adresse",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Wenn deaktiviert, kann diese Methode nicht verwendet werden.",
"PopUpForm.Providers.enabled.label": "Aktivieren",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "Die URL zur Weiterleitung zu deiner Frontend-App",
"PopUpForm.Providers.redirectURL.label": "Die Weiterleitungs-URL für die App-Einstellungen von {provider}",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "E-Mail-Templates bearbeiten",
"PopUpForm.header.edit.providers": "Anbieter bearbeiten",
"Settings.roles.deleted": "Rolle gelöscht",
"Settings.roles.edited": "Rolle bearbeitet",
"Settings.section-label": "Nutzer- & Berechtigungen-Plugin",
"notification.success.submit": "Einstellungen aktualisiert",
"plugin.description.long": "Beschütze deine API mit einem vollständigen Authentifikationsprozess basierend auf JWT. Zudem bietet dieses Plugin eine ACL-Strategie, die erlaubt, die Berechtigungen für Benutzergruppen festzulegen.",
"plugin.description.short": "Beschütze deine API mit einem vollständigen Authentifikationsprozess basierend auf JWT.",
"plugin.name": "Nutzer- & Berechtigungen-Plugin",
"popUpWarning.button.cancel": "Abbrechen",
"popUpWarning.button.confirm": "Bestätigen",
"popUpWarning.title": "Bitte bestätigen",
"popUpWarning.warning.cancel": "Willst du wirklich alle deine Änderungen verwerfen?"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "Bundet rute til",
"EditForm.inputSelect.description.role": "Den vil tilknytte den nye godkendte bruger til den valgte rolle.",
"EditForm.inputSelect.label.role": "Standard rolle for godkendte brugere",
"EditForm.inputToggle.description.email": "Tillad IKKE brugere at oprette flere brugere med den samme e-mail-adresse med forskellige godkendelsesudbydere.",
"EditForm.inputToggle.description.email-confirmation": "Når aktiv (TIL), modtager nye registrerede brugere en bekræftelses e-mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Efter bekræftet email, vælg hvor du vil omdirigeres til.",
"EditForm.inputToggle.description.email-reset-password": "URL til din apps nulstil kodeord side",
"EditForm.inputToggle.description.sign-up": "Når deaktiveret (FRA), er registrering forbudt. Ingen kan subscribe uanset udbyder.",
"EditForm.inputToggle.label.email": "En bruger pr. e-mail",
"EditForm.inputToggle.label.email-confirmation": "Aktivér e-mail bekræftelse",
"EditForm.inputToggle.label.email-confirmation-redirection": "Omdirigerings URL",
"EditForm.inputToggle.label.email-reset-password": "Nulstil kodeord side",
"EditForm.inputToggle.label.sign-up": "Aktivér oprettelser",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "f.eks. https://hjemmeside.dk/nulstil-kodeord",
"EditForm.inputToggle.placeholder.email-reset-password": "f.eks. https://hjemmeside.dk/nulstil-kodeord",
"EditPage.form.roles": "Rolle detaljer",
"Email.template.data.loaded": "E-mail skabeloner er hentet",
"Email.template.email_confirmation": "E-mail adresse bekræftelse",
"Email.template.form.edit.label": "Redigér en skabelon",
"Email.template.table.action.label": "handling",
"Email.template.table.icon.label": "ikon",
"Email.template.table.name.label": "navn",
"Form.advancedSettings.data.loaded": "Avancerede indstillinger hentet",
"HeaderNav.link.advancedSettings": "Advancerede indstillinger",
"HeaderNav.link.emailTemplates": "E-mail skabeloner",
"HeaderNav.link.providers": "Udbydere",
"Plugin.permissions.plugins.description": "Definér alle tilladte handlinger for {name} plugin.",
"Plugins.header.description": "Kunne handlinger tilknyttet en rute er vist nedenfor.",
"Plugins.header.title": "Rettigheder",
"Policies.header.hint": "Vælg applikationens handlinger eller plugin handlinger og klik på tandhjulet for at vise den bunde rute",
"Policies.header.title": "Advancerede indstillinger",
"PopUpForm.Email.email_templates.inputDescription": "Hvis du er usikker på brugen af variabler, {link}",
"PopUpForm.Email.link.documentation": "tjek vores dokumentation.",
"PopUpForm.Email.options.from.email.label": "Afsender e-mail",
"PopUpForm.Email.options.from.email.placeholder": "johndoe@gmail.com",
"PopUpForm.Email.options.from.name.label": "Afsender name",
"PopUpForm.Email.options.from.name.placeholder": "John Doe",
"PopUpForm.Email.options.message.label": "Besked",
"PopUpForm.Email.options.object.label": "Emne",
"PopUpForm.Email.options.object.placeholder": "Bekræft venligst din e-mail adresse for %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Svar e-mail",
"PopUpForm.Email.options.response_email.placeholder": "johndoe@gmail.com",
"PopUpForm.Providers.enabled.description": "Hvis deaktiveret, kan brugere ikke bruge denne udbyder.",
"PopUpForm.Providers.enabled.label": "Aktivér",
"PopUpForm.Providers.key.label": "Klient ID",
"PopUpForm.Providers.key.placeholder": "TEKST",
"PopUpForm.Providers.redirectURL.front-end.label": "Omstillings URL til din font-end app",
"PopUpForm.Providers.redirectURL.label": "Omstillings URL som tilføjes til din {provider} applikation konfigurationer",
"PopUpForm.Providers.secret.label": "Klient hemmelighed",
"PopUpForm.Providers.secret.placeholder": "TEKST",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "mit.subdomain.dk",
"PopUpForm.header.edit.email-templates": "Redigér e-mail skabeloner",
"PopUpForm.header.edit.providers": "Redigér udbydere",
"Providers.data.loaded": "Providers hentet",
"Providers.status": "Status",
"Roles.empty": "Du har endnu ingen roller.",
"Roles.empty.search": "Ingen roller matcher søgningen.",
"Settings.roles.deleted": "Rolle slettet",
"Settings.roles.edited": "Rolle redigeret",
"Settings.section-label": "Brugere & Tilladelser plugin",
"components.Input.error.validation.email": "Dette er en ugyldig e.mail",
"components.Input.error.validation.json": "Dette stemmer ikke med JSON formatet",
"components.Input.error.validation.max": "Værdien er for høj.",
"components.Input.error.validation.maxLength": "Værdien er for lang.",
"components.Input.error.validation.min": "Værdien er for lav.",
"components.Input.error.validation.minLength": "Værdien er for kort.",
"components.Input.error.validation.minSupMax": "Kan ikke være overlegen",
"components.Input.error.validation.regex": "Værdien stemmer ikke overens med regex.",
"components.Input.error.validation.required": "Værdien er påkrævet.",
"components.Input.error.validation.unique": "Værdien er allerede brugt.",
"notification.success.submit": "Indstillingerne er blevet opdateret",
"page.title": "Indstillinger - Roller",
"plugin.description.long": "Beskyt din API med fuld godkendelse med JWT. Dette plugin kommer også med en ACL strategi som tillader dig at håndtere rettigeheder mellem grupper af brugere.",
"plugin.description.short": "Beskyt din API med fuld godkendelse med JWT",
"plugin.name": "Roller & rettigheder",
"popUpWarning.button.cancel": "Annuller",
"popUpWarning.button.confirm": "Bekræft",
"popUpWarning.title": "Bekræft venligst",
"popUpWarning.warning.cancel": "Er du sikker på at du vil annullere dine ændringer?"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "Bound route to",
"EditForm.inputSelect.description.role": "It will attach the new authenticated user to the selected role.",
"EditForm.inputSelect.label.role": "Default role for authenticated users",
"EditForm.inputToggle.description.email": "Disallow the user to create multiple accounts using the same email address with different authentication providers.",
"EditForm.inputToggle.description.email-confirmation": "When enabled (ON), new registered users receive a confirmation email.",
"EditForm.inputToggle.description.email-confirmation-redirection": "After you confirmed your email, choose where you will be redirected.",
"EditForm.inputToggle.description.email-reset-password": "URL of your application's reset password page",
"EditForm.inputToggle.description.sign-up": "When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.",
"EditForm.inputToggle.label.email": "One account per email address",
"EditForm.inputToggle.label.email-confirmation": "Enable email confirmation",
"EditForm.inputToggle.label.email-confirmation-redirection": "Redirection url",
"EditForm.inputToggle.label.email-reset-password": "Reset password page",
"EditForm.inputToggle.label.sign-up": "Enable sign-ups",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Role details",
"Email.template.data.loaded": "Email templates has been loaded",
"Email.template.email_confirmation": "Email address confirmation",
"Email.template.form.edit.label": "Edit a template",
"Email.template.table.action.label": "action",
"Email.template.table.icon.label": "icon",
"Email.template.table.name.label": "name",
"Form.advancedSettings.data.loaded": "Advanced settings data has been loaded",
"HeaderNav.link.advancedSettings": "Advanced settings",
"HeaderNav.link.emailTemplates": "Email templates",
"HeaderNav.link.providers": "Providers",
"Plugin.permissions.plugins.description": "Define all allowed actions for the {name} plugin.",
"Plugins.header.description": "Only actions bound by a route are listed below.",
"Plugins.header.title": "Permissions",
"Policies.header.hint": "Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
"Policies.header.title": "Advanced settings",
"PopUpForm.Email.email_templates.inputDescription": "If you're unsure how to use variables, {link}",
"PopUpForm.Email.link.documentation": "check out our documentation.",
"PopUpForm.Email.options.from.email.label": "Shipper email",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Shipper name",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Message",
"PopUpForm.Email.options.object.label": "Subject",
"PopUpForm.Email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Response email",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "If disabled, users won't be able to use this provider.",
"PopUpForm.Providers.enabled.label": "Enable",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "The redirect URL to your front-end app",
"PopUpForm.Providers.redirectURL.label": "The redirect URL to add in your {provider} application configurations",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Edit email template",
"PopUpForm.header.edit.providers": "Edit Provider",
"Providers.data.loaded": "Providers have been loaded",
"Providers.status": "Status",
"Roles.empty": "You don't have any roles yet.",
"Roles.empty.search": "No roles match the search.",
"Settings.roles.deleted": "Role deleted",
"Settings.roles.edited": "Role edited",
"Settings.section-label": "Users & Permissions plugin",
"components.Input.error.validation.email": "This is not a valid email",
"components.Input.error.validation.json": "This doesn't match the JSON format",
"components.Input.error.validation.max": "The value is too high.",
"components.Input.error.validation.maxLength": "The value is too long.",
"components.Input.error.validation.min": "The value is too low.",
"components.Input.error.validation.minLength": "The value is too short.",
"components.Input.error.validation.minSupMax": "Can't be superior",
"components.Input.error.validation.regex": "The value does not match the regex.",
"components.Input.error.validation.required": "This value is required.",
"components.Input.error.validation.unique": "This value is already used.",
"notification.success.submit": "Settings have been updated",
"page.title": "Settings - Roles",
"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",
"popUpWarning.button.cancel": "Cancel",
"popUpWarning.button.confirm": "Confirm",
"popUpWarning.title": "Please confirm",
"popUpWarning.warning.cancel": "Are you sure you want to cancel your modifications?"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "Ruta enlazada a",
"EditForm.inputSelect.description.role": "Adjuntará el nuevo usuario autenticado al rol seleccionado.",
"EditForm.inputSelect.label.role": "Rol predeterminado para usuarios autenticados",
"EditForm.inputToggle.description.email": "No permita que el usuario cree varias cuentas utilizando la misma dirección de correo electrónico con distintos proveedores de autenticación.",
"EditForm.inputToggle.description.email-confirmation": "Estando habilitado (ON), nuevos usuarios registrados reciben un correo de confirmación.",
"EditForm.inputToggle.description.email-confirmation-redirection": "After confirmed your email, chose where you will be redirected.",
"EditForm.inputToggle.description.email-reset-password": "URL de la página de restablecimiento de contraseña de su aplicación",
"EditForm.inputToggle.description.sign-up": "Cuando está desactivado (OFF), el proceso de registro está prohibido. Nadie puede suscribirse sin importar el proveedor utilizado.",
"EditForm.inputToggle.label.email": "Una cuenta por dirección de correo electrónico",
"EditForm.inputToggle.label.email-confirmation": "Habilitar confirmación de correo",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL de redirección",
"EditForm.inputToggle.label.email-reset-password": "Página de reestablecer la contraseña",
"EditForm.inputToggle.label.sign-up": "Habilitar inscripciones",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ej: https://tufrontend.com/restablecer-contrasena",
"EditForm.inputToggle.placeholder.email-reset-password": "ej: https://tufrontend.com/restablecer-contrasena",
"EditPage.form.roles": "Detalles del rol",
"Email.template.data.loaded": "Se han cargado las plantillas de correo electrónico",
"Email.template.email_confirmation": "Confirmación de dirección de correo electrónico",
"Email.template.form.edit.label": "Editar una plantilla",
"Email.template.table.action.label": "acción",
"Email.template.table.icon.label": "icono",
"Email.template.table.name.label": "nombre",
"Form.advancedSettings.data.loaded": "Se han cargado los datos de configuración avanzada",
"HeaderNav.link.advancedSettings": "Ajustes avanzados",
"HeaderNav.link.emailTemplates": "Plantillas de email",
"HeaderNav.link.providers": "Proveedores",
"Plugin.permissions.plugins.description": "Defina todas las acciones permitidas para el plugin {name}.",
"Plugins.header.description": "Sólo las acciones vinculadas a una ruta se enumeran a continuación.",
"Plugins.header.title": "Permisos",
"Policies.header.hint": "Seleccione las acciones de la aplicación o las acciones del plugin y haga clic en el icono del engranaje para ver la ruta vinculada",
"Policies.header.title": "Ajustes avanzados",
"PopUpForm.Email.email_templates.inputDescription": "Si no estás seguro de cómo usar las variables, {link}",
"PopUpForm.Email.link.documentation": "consulte nuestra documentación.",
"PopUpForm.Email.options.from.email.label": "Email del remitente",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nombre del remitente",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mensaje",
"PopUpForm.Email.options.object.label": "Tema",
"PopUpForm.Email.options.object.placeholder": "Confirma tu dirección de correo electrónico para %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email de respuesta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Si está desactivado, los usuarios no podrán utilizar este proveedor.",
"PopUpForm.Providers.enabled.label": "Habilitar",
"PopUpForm.Providers.key.label": "ID de cliente",
"PopUpForm.Providers.key.placeholder": "TEXTO",
"PopUpForm.Providers.redirectURL.front-end.label": "La URL de redireccionamiento a su aplicación front-end",
"PopUpForm.Providers.redirectURL.label": "La URL de redireccionamiento para agregar en las configuraciones de su aplicación de {proveedor}",
"PopUpForm.Providers.secret.label": "Secreto Cliente",
"PopUpForm.Providers.secret.placeholder": "TEXTO",
"PopUpForm.Providers.subdomain.label": "URI de host (subdominio)",
"PopUpForm.Providers.subdomain.placeholder": "mi.subdominio.com",
"PopUpForm.header.edit.email-templates": "Editar Plantillas de Email",
"PopUpForm.header.edit.providers": "Editar proveedor",
"Providers.data.loaded": "Los proveedores se han cargado",
"Providers.status": "Estado",
"Roles.empty": "Aún no tienes ningún rol.",
"Roles.empty.search": "Ningún rol coincide con la búsqueda.",
"Settings.roles.deleted": "Rol eliminado",
"Settings.roles.edited": "Rol editado",
"Settings.section-label": "Plugin de Usuarios y Permisos",
"components.Input.error.validation.email": "El correo electrónico inválido",
"components.Input.error.validation.json": "No coincide con el formato JSON",
"components.Input.error.validation.max": "El valor es demasiado alto.",
"components.Input.error.validation.maxLength": "El valor es demasiado largo.",
"components.Input.error.validation.min": "El valor es demasiado bajo.",
"components.Input.error.validation.minLength": "El valor es demasiado corto.",
"components.Input.error.validation.minSupMax": "No puede ser superior",
"components.Input.error.validation.regex": "El valor no coincide con la expresión regular.",
"components.Input.error.validation.required": "Este valor es obligatorio.",
"components.Input.error.validation.unique": "Este valor ya se utiliza.",
"notification.success.submit": "Los ajustes se han actualizado",
"page.title": "Configuración - Roles",
"plugin.description.long": "Proteja su API con un proceso de autenticación completo basado en JWT. Este plugin viene también con una estrategia ACL que le permite administrar los permisos entre los grupos de usuarios.",
"plugin.description.short": "Proteja su API con un proceso de autenticación completo basado en JWT",
"plugin.name": "Roles y Permisos",
"popUpWarning.button.cancel": "Cancelar",
"popUpWarning.button.confirm": "Confirmar",
"popUpWarning.title": "Por favor confirme",
"popUpWarning.warning.cancel": "¿Está seguro de que desea cancelar sus modificaciones?"
}

View File

@@ -0,0 +1,46 @@
{
"BoundRoute.title": "Route associée à",
"EditForm.inputSelect.description.role": "Choisissez le rôle qui sera lié aux utilisateurs lors de leur enregistrement.",
"EditForm.inputSelect.label.role": "Rôle par defaut pour les nouveaux utilisateurs",
"EditForm.inputToggle.description.email": "Interdire l'utilisateur de créer de multiple comptes avec la même adresse e-mail avec des providers différents",
"EditForm.inputToggle.description.email-confirmation": "Quand cette option est activée (ON), les nouveaux utilisateurs enregistrés reçoivent un e-mail de confirmation.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Après confirmation de votre e-mail, choisissez où vous allez être redirigé.",
"EditForm.inputToggle.description.email-reset-password": "URL de la page de réinitialisation de mot de passe.",
"EditForm.inputToggle.description.sign-up": "Quand l'inscription est désactivée (OFF), aucun utilisateur ne peut s'inscrire qu'importe le provider",
"EditForm.inputToggle.label.email": "Un compte par adresse e-mail",
"EditForm.inputToggle.label.email-confirmation": "Activer l'e-mail de confirmation",
"EditForm.inputToggle.label.email-confirmation-redirection": "Redirection de l'URL",
"EditForm.inputToggle.label.email-reset-password": "Page de réinitialisation de mot de passe",
"EditForm.inputToggle.label.sign-up": "Activer l'inscription",
"HeaderNav.link.advancedSettings": "Paramètres avancés",
"HeaderNav.link.emailTemplates": "Templates d'e-mail",
"HeaderNav.link.providers": "Fournisseurs",
"Plugin.permissions.plugins.description": "Définissez les actions autorisées dans le {name} plugin.",
"Plugins.header.description": "Sont listés uniquement les actions associées à une route.",
"Plugins.header.title": "Permissions",
"Policies.header.hint": "Sélectionnez les actions de l'application ou d'un plugin et cliquer sur l'icon de paramètres pour voir les routes associées à cette action",
"Policies.header.title": "Paramètres avancés",
"PopUpForm.Email.email_templates.inputDescription": "Regardez la documentation des variables, {link}",
"PopUpForm.Email.options.from.email.label": "E-mail de l'envoyeur",
"PopUpForm.Email.options.from.email.placeholder": "arthurdupont@gmail.com",
"PopUpForm.Email.options.from.name.label": "Nom de l'envoyeur",
"PopUpForm.Email.options.from.name.placeholder": "Arthur Dupont",
"PopUpForm.Email.options.message.label": "Message",
"PopUpForm.Email.options.object.label": "Objet",
"PopUpForm.Email.options.response_email.label": "E-mail de réponse",
"PopUpForm.Email.options.response_email.placeholder": "arthurdupont@gmail.com",
"PopUpForm.Providers.enabled.description": "S'il est désactivé les utilisateurs ne pourront pas utiliser ce provider.",
"PopUpForm.Providers.enabled.label": "Activer",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "L'URL de redirection de votre app front-end",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Editer E-mail Templates",
"notification.success.submit": "Les configurations ont bien été sauvegardés",
"plugin.description.long": "Protégez votre API avec un système d'authentification complet basé sur JWT (JSON Web Token). Ce plugin ajoute aussi une stratégie ACL (Access Control Layer) qui vous permet de gérer les permissions entre les groupes d'utilisateurs.",
"plugin.description.short": "Protégez votre API avec un système d'authentification complet basé sur JWT.",
"plugin.name": "Rôles et autorisations"
}

View File

@@ -0,0 +1,58 @@
{
"BoundRoute.title": "Rute terikat ke",
"EditForm.inputSelect.description.role": "Ini akan melampirkan pengguna baru yang diautentikasi ke peran yang dipilih.",
"EditForm.inputSelect.label.role": "Peran default untuk pengguna yang diautentikasi",
"EditForm.inputToggle.description.email": "Larang pengguna membuat beberapa akun menggunakan alamat email yang sama dengan penyedia otentikasi yang berbeda.",
"EditForm.inputToggle.description.email-confirmation": "Saat diaktifkan (ON), pengguna baru yang terdaftar menerima email konfirmasi.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Setelah Anda mengkonfirmasi email Anda, pilih ke mana Anda akan diarahkan.",
"EditForm.inputToggle.description.email-reset-password": "URL halaman setel ulang sandi aplikasi Anda",
"EditForm.inputToggle.description.sign-up": "Saat dinonaktifkan (OFF), proses pendaftaran dilarang. Tidak ada yang bisa berlangganan lagi tidak peduli penyedia yang digunakan.",
"EditForm.inputToggle.label.email": "Satu akun per alamat email",
"EditForm.inputToggle.label.email-confirmation": "Aktifkan konfirmasi email",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL pengalihan",
"EditForm.inputToggle.label.email-reset-password": "Atur ulang halaman kata sandi",
"EditForm.inputToggle.label.sign-up": "Aktifkan pendaftaran",
"Email.template.email_confirmation": "Konfirmasi alamat email",
"HeaderNav.link.advancedSettings": "Pengaturan lanjutan",
"HeaderNav.link.emailTemplates": "Template email",
"HeaderNav.link.providers": "Penyedia",
"Plugin.permissions.plugins.description": "Tentukan semua tindakan yang diizinkan untuk plugin {name}.",
"Plugins.header.description": "Hanya tindakan yang terikat oleh rute yang dicantumkan di bawah.",
"Plugins.header.title": "Izin",
"Policies.header.hint": "Pilih tindakan aplikasi atau tindakan plugin dan klik ikon roda gigi untuk menampilkan rute terikat",
"Policies.header.title": "Pengaturan lanjutan",
"PopUpForm.Email.email_templates.inputDescription": "Jika Anda tidak yakin bagaimana menggunakan variabel, {link}",
"PopUpForm.Email.link.documentation": "lihat dokumentasi kami.",
"PopUpForm.Email.options.from.email.label": "Email pengirim",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nama pengirim",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Pesan",
"PopUpForm.Email.options.object.label": "Subyek",
"PopUpForm.Email.options.object.placeholder": "Harap konfirmasi alamat email Anda untuk% APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email tanggapan",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Jika dinonaktifkan, pengguna tidak akan dapat menggunakan penyedia ini.",
"PopUpForm.Providers.enabled.label": "Memungkinkan",
"PopUpForm.Providers.key.label": "ID Klien",
"PopUpForm.Providers.key.placeholder": "TEKS",
"PopUpForm.Providers.redirectURL.front-end.label": "URL pengalihan ke aplikasi front-end Anda",
"PopUpForm.Providers.redirectURL.label": "URL pengalihan yang akan ditambahkan dalam konfigurasi aplikasi {provider} Anda",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEKS",
"PopUpForm.Providers.subdomain.label": "URI Host (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "saya.subdomain.com",
"PopUpForm.header.edit.email-templates": "Edit Template Email",
"PopUpForm.header.edit.providers": "Edit Penyedia",
"Settings.roles.deleted": "Peran dihapus",
"Settings.roles.edited": "Peran diedit",
"Settings.section-label": "Plugin Pengguna & Izin",
"notification.success.submit": "Pengaturan telah diperbarui",
"plugin.description.long": "Lindungi API Anda dengan proses otentikasi penuh berdasarkan JWT. Plugin ini juga dilengkapi dengan strategi ACL yang memungkinkan Anda untuk mengelola izin di antara grup pengguna.",
"plugin.description.short": "Lindungi API Anda dengan proses otentikasi penuh berdasarkan JWT",
"plugin.name": "Plugin Pengguna & Izin",
"popUpWarning.button.cancel": "Batalkan",
"popUpWarning.button.confirm": "Konfirmasi",
"popUpWarning.title": "Harap konfirmasi",
"popUpWarning.warning.cancel": "Anda yakin ingin membatalkan modifikasi Anda?"
}

View File

@@ -0,0 +1,58 @@
{
"BoundRoute.title": "Vincola route a",
"EditForm.inputSelect.description.role": "Questa operazione assocerà i nuovi utenti autenticati al ruolo selezionato.",
"EditForm.inputSelect.label.role": "Ruolo di default per gli utenti registrati",
"EditForm.inputToggle.description.email": "Non consentire all'utente di creare account multipli usando lo stesso indirizzo email con provider di autenticazione diversi.",
"EditForm.inputToggle.description.email-confirmation": "Quando abilitato (ON), i nuovi utenti registrati riceveranno una richiesta di conferma via email.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Scegli dove redirigere gli utenti che completano la conferma dell'indirizzo email.",
"EditForm.inputToggle.description.email-reset-password": "URL della pagina per il reset della password della tua applicazione",
"EditForm.inputToggle.description.sign-up": "Quando disabilitata (OFF), il processo di registrazione è proibito. Nessuno può iscriversi indipendentemente dal provider utilizzato.",
"EditForm.inputToggle.label.email": "Un solo account per indirizzo email",
"EditForm.inputToggle.label.email-confirmation": "Abilita conferma email",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL di reindirizzamento",
"EditForm.inputToggle.label.email-reset-password": "Pagina reset password",
"EditForm.inputToggle.label.sign-up": "Abilita registrazione",
"Email.template.email_confirmation": "Conferma dell'indirizzo Email",
"HeaderNav.link.advancedSettings": "Impostazioni avanzate",
"HeaderNav.link.emailTemplates": "Template delle Email",
"HeaderNav.link.providers": "Provider",
"Plugin.permissions.plugins.description": "Definisce tutte le azioni consentite per il plugin {name}.",
"Plugins.header.description": "Di seguito sono elencate solo le azioni vincolate da una route.",
"Plugins.header.title": "Permessi",
"Policies.header.hint": "Seleziona le azioni dell'applicazione o del plugin e clicca sull'ingranaggio per mostrare il percorso corrispondente",
"Policies.header.title": "Impostazioni avanzate",
"PopUpForm.Email.email_templates.inputDescription": "Se non sai bene come usare le variabili, {link}",
"PopUpForm.Email.link.documentation": "controlla la nostra documentazione.",
"PopUpForm.Email.options.from.email.label": "Email del mittente",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nome del mittente",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Messaggio",
"PopUpForm.Email.options.object.label": "Oggetto",
"PopUpForm.Email.options.object.placeholder": "Conferma il tuo indirizzo email per %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email di risposta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Se disabilitato, gli utenti non potranno usare questo provider.",
"PopUpForm.Providers.enabled.label": "Abilita",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "L'URL di reindirizzamento per la tua app di front-end",
"PopUpForm.Providers.redirectURL.label": "L'URL di reindirizzamento da aggiungere nelle impostazioni dell'applicazione di {provider}",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Sottodominio)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Modifica i Template Email",
"PopUpForm.header.edit.providers": "Modifica Provider",
"Settings.roles.deleted": "Ruolo eliminato",
"Settings.roles.edited": "Ruolo modificato",
"Settings.section-label": "Plugin Utenti & Permessi",
"notification.success.submit": "Impostazioni aggiornate",
"plugin.description.long": "Proteggi le tue API con un processo di autenticazione completo basato su JWT. Questo plugin è implementato con una strategia ACL che ti consente di gestire i permessi tra i gruppi di utenti.",
"plugin.description.short": "Proteggi le tue API con un processo di autenticazione completo basato su JWT",
"plugin.name": "Plugin Utenti & Permessi",
"popUpWarning.button.cancel": "Annulla",
"popUpWarning.button.confirm": "Conferma",
"popUpWarning.title": "Si prega di confermare",
"popUpWarning.warning.cancel": "Sei sicuro di voler annullare le tue modifiche?"
}

View File

@@ -0,0 +1,44 @@
{
"BoundRoute.title": "Bound route to",
"EditForm.inputSelect.description.role": "新しい認証されたユーザーが選択された役割にアタッチされます。",
"EditForm.inputSelect.label.role": "認証されたユーザーのデフォルトの役割",
"EditForm.inputToggle.description.email": "ユーザーが異なる認証プロバイダで同じ電子メールアドレスを使用して複数のアカウントを作成できないようにします。",
"EditForm.inputToggle.description.email-confirmation": "有効ONにすると、新しい登録ユーザーに確認メールが送信されます。",
"EditForm.inputToggle.description.email-confirmation-redirection": "あなたのEメールを確認したら、リダイレクト先を選択してください。",
"EditForm.inputToggle.description.sign-up": "あなたの電子メールを確認した後、リダイレクト先を選択しました。",
"EditForm.inputToggle.label.email": "メールアドレスごとに1つのアカウント",
"EditForm.inputToggle.label.email-confirmation": "Eメールの確認を有効にする",
"EditForm.inputToggle.label.email-confirmation-redirection": "リダイレクトURL",
"EditForm.inputToggle.label.sign-up": "申し込みを有効にする",
"HeaderNav.link.advancedSettings": "高度な設定",
"HeaderNav.link.emailTemplates": "メールテンプレート",
"HeaderNav.link.providers": "プロバイダー",
"Plugin.permissions.plugins.description": "{name} 個のプラグインに対して許可されたすべてのアクションを定義する",
"Plugins.header.description": "ルートにバインドされたアクションのみが以下にリストされています",
"Plugins.header.title": "権限",
"Policies.header.hint": "アプリケーションのアクションまたはプラグインのアクションを選択し、コグアイコンをクリックしてバインドされたルートを表示します",
"Policies.header.title": "高度な設定",
"PopUpForm.Email.email_templates.inputDescription": "変数の使用方法がわからない場合は、{link}",
"PopUpForm.Email.options.from.email.label": "送信者Eメール",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "送信者名",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "メッセージ",
"PopUpForm.Email.options.object.label": "件名",
"PopUpForm.Email.options.response_email.label": "応答メール",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "無効にすると、ユーザーはこのプロバイダを使用できなくなります。",
"PopUpForm.Providers.enabled.label": "有効にする",
"PopUpForm.Providers.key.label": "クライアントID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "フロントエンドアプリへのリダイレクトURL",
"PopUpForm.Providers.secret.label": "クライアントの秘密",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "メールテンプレートの編集",
"notification.success.submit": "設定が更新されました",
"plugin.description.long": "JWTに基づいた完全な認証プロセスでAPIを保護します。このプラグインには、ユーザーのグループ間で権限を管理できるACL戦略もあります。",
"plugin.description.short": "JWTに基づく完全な認証プロセスでAPIを保護する",
"plugin.name": "ロールと権限"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "라우트(bound route)",
"EditForm.inputSelect.description.role": "인증된 사용자에 선택한 역할(role)을 부여합니다.",
"EditForm.inputSelect.label.role": "인증된 사용자의 기본 역할(role)",
"EditForm.inputToggle.description.email": "사용자가 동일한 이메일 주소를 사용해 여러 계정을 만들지 못하게 합니다.",
"EditForm.inputToggle.description.email-confirmation": "(ON)이 활성화되면, 새로 가입하는 사용자는 인증 메일을 받게됩니다.",
"EditForm.inputToggle.description.email-confirmation-redirection": "이메일 인증완료 후 리다이렉트 될 주소",
"EditForm.inputToggle.description.email-reset-password": "애플리케이션의 비밀번호 재설정 URL 페이지",
"EditForm.inputToggle.description.sign-up": "비활성(OFF)일 경우, 등록 프로세스를 금지합니다. 사용하는 프로바이더(provider)에 관계 없이 누구도 가입할 수 없습니다.",
"EditForm.inputToggle.label.email": "이메일 주소 당 하나의 계정",
"EditForm.inputToggle.label.email-confirmation": "이메일 인증 활성화",
"EditForm.inputToggle.label.email-confirmation-redirection": "리다이렉션 url",
"EditForm.inputToggle.label.email-reset-password": "패스워드 재설정 페이지",
"EditForm.inputToggle.label.sign-up": "사용자 등록",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "예: https://yourfrontend.com/reset-password",
"EditForm.inputToggle.placeholder.email-reset-password": "예: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "역할 상세정보",
"Email.template.data.loaded": "이메일 템플릿을 불러왔습니다.",
"Email.template.email_confirmation": "이메일 주소 확인",
"Email.template.form.edit.label": "템플릿 수정",
"Email.template.table.action.label": "action",
"Email.template.table.icon.label": "icon",
"Email.template.table.name.label": "name",
"Form.advancedSettings.data.loaded": "고급 설정 정보를 불러왔습니다.",
"HeaderNav.link.advancedSettings": "고급 설정",
"HeaderNav.link.emailTemplates": "이메일 템플릿",
"HeaderNav.link.providers": "프로바이더(Providers)",
"Plugin.permissions.plugins.description": "{name} 플러그인에서 허용할 액션을 설정합니다.",
"Plugins.header.description": "라우트(route)에 연결된 액션만 표시됩니다.",
"Plugins.header.title": "권한(Permissions)",
"Policies.header.hint": "애플리케이션 또는 플러그인을 선택하고 항목을 클릭하면 바인딩 된 경로를 표시할 수 있습니다.",
"Policies.header.title": "고급 설정",
"PopUpForm.Email.email_templates.inputDescription": "이메일 템플릿 문법은 이 {link}를 확인하세요.",
"PopUpForm.Email.link.documentation": "check out our documentation.",
"PopUpForm.Email.options.from.email.label": "보내는 이메일",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "보내는 사람",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "내용",
"PopUpForm.Email.options.object.label": "제목",
"PopUpForm.Email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "응답받을 이메일",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "사용하지 않을 경우 이 프로바이더(provider) 기능을 이용할 수 없습니다.",
"PopUpForm.Providers.enabled.label": "사용",
"PopUpForm.Providers.key.label": "클라이언트 ID(Client ID)",
"PopUpForm.Providers.key.placeholder": "텍스트",
"PopUpForm.Providers.redirectURL.front-end.label": "프론트엔드 애플리케이션 리다이렉트 URL",
"PopUpForm.Providers.redirectURL.label": "{provider} 애플리케이션 구성에 추가할 리디렉션 URL",
"PopUpForm.Providers.secret.label": "클라이언트 시크릿(Client Secret)",
"PopUpForm.Providers.secret.placeholder": "텍스트",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "이메일 템플릿 수정",
"PopUpForm.header.edit.providers": "프로바이더 수정",
"Providers.data.loaded": "프로바이더를 불러왔습니다.",
"Providers.status": "상태",
"Roles.empty": "아직 역할이 없습니다.",
"Roles.empty.search": "검색과 일치하는 역할이 없습니다.",
"Settings.roles.deleted": "Role deleted",
"Settings.roles.edited": "Role edited",
"Settings.section-label": "사용자 & 권한 플러그인",
"components.Input.error.validation.email": "유효하지 않은 이메일입니다.",
"components.Input.error.validation.json": "JSON 형식과 일치하지 않습니다.",
"components.Input.error.validation.max": "값이 너무 큽니다.",
"components.Input.error.validation.maxLength": "값이 너무 깁니다.",
"components.Input.error.validation.min": "값이 너무 작습니다.",
"components.Input.error.validation.minLength": "값이 너무 짧습니다.",
"components.Input.error.validation.minSupMax": "이보다 클 수 없습니다.",
"components.Input.error.validation.regex": "값이 정규식과 일치하지 않습니다.",
"components.Input.error.validation.required": "필수 항목입니다.",
"components.Input.error.validation.unique": "이 값은 이미 사용되고 있습니다.",
"notification.success.submit": "설정을 업데이트했습니다.",
"page.title": "설정 - 역할",
"plugin.description.long": "JWT 기반의 인증 프로세스로 API를 보호하세요. 이 플러그인에서 사용자 그룹간 권한을 관리할 수 있는 ACL 전략도 설정할 수 있습니다.",
"plugin.description.short": "JWT 기반의 인증 프로세스로 API를 보호하세요.",
"plugin.name": "역할(roles) & 권한(permissions)",
"popUpWarning.button.cancel": "취소",
"popUpWarning.button.confirm": "확인",
"popUpWarning.title": "Please confirm",
"popUpWarning.warning.cancel": "수정 사항을 취소하시겠습니까?"
}

View File

@@ -0,0 +1,45 @@
{
"BoundRoute.title": "Ikat laluan ke",
"EditForm.inputSelect.description.role": "Ini akan meletakkan peranan yang dipilih pada pengguna baru.",
"EditForm.inputSelect.label.role": "Peranan asal untuk pengguna yang disahkan",
"EditForm.inputToggle.description.email": "Tidak membenarkan pengguna membuat beberapa akaun menggunakan alamat e-mel yang sama dengan pembekal pengesahan yang berbeza.",
"EditForm.inputToggle.description.email-confirmation": "Apabila diaktifkan (ON), pengguna berdaftar baru akan menerima e-mel pengesahan.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Setelah mengesahkan e-mel anda, pilih di mana anda akan di redirect kan.",
"EditForm.inputToggle.description.email-reset-password": "URL halaman kata laluan tetapan semula untuk aplikasi anda",
"EditForm.inputToggle.description.sign-up": "Apabila dinyahaktifkan (MATI), proses pendaftaran tidak dibenarkan. Tidak ada yang boleh melanggan lagi tidak kira pembekal telah dipakai.",
"EditForm.inputToggle.label.email": "Satu akaun setiap alamat e-mel",
"EditForm.inputToggle.label.email-confirmation": "Aktifkan pengesahan e-mel",
"EditForm.inputToggle.label.email-confirmation-redirection": "Redirection url",
"EditForm.inputToggle.label.email-reset-password": "Halaman tetapan semula kata laluan",
"EditForm.inputToggle.label.sign-up": "Aktifkan pendaftaran",
"HeaderNav.link.advancedSettings": "Tetapan lanjut",
"HeaderNav.link.emailTemplates": "Templat e-mel",
"HeaderNav.link.providers": "Pembekal",
"Plugin.permissions.plugins.description": "Pilih arahan yang dibenarkan untuk plugin {name}.",
"Plugins.header.description": "Hanya arahan yang terpasang dengan laluan sahaja yang tersenarai di bawah.",
"Plugins.header.title": "Keizinan",
"Policies.header.hint": "Pilih tindakan aplikasi atau plugin dan klik pada ikon gear untuk melihat laluan yang terpasang",
"Policies.header.title": "Tetapan lanjut",
"PopUpForm.Email.email_templates.inputDescription": "Sekiranya anda tidak pasti cara menggunakan pemboleh ubah, {link} ",
"PopUpForm.Email.options.from.email.label": "E-mel penghantar",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nama pengirim",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mesej",
"PopUpForm.Email.options.object.label": "Subjek",
"PopUpForm.Email.options.response_email.label": "E-mel jawapan",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Sekiranya dinyahaktifkan, pengguna tidak akan dapat menggunakan pembekal ini.",
"PopUpForm.Providers.enabled.label": "Aktifkan",
"PopUpForm.Providers.key.label": "ID Pelanggan",
"PopUpForm.Providers.key.placeholder": "TEKS",
"PopUpForm.Providers.redirectURL.front-end.label": "URL pengubah hala ke aplikasi 'front-end' anda",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEKS",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Edit Templat E-mel",
"notification.success.submit": "Tetapan telah dikemas kini",
"plugin.description.long": "Lindungi API anda dengan proses pengesahan penuh berdasarkan JWT. Plugin ini juga dilengkapi dengan strategi ACL yang membolehkan anda mengurus pengizinan antara kumpulan pengguna.",
"plugin.description.short": "Lindungi API anda dengan proses pengesahan penuh berdasarkan JWT"
}

View File

@@ -0,0 +1,44 @@
{
"BoundRoute.title": "Gebonden route naar",
"EditForm.inputSelect.description.role": "Het zal de nieuwe geautoriseerde gebruiker aan de geselecteerde rol verbinden.",
"EditForm.inputSelect.label.role": "Standaard rol voor geautoriseerde gebruikers",
"EditForm.inputToggle.description.email": "Zorg ervoor dat de gebruiker niet meerdere accounts kan maken met hetzelfde e-mailadres maar met verschillende leveranciers.",
"EditForm.inputToggle.description.email-confirmation": "Wanneer ingeschakeld (ON), ontvangen nieuw geregistreerde gebruikers een bevestigingsmail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Na het bevestigen van je e-mail, kies naar waar je doorgestuurd zal worden.",
"EditForm.inputToggle.description.sign-up": "Wanneer uitgeschakeld (OFF), is registratie verboden. Niemand kan abonneren ongeacht de leverancier",
"EditForm.inputToggle.label.email": "Één account per e-mailadres.",
"EditForm.inputToggle.label.email-confirmation": "Schakel emailbevestiging in",
"EditForm.inputToggle.label.email-confirmation-redirection": "Doorstuur URL",
"EditForm.inputToggle.label.sign-up": "Registratie inschakelen",
"HeaderNav.link.advancedSettings": "Geavanceerde instellingen",
"HeaderNav.link.emailTemplates": "E-mail sjabloon",
"HeaderNav.link.providers": "Leveranciers",
"Plugin.permissions.plugins.description": "Voer alle toegestane acties in voor extensie {name}.",
"Plugins.header.description": "Alleen acties gekoppeld aan een route worden hieronder weergegeven.",
"Plugins.header.title": "Permissies",
"Policies.header.hint": "Selecteer de actie van de applicatie of de acties van de extensie en klik op het tandwiel icoontje om de gekoppelde route weer te geven",
"Policies.header.title": "Geavanceerde instellingen",
"PopUpForm.Email.email_templates.inputDescription": "Als je niet zeker weet hoe je variabelen moet gebruiken, {link}",
"PopUpForm.Email.options.from.email.label": "Afzender e-mail",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Afzender naam",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Bericht",
"PopUpForm.Email.options.object.label": "Onderwerp",
"PopUpForm.Email.options.response_email.label": "Antwoord e-mail",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Als deze uitgeschakeld is kunnen gebruikers geen gebruik maken van deze leverancier.",
"PopUpForm.Providers.enabled.label": "Inschakelen",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "De doorstuur URL voor jouw front-end app",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "E-mail sjablonen aanpassen",
"notification.success.submit": "Instellingen zijn geüpdatet",
"plugin.description.long": "Beveilig je API met een volledig authenticatie proces op JWT. Deze extensie komt ook met een ACL strategie welke ervoor zorgt dat je de permissies tussen groepen van gebruikers kan beheren.",
"plugin.description.short": "Beveilig je API met een volledig authenticatie proces op JWT",
"plugin.name": "Rollen & Permissies"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "Wywoływanie",
"EditForm.inputSelect.description.role": "Połączy nowego uwierzytelnionego użytkownika z wybraną rolą.",
"EditForm.inputSelect.label.role": "Domyślna rola dla uwierzytelnionych użytkowników",
"EditForm.inputToggle.description.email": "Nie zezwalaj użytkownikowi na tworzenie wielu kont za pomocą tego samego adresu e-mail u różnych dostawców uwierzytelniania.",
"EditForm.inputToggle.description.email-confirmation": "Gdy włączone (ON), nowo zarejestrowani uzytkownicy otrzymają wiadomość potwierdzającą.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Po potwierdzeniu adresu email, wybierz gdzie zostaniesz przekierowany.",
"EditForm.inputToggle.description.email-reset-password": "Adres URL strony resetowania hasła aplikacji",
"EditForm.inputToggle.description.sign-up": "Po wyłączeniu (OFF) proces rejestracji jest zabroniony. Nikt nie może już dołączyć bez względu na używanego dostawcę.",
"EditForm.inputToggle.label.email": "Jedno konto na adres email",
"EditForm.inputToggle.label.email-confirmation": "Zezwól na potwierdzenie adresu email",
"EditForm.inputToggle.label.email-confirmation-redirection": "Url przekierowania",
"EditForm.inputToggle.label.email-reset-password": "Strona resetowania hasła",
"EditForm.inputToggle.label.sign-up": "Włącz możliwość rejestracji",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Szczegóły roli",
"Email.template.data.loaded": "Szablon email został załadowany",
"Email.template.email_confirmation": "Potwierdzenie adresu email",
"Email.template.form.edit.label": "Edytuj szablon",
"Email.template.table.action.label": "akcja",
"Email.template.table.icon.label": "ikonka",
"Email.template.table.name.label": "nazwa",
"Form.advancedSettings.data.loaded": "Ustawienia zaawansowane zostały załadowane",
"HeaderNav.link.advancedSettings": "Zaawansowane",
"HeaderNav.link.emailTemplates": "Szablony e-mail",
"HeaderNav.link.providers": "Dostawcy",
"Plugin.permissions.plugins.description": "Określ dozwolone działania dla pluginu {name}.",
"Plugins.header.description": "Jedynie akcje związane z wywoływaniami są wymienione poniżej.",
"Plugins.header.title": "Uprawnienia",
"Policies.header.hint": "Wybierz działania aplikacji lub działania pluginu i kliknij ikonę koła zębatego, aby wyświetlić wywoływania",
"Policies.header.title": "Zaawansowane",
"PopUpForm.Email.email_templates.inputDescription": "Nie wiesz jak skonfigurować zmienne? {link}",
"PopUpForm.Email.link.documentation": "sprawdź dokumentację.",
"PopUpForm.Email.options.from.email.label": "Email nadawcy",
"PopUpForm.Email.options.from.email.placeholder": "jannowak@gmail.com",
"PopUpForm.Email.options.from.name.label": "Nazwa nadawcy",
"PopUpForm.Email.options.from.name.placeholder": "Jan Nowak",
"PopUpForm.Email.options.message.label": "Wiadomość",
"PopUpForm.Email.options.object.label": "Temat",
"PopUpForm.Email.options.object.placeholder": "Proszę potwierdź adres email dla %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email zwrotny",
"PopUpForm.Email.options.response_email.placeholder": "jannowak@gmail.com",
"PopUpForm.Providers.enabled.description": "W przypadku wyłączenia, użytkownicy nie będą mogli skorzystać z tego dostawcy.",
"PopUpForm.Providers.enabled.label": "Włączony",
"PopUpForm.Providers.key.label": "ID klienta",
"PopUpForm.Providers.key.placeholder": "TEKST",
"PopUpForm.Providers.redirectURL.front-end.label": "Adres przekierowania do własnej aplikacji",
"PopUpForm.Providers.redirectURL.label": "Adres przekierowania do dodania w twoich ustawieniach aplikacji: {provider}",
"PopUpForm.Providers.secret.label": "Klucz sekretny klienta",
"PopUpForm.Providers.secret.placeholder": "TEKST",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Zmień szablony e-mail",
"PopUpForm.header.edit.providers": "Edytuj dostawcę",
"Providers.data.loaded": "Dostawcy zostali załadowani",
"Providers.status": "Status",
"Roles.empty": "Nie masz jeszcze żadnych ról.",
"Roles.empty.search": "Żadne role nie pasują do wyszukiwania.",
"Settings.roles.deleted": "Rola usunięta",
"Settings.roles.edited": "Rola edytowana",
"Settings.section-label": "Użytkownicy i Uprawnienia",
"components.Input.error.validation.email": "Ten email jest niepoprawny",
"components.Input.error.validation.json": "Nie pasuje do formatu JSON",
"components.Input.error.validation.max": "Wartość zbyt duża.",
"components.Input.error.validation.maxLength": "Wartość zbyt długa.",
"components.Input.error.validation.min": "Wartość zbyt mała.",
"components.Input.error.validation.minLength": "Wartość zbyt krótka.",
"components.Input.error.validation.minSupMax": "Nie może być wyższy",
"components.Input.error.validation.regex": "Wartość nie pasuje do regexa.",
"components.Input.error.validation.required": "Wartość wymagana.",
"components.Input.error.validation.unique": "Wartość już używana.",
"notification.success.submit": "Ustawienia zostały zaktualizowane",
"page.title": "Ustawienia - Role",
"plugin.description.long": "Chroń API za pomocą procesu pełnego uwierzytelniania opartego na JWT. Ten plugin zawiera również strategię ACL, która pozwala zarządzać uprawnieniami między grupami użytkowników.",
"plugin.description.short": "Chroń API za pomocą procesu pełnego uwierzytelniania opartego na JWT",
"plugin.name": "Role i Uprawnienia",
"popUpWarning.button.cancel": "Anuluj",
"popUpWarning.button.confirm": "Potwierdź",
"popUpWarning.title": "Proszę potwierdź",
"popUpWarning.warning.cancel": "Czy jesteś pewny, że chcesz anulować zmiany?"
}

View File

@@ -0,0 +1,40 @@
{
"BoundRoute.title": "Rota definida para",
"EditForm.inputSelect.description.role": "Ele anexará o novo usuário autenticado ao nível selecionado.",
"EditForm.inputSelect.label.role": "Nível padrão para usuários autenticados",
"EditForm.inputToggle.description.email": "Não permitir que o usuário crie várias contas usando o mesmo endereço de e-mail com diferentes provedores de autenticação.",
"EditForm.inputToggle.description.sign-up": "Quando desativado (OFF), o processo de registro é proibido. Nenhum novo usuário poderá se registrar, não importa o provedor usado.",
"EditForm.inputToggle.label.email": "Limitar 1 conta por endereço de email",
"EditForm.inputToggle.label.sign-up": "Ativar registro de usuários",
"HeaderNav.link.advancedSettings": "Configurações avançadas",
"HeaderNav.link.emailTemplates": "Modelos de email",
"HeaderNav.link.providers": "Provedores",
"Plugin.permissions.plugins.description": "Defina todas as ações permitidas para o plugin {name}.",
"Plugins.header.description": "Somente ações vinculadas por uma rota estão listadas abaixo.",
"Plugins.header.title": "Permissões",
"Policies.header.hint": "Selecione as ações do aplicativo ou as ações do plugin e clique no ícone do cog para exibir a rota",
"Policies.header.title": "Configurações avançadas",
"PopUpForm.Email.email_templates.inputDescription": "Se não tiver certeza de como usar variáveis, {link}",
"PopUpForm.Email.options.from.email.label": "Email do remetente",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nome do remetente",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mensagem",
"PopUpForm.Email.options.object.label": "Assunto",
"PopUpForm.Email.options.response_email.label": "Email de resposta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Se desativado, os usuários não poderão usar este provedor",
"PopUpForm.Providers.enabled.label": "Ativar",
"PopUpForm.Providers.key.label": "ID do cliente",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "O URL de redirecionamento para seu aplicativo front-end",
"PopUpForm.Providers.secret.label": "Segredo do Cliente",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Editar modelos de email",
"notification.success.submit": "As configurações foram atualizadas",
"plugin.description.long": "Proteja sua API com um processo de autenticação completo baseado no JWT. Esse plugin também vem com uma estratégia de ACL que permite gerenciar as permissões entre os grupos de usuários.",
"plugin.description.short": "Proteja sua API com um processo de autenticação completo baseado no JWT",
"plugin.name": "Papéis e permissões"
}

View File

@@ -0,0 +1,44 @@
{
"BoundRoute.title": "Ligar rota a",
"EditForm.inputSelect.description.role": "Vai atribuir o grupo selecionado ao novo utilizador autenticado.",
"EditForm.inputSelect.label.role": "Grupo por defeito para utilizadores autenticados",
"EditForm.inputToggle.description.email": "Proibir a criação de múltiplas contas com o mesmo email por serviços de autenticação diferentes.",
"EditForm.inputToggle.description.email-confirmation": "Quando ativado (ON), os novos utilizadores recebem um email de confirmação.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Após confirmar o seu email, escolha para onde vai ser redirecionado.",
"EditForm.inputToggle.description.sign-up": "Quando desativado (OFF), o processo de registo está proibido. Ninguém se consegue registar mais, independentemente do serviço de authenticação.",
"EditForm.inputToggle.label.email": "Uma conta por endereço de email",
"EditForm.inputToggle.label.email-confirmation": "Ativar email de confirmação",
"EditForm.inputToggle.label.email-confirmation-redirection": "Endereço de redirecionamento (URL)",
"EditForm.inputToggle.label.sign-up": "Ativar registos",
"HeaderNav.link.advancedSettings": "Configurações avançadas",
"HeaderNav.link.emailTemplates": "Modelos de email",
"HeaderNav.link.providers": "Serviços de autenticação",
"Plugin.permissions.plugins.description": "Defina todas as ações permitidas para o plugin {name}.",
"Plugins.header.description": "Todas as ações associadas a uma rota estão listadas abaixo.",
"Plugins.header.title": "Permissões",
"Policies.header.hint": "Selecione as ações da aplicação ou dos plugins e clique no ícone para mostrar as rotas associadas",
"Policies.header.title": "Configurações avançadas",
"PopUpForm.Email.email_templates.inputDescription": "Se não tem a certeza de como usar as variáveis, {link}",
"PopUpForm.Email.options.from.email.label": "Shipper email",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Shipper name",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mensagem",
"PopUpForm.Email.options.object.label": "Assunto",
"PopUpForm.Email.options.response_email.label": "Email de resposta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Se desativado, os utilizadores não conseguirão utilizar este serviço de autenticação.",
"PopUpForm.Providers.enabled.label": "Ativar",
"PopUpForm.Providers.key.label": "ID de Client",
"PopUpForm.Providers.key.placeholder": "TEXTO",
"PopUpForm.Providers.redirectURL.front-end.label": "Endereço de redirecionamento para a sua aplicação de front-end",
"PopUpForm.Providers.secret.label": "Segredo de cliente",
"PopUpForm.Providers.secret.placeholder": "TEXTO",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Editar Modelos de Email",
"notification.success.submit": "As configurações foram atualizadas",
"plugin.description.long": "Proteja a sua API com um processo completo de autenticação baseado em JWT. Este plugin também vem com estratégia de ACL que permite gerir permissões entre grupos de utilizadores.",
"plugin.description.short": "Proteja a sua API com um processo completo de autenticação baseado em JWT",
"plugin.name": "Grupos & Permissões"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "Связать путь с",
"EditForm.inputSelect.description.role": "При регистрации пользователи будут иметь выбранную роль.",
"EditForm.inputSelect.label.role": "Роль по умолчанию для новых пользователей",
"EditForm.inputToggle.description.email": "Запретить пользователю создавать несколько учётных записей, используя один и тот же адрес электронной почты, у разных поставщиков аутентификации.",
"EditForm.inputToggle.description.email-confirmation": "Если включено (ON), при регистрации пользователи будут получать письмо для подтверждения адреса электронной почты.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Укажите URL-адрес для перенаправления пользователей после подтверждения адреса электронной почты.",
"EditForm.inputToggle.description.email-reset-password": "URL-адрес страницы для сброса пароля учётной записи пользователя",
"EditForm.inputToggle.description.sign-up": "Если выключено (OFF), процесс регистрации пользователей запрещен. Никто не может зарегистрироваться, независимо от провайдера.",
"EditForm.inputToggle.label.email": "Одна учётная запись на один адрес электронной почты",
"EditForm.inputToggle.label.email-confirmation": "Включить подтверждение по электронной почте",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL-адрес для перенаправления",
"EditForm.inputToggle.label.email-reset-password": "Страница сброса пароля",
"EditForm.inputToggle.label.sign-up": "Включить регистрации",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "например: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "например: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Сведения о роли",
"Email.template.data.loaded": "Шаблоны автоматических писем для электронной почты были загружены",
"Email.template.email_confirmation": "Адреса электронной почты с письмом о подтверждении",
"Email.template.form.edit.label": "Редактировать шаблон",
"Email.template.table.action.label": "действие",
"Email.template.table.icon.label": "иконка",
"Email.template.table.name.label": "название",
"Form.advancedSettings.data.loaded": "Данные расширенных настроек были загружены",
"HeaderNav.link.advancedSettings": "Расширенные настройки",
"HeaderNav.link.emailTemplates": "Шаблоны писем",
"HeaderNav.link.providers": "Провайдеры",
"Plugin.permissions.plugins.description": "Определите все разрешенные действия для плагина {name}.",
"Plugins.header.description": "Ниже перечислены только действия, связанные с путём.",
"Plugins.header.title": "Разрешения",
"Policies.header.hint": "Выберите действия приложения или плагина и нажмите на значок шестерёнки, чтобы отобразить связанный путь",
"Policies.header.title": "Расширенные настройки",
"PopUpForm.Email.email_templates.inputDescription": "Если вы не уверены, как использовать переменные — {link}",
"PopUpForm.Email.link.documentation": "ознакомьтесь с нашей документацией.",
"PopUpForm.Email.options.from.email.label": "Электронная почта отправителя",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Имя отправителя",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Сообщение",
"PopUpForm.Email.options.object.label": "Тема",
"PopUpForm.Email.options.object.placeholder": "Пожалуйста, подтвердите свой адрес электронной почты для %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Электронная почта для ответов",
"PopUpForm.Email.options.response_email.placeholder": "paul@example.com",
"PopUpForm.Providers.enabled.description": "Если этот параметр отключен, пользователи не смогут использовать этого поставщика.",
"PopUpForm.Providers.enabled.label": "Включено",
"PopUpForm.Providers.key.label": "ID клиента",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "URL-адрес перенаправления на ваше приложение",
"PopUpForm.Providers.redirectURL.label": "URL-адрес перенаправления, который нужно добавить в {provider} конфигурации приложения",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Хост URI (Поддомен)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Редактировать шаблон письма",
"PopUpForm.header.edit.providers": "Редактировать провайдера",
"Providers.data.loaded": "Провайдеры были загружены",
"Providers.status": "Статус",
"Roles.empty": "У вас пока нет никаких ролей.",
"Roles.empty.search": "Ни одна роль не соответствует поисковому запросу.",
"Settings.roles.deleted": "Роль удалена",
"Settings.roles.edited": "Роль отредактирована",
"Settings.section-label": "Плагин «Пользователи и Разрешения»",
"components.Input.error.validation.email": "Неверный адрес электронной почты",
"components.Input.error.validation.json": "Это не соответствует формату JSON",
"components.Input.error.validation.max": "Значение слишком велико.",
"components.Input.error.validation.maxLength": "Значение слишком длинное.",
"components.Input.error.validation.min": "Значение слишком мало.",
"components.Input.error.validation.minLength": "Значение слишком короткое.",
"components.Input.error.validation.minSupMax": "Не может быть выше",
"components.Input.error.validation.regex": "Значение не соответствует регулярному выражению.",
"components.Input.error.validation.required": "Это значение является обязательным.",
"components.Input.error.validation.unique": "Это значение уже используется.",
"notification.success.submit": "Настройки были обновлены",
"page.title": "Настройки — Роли",
"plugin.description.long": "Защитите свой API с помощью полноценного процесса аутентификации, основанного на JWT. Этот плагин также имеет настройки стратегии ACL, которые позволяют вам управлять разрешениями между группами пользователей.",
"plugin.description.short": "Защитите свой API с помощью полноценного процесса аутентификации, основанного на JWT.",
"plugin.name": "Пользователи и Разрешения",
"popUpWarning.button.cancel": "Отменить",
"popUpWarning.button.confirm": "Подтвердить",
"popUpWarning.title": "Пожалуйста подтвердите",
"popUpWarning.warning.cancel": "Вы уверены, что хотите отменить свои изменения?"
}

View File

@@ -0,0 +1,46 @@
{
"BoundRoute.title": "URL endpoint naviazaný k",
"EditForm.inputSelect.description.role": "Pridá rolu k používateľovi.",
"EditForm.inputSelect.label.role": "Predvolená rola pre autorizovaných používateľov",
"EditForm.inputToggle.description.email": "Zakázať používateľovi vytvoriť viac účtov s rovnakou e-mailovou adresou pre rôznych poskytovateľov.",
"EditForm.inputToggle.description.email-confirmation": "Ak je povolené (ON), registrovaní používatelia dostanú potvrdzovací e-mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "URL na ktorú bude používateľ presmerovaný po potvrdení e-mailu.",
"EditForm.inputToggle.description.email-reset-password": "URL pre nastavenie nového hesla",
"EditForm.inputToggle.description.sign-up": "Ak je zakázané (OFF), registrácie nebudú povolené. Nikto sa nebude môcť registrovať bez ohľadu na zvoleného poskytovateľa.",
"EditForm.inputToggle.label.email": "Iba jedno konto pre jednu e-mailovú adresu",
"EditForm.inputToggle.label.email-confirmation": "Povoliť potvrdzovanie e-mailových adries",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL pre potvrdenie e-mailovej adresy",
"EditForm.inputToggle.label.email-reset-password": "URL pre obnovu hesla",
"EditForm.inputToggle.label.sign-up": "Povoliť registrácie",
"HeaderNav.link.advancedSettings": "Pokročilé nastavenia",
"HeaderNav.link.emailTemplates": "Šablóny emailov",
"HeaderNav.link.providers": "Poskytovatelia",
"Plugin.permissions.plugins.description": "Zvoľte akcie, ktoré majú byť povolené pre plugin {name}.",
"Plugins.header.description": "Zobrazujú sa iba akcie naviazané na URL endpoint.",
"Plugins.header.title": "Oprávnenia",
"Policies.header.hint": "Vyberte akciu a kliknite na ikonku nastavení pre zobrazenie naviazanej URL",
"Policies.header.title": "Pokročilé nastavenia",
"PopUpForm.Email.email_templates.inputDescription": "Ak si nie ste istý ako používať premenné, {link}",
"PopUpForm.Email.options.from.email.label": "E-mail odosielateľa",
"PopUpForm.Email.options.from.email.placeholder": "janko.hrasko@gmail.com",
"PopUpForm.Email.options.from.name.label": "Meno odosielateľa",
"PopUpForm.Email.options.from.name.placeholder": "Janko Hraško",
"PopUpForm.Email.options.message.label": "Obsah e-mailu",
"PopUpForm.Email.options.object.label": "Predmet",
"PopUpForm.Email.options.response_email.label": "Odpovedať na e-mail",
"PopUpForm.Email.options.response_email.placeholder": "janko.hrasko@gmail.com",
"PopUpForm.Providers.enabled.description": "Ak je zakázané, používatelia nebudú môcť použiť tohto poskytovateľa.",
"PopUpForm.Providers.enabled.label": "Povoliť",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "URL presmerovania do vašej aplikácie",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Upraviť šablóny e-mailov",
"notification.success.submit": "Nastavenia boli uložené",
"plugin.description.long": "Zabezpečte vaše API pomocou JWT tokenov. Tento plugin taktiež podporuje ACL záznamy, ktoré umožňujú spravovať oprávnenia v rámci skupín používateľov.",
"plugin.description.short": "Zabezpečte vaše API pomocou JWT tokenov",
"plugin.name": "Roly a oprávnenia"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "Bind rutt till",
"EditForm.inputSelect.description.role": "Den bifogar den nya autentiserade användaren till den valda rollen.",
"EditForm.inputSelect.label.role": "Standardroll för autentiserade användare",
"EditForm.inputToggle.description.email": "Tillåt ej användaren att skapa flera konton med samma e-postadress med olika autentiseringstjänster.",
"EditForm.inputToggle.description.email-confirmation": "När aktiverat (PÅ) får nya registrerade användare ett bekräftelsemeddelande.",
"EditForm.inputToggle.description.email-confirmation-redirection": "När du har bekräftat din e-post väljer du var du ska omdirigeras.",
"EditForm.inputToggle.description.email-reset-password": "URL:en till din applikations sida för återställning av lösenord",
"EditForm.inputToggle.description.sign-up": "När inaktiverad (AV) är registreringsprocessen förbjuden. Ingen kan prenumerera längre oavsett vilken autentiseringstjänst som används.",
"EditForm.inputToggle.label.email": "Ett konto per e-postadress",
"EditForm.inputToggle.label.email-confirmation": "Aktivera e-postbekräftelse",
"EditForm.inputToggle.label.email-confirmation-redirection": "Omdirigerings-url",
"EditForm.inputToggle.label.email-reset-password": "Återställ lösenordssidan",
"EditForm.inputToggle.label.sign-up": "Tillåt registreringar",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "t.ex: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "t.ex: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Rolldetaljer",
"Email.template.data.loaded": "E-postmallar har laddats",
"Email.template.email_confirmation": "Bekräftelse av e-postadress",
"Email.template.form.edit.label": "Redigera en mall",
"Email.template.table.action.label": "händelse",
"Email.template.table.icon.label": "ikon",
"Email.template.table.name.label": "namn",
"Form.advancedSettings.data.loaded": "Data för avancerade inställningar har laddats",
"HeaderNav.link.advancedSettings": "Avancerade inställningar",
"HeaderNav.link.emailTemplates": "E-postmall",
"HeaderNav.link.providers": "Autentiseringstjänster",
"Plugin.permissions.plugins.description": "Definiera alla tillåtna åtgärder för {name} plugin.",
"Plugins.header.description": "Endast åtgärder som är bundna av en rutt listas nedan.",
"Plugins.header.title": "Behörigheter",
"Policies.header.hint": "Välj programmets åtgärder eller plugins åtgärder och klicka på kugghjulsikonen för att visa den bundna rutten",
"Policies.header.title": "Avancerade inställningar",
"PopUpForm.Email.email_templates.inputDescription": "Om du är osäker på hur du använder variabler, {link}",
"PopUpForm.Email.link.documentation": "Kolla in vår dokumentation.",
"PopUpForm.Email.options.from.email.label": "Avsändarens e-postadress",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Avsändarens namn",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Meddelande",
"PopUpForm.Email.options.object.label": "Ämne",
"PopUpForm.Email.options.object.placeholder": "Bekräfta din e-postadress för %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Svarsmail",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Om inaktiverat kan användarna inte använda den här tjänsten.",
"PopUpForm.Providers.enabled.label": "Tillåt",
"PopUpForm.Providers.key.label": "Klient ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "Omdirigerings-URL: en till din front-end-app",
"PopUpForm.Providers.redirectURL.label": "Webbadressen för omdirigering som ska läggas till i {Provider} applikationskonfigurationer",
"PopUpForm.Providers.secret.label": "Klient hemlighet",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomän)",
"PopUpForm.Providers.subdomain.placeholder": "min.subdoman.com",
"PopUpForm.header.edit.email-templates": "Redigera e-postmallar",
"PopUpForm.header.edit.providers": "Redigera tjänst",
"Providers.data.loaded": "Tjänster har laddats in",
"Providers.status": "Status",
"Roles.empty": "Du har inga roller än.",
"Roles.empty.search": "Inga roller matchar sökningen.",
"Settings.roles.deleted": "Roll borttagen",
"Settings.roles.edited": "Roll redigerad",
"Settings.section-label": "Roller och behörigheter",
"components.Input.error.validation.email": "E-postadressen är ogiltig",
"components.Input.error.validation.json": "Detta är inte giltig JSON",
"components.Input.error.validation.max": "Värdet är för högt.",
"components.Input.error.validation.maxLength": "Värdet är för långt.",
"components.Input.error.validation.min": "Värdet är för lågt.",
"components.Input.error.validation.minLength": "Värdet är för kort.",
"components.Input.error.validation.minSupMax": "Minsta värdet är större än maximalt värde.",
"components.Input.error.validation.regex": "Värdet matchar inte regex-mönstret.",
"components.Input.error.validation.required": "Värdet är obligatoriskt.",
"components.Input.error.validation.unique": "Detta värdet är redan använt.",
"notification.success.submit": "Inställningar har uppdaterats",
"page.title": "Inställningar - Roller",
"plugin.description.long": "Skydda ditt API med en fullständig autentiseringsprocess baserad på JWT. Detta plugin har också en ACL-strategi som låter dig hantera behörigheterna mellan användargrupperna.",
"plugin.description.short": "Skydda ditt API med en fullständig autentiseringsprocess baserad på JWT",
"plugin.name": "Roller och behörigheter",
"popUpWarning.button.cancel": "Avbryt",
"popUpWarning.button.confirm": "Bekräfta",
"popUpWarning.title": "Var god bekräfta",
"popUpWarning.warning.cancel": "Är du säker att du vill avbryta dina ändringar?"
}

View File

@@ -0,0 +1,56 @@
{
"BoundRoute.title": "กำหนดเส้นทางไปยัง",
"EditForm.inputSelect.description.role": "แนบผู้ใช้ที่พิสูจน์ตัวตนใหม่ไปยังบทบาทที่เลือก",
"EditForm.inputSelect.label.role": "บทบาทพื้นฐานสำหรับผู้ใช้ที่พิสูจน์ตัวตน",
"EditForm.inputToggle.description.email": "ไม่อนุญาตให้ผู้ใช้สร้างหลายแอคเคาต์ โดยใช้อีเมลเดียวกันกับผู้ให้บริการการพิสูจน์ตัวตนที่ต่างกัน",
"EditForm.inputToggle.description.email-confirmation": "เมื่อเปิดใช้งาน (เปิด) ผู้ใช้สีแดงที่ลงทะเบียนใหม่จะได้รับอีเมลยืนยัน",
"EditForm.inputToggle.description.email-confirmation-redirection": "หลังจากยืนยันอีเมลของคุณแล้ว, ให้เลือกตำแหน่งที่คุณจะเปลี่ยนทิศทาง",
"EditForm.inputToggle.description.email-reset-password": "URL ของเพจรีเซ็ตรหัสผ่านแอปพลิเคชันของคุณ",
"EditForm.inputToggle.description.sign-up": "เมื่อปิดใช้งาน (OFF) กระบวนการลงทะเบียนจะถูกห้าม ไม่มีใครสามารถสมัครสมาชิกได้อีกต่อไปไม่ว่าจะเป็นผู้ให้บริการที่ใช้",
"EditForm.inputToggle.label.email": "หนึ่งแอคเคาต์ต่ออีเมลแอดเดรส",
"EditForm.inputToggle.label.email-confirmation": "เปิดใช้งานการยืนยันอีเมล",
"EditForm.inputToggle.label.email-confirmation-redirection": "Url การเปลี่ยนทิศทาง",
"EditForm.inputToggle.label.email-reset-password": "หน้ารีเซ็ตรหัสผ่าน",
"EditForm.inputToggle.label.sign-up": "เปิดใช้งานการลงทะเบียน",
"Email.template.email_confirmation": "ยืนยันอีเมลแอดเดรส",
"HeaderNav.link.advancedSettings": "การตั้งค่าขั้นสูง",
"HeaderNav.link.emailTemplates": "เท็มเพลตอีเมล",
"HeaderNav.link.providers": "ผู้ให้บริการ",
"Plugin.permissions.plugins.description": "กำหนดการดำเนินการที่อนุญาตทั้งหมดสำหรับปลั๊กอิน {name}",
"Plugins.header.description": "เฉพาะการดำเนินการที่โยงโดยเราต์จะถูกแสดงด้านล่าง",
"Plugins.header.title": "สิทธิการใช้งาน",
"Policies.header.hint": "เลือกแอ็คชันของแอปพลิเคชันหรือแอ็คชันของปลั๊กอินและคลิกบนไอคอนฟันเฟือง เพื่อแสดงเส้นทางที่โยงไว้",
"Policies.header.title": "การตั้งค่าขั้นสูง",
"PopUpForm.Email.email_templates.inputDescription": "ถ้าคุณไม่แน่ใจว่าจะใช้ตัวแปรอย่างไร {link}",
"PopUpForm.Email.link.documentation": "ดูเอกสารของเราสิ",
"PopUpForm.Email.options.from.email.label": "อีเมล Shipper",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "ชื่อ Shipper",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "ข้อความ",
"PopUpForm.Email.options.object.label": "เรื่อง",
"PopUpForm.Email.options.object.placeholder": "โปรดยืนยันอีเมลแอดเดรสของคุณสำหรับ % APP _ NAME %",
"PopUpForm.Email.options.response_email.label": "อีเมลตอบกลับ",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "ถ้าปิดใช้งาน, ผู้ใช้จะไม่สามารถใช้ผู้ให้บริการนี้ได้",
"PopUpForm.Providers.enabled.label": "เปิดใช้งาน",
"PopUpForm.Providers.key.label": "ID ไคลเอ็นต์",
"PopUpForm.Providers.key.placeholder": "ข้อความ",
"PopUpForm.Providers.redirectURL.front-end.label": "เปลี่ยนทิศทาง URL ไปยังแอป front-end ของคุณ",
"PopUpForm.Providers.redirectURL.label": "เปลี่ยนทิศทาง URL เพื่อเพิ่มในตั้งค่าแอปพลิเคชัน {provider} ของคุณ",
"PopUpForm.Providers.secret.label": "Secret ไคลเอ็นต์",
"PopUpForm.Providers.secret.placeholder": "ข้อความ",
"PopUpForm.header.edit.email-templates": "แก้ไขเทมเพลตอีเมล",
"PopUpForm.header.edit.providers": "แก้ไขผู้ให้บริการ",
"Settings.roles.deleted": "ลบบทบาทแล้ว",
"Settings.roles.edited": "บทบาทที่แก้ไข",
"Settings.section-label": "ปลั๊กอินผู้ใช้ & สิทธิ",
"notification.success.submit": "อัปเดตการตั้งค่าแล้ว",
"plugin.description.long": "ป้องกัน API ของคุณด้วยกระบวนการพิสูจน์ตัวตนแบบสมบูรณ์โดยอิงจาก JWT ปลั๊กอินนี้มาพร้อมกับกลยุทธ์ ACL ที่อนุญาตให้คุณจัดการกับสิทธิระหว่างกลุ่มของผู้ใช้ได้ด้วย",
"plugin.description.short": "ปกป้อง API ของคุณที่มีกระบวนการพิสูจน์ตัวตนแบบสมบูรณ์โดยอิงจาก JWT",
"plugin.name": "ปลั๊กอิน ผู้ใช้ & การอนุญาต",
"popUpWarning.button.cancel": "ยกเลิก",
"popUpWarning.button.confirm": "ยืนยัน",
"popUpWarning.title": "โปรดยืนยัน",
"popUpWarning.warning.cancel": "คุณแน่ใจว่าต้องการยกเลิกการแก้ไขของคุณหรือไม่?"
}

View File

@@ -0,0 +1,81 @@
{
"BoundRoute.title": "Bağlı rota",
"EditForm.inputSelect.description.role": "Yeni kimliği doğrulanmış kullanıcıyı seçilen rolü ekler.",
"EditForm.inputSelect.label.role": "Kimliği doğrulanmış kullanıcılar için varsayılan rol",
"EditForm.inputToggle.description.email": "Kullanıcıyı, farklı kimlik doğrulama sağlayıcılarıyla aynı e-posta adresini kullanarak birden fazla hesap oluşturmasına izin vermeyin.",
"EditForm.inputToggle.description.email-confirmation": "Etkinleştirildiğinde yeni kayıtlı kullanıcılar bir onay e-postası alır.",
"EditForm.inputToggle.description.email-confirmation-redirection": "E-postanızı onayladıktan sonra, yönlendirileceğiniz yeri seçin.",
"EditForm.inputToggle.description.sign-up": "Devre dışı bırakıldığında (KAPALI), kayıt işlemi yasaktır. Artık kullanılan sağlayıcı ne olursa olsun hiç kimse abone olamaz.",
"EditForm.inputToggle.label.email": "E-posta adresi başına bir hesap",
"EditForm.inputToggle.label.email-confirmation": "E-posta onayını etkinleştir",
"EditForm.inputToggle.label.email-confirmation-redirection": "Yönlendirme URL'si",
"EditForm.inputToggle.label.sign-up": "Kayıtları etkinleştir",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ör: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "ör: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Rol detayları",
"Email.template.data.loaded": "E-posta şablonları yüklendi",
"Email.template.email_confirmation": "E-posta adresi doğrulaması",
"Email.template.form.edit.label": "Şablonu düzenle",
"Email.template.table.action.label": "eylem",
"Email.template.table.icon.label": "ikon",
"Email.template.table.name.label": "ad",
"Form.advancedSettings.data.loaded": "Gelişmiş ayarlar verisi yüklendi",
"HeaderNav.link.advancedSettings": "Gelişmiş Ayarlar",
"HeaderNav.link.emailTemplates": "E-posta Şablonları",
"HeaderNav.link.providers": "Sağlayıcıları",
"Plugin.permissions.plugins.description": "{name} eklentisi için izin verilen tüm eylemleri tanımlayın.",
"Plugins.header.description": "Yalnızca bir güzergahla sınırlandırılan işlemler aşağıda listelenmiştir.",
"Plugins.header.title": "İzinler",
"Policies.header.hint": "Uygulamanın eylemlerini veya eklentinin eylemlerini seçin ve bağlı rotayı görüntülemek için dişli çark simgesini tıklayın",
"Policies.header.title": "Gelişmiş Ayarlar",
"PopUpForm.Email.email_templates.inputDescription": "Değişkenleri nasıl kullanacağınızdan emin değilseniz, {link}",
"PopUpForm.Email.link.documentation": "dokümantasyonu kontrol et.",
"PopUpForm.Email.options.from.email.label": "Gönderenin E-posta",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Gönderenin adı",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mesaj",
"PopUpForm.Email.options.object.label": "Konu",
"PopUpForm.Email.options.object.placeholder": "%APP_NAME% için e-posta adresini doğrula",
"PopUpForm.Email.options.response_email.label": "Yanıt e-postası",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Devre dışı bırakıldıysa kullanıcılar bu sağlayıcıyı kullanamaz.",
"PopUpForm.Providers.enabled.label": "Etkinleştirme",
"PopUpForm.Providers.key.label": "Web istemcisi ID",
"PopUpForm.Providers.key.placeholder": "METİN",
"PopUpForm.Providers.redirectURL.front-end.label": "Arayüz uygulamanızın yönlendirme URL'si",
"PopUpForm.Providers.redirectURL.label": "{provider} uygulama ayarlarına ekleyeceğin yönlendirme URLi",
"PopUpForm.Providers.secret.label": "Web istemcisi Secret",
"PopUpForm.Providers.secret.placeholder": "METİN",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "E-posta Şablonlarını Düzenle",
"PopUpForm.header.edit.providers": "Sağlayıcıyı Düzenle",
"Providers.data.loaded": "Sağlayıcılar yüklendi",
"Providers.image": "Görsel",
"Providers.status": "Durum",
"Roles.empty": "Henüz hiç rolün yok.",
"Roles.empty.search": "Aramaya uygun rol bulunmadı.",
"Settings.roles.deleted": "Rol silindi",
"Settings.roles.edited": "Rol düzenlendi",
"Settings.section-label": "Kullanıcılar ve İzinler eklentisi",
"components.Input.error.validation.email": "Bu geçersiz bir e-posta",
"components.Input.error.validation.json": "Bu JSON biçimine uymuyor",
"components.Input.error.validation.max": "Değer çok yüksek.",
"components.Input.error.validation.maxLength": "Değer çok uzun.",
"components.Input.error.validation.min": "Değer çok düşük.",
"components.Input.error.validation.minLength": "Değer çok kısa.",
"components.Input.error.validation.minSupMax": "Üst olamaz",
"components.Input.error.validation.regex": "Değer RegExp'e uymuyor.",
"components.Input.error.validation.required": "Değer gerekli.",
"components.Input.error.validation.unique": "Değer zaten kullanılıyor.",
"notification.success.submit": "Ayarlar güncellendi",
"page.title": "Ayarlar - Roller",
"plugin.description.long": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun. Bu eklenti, kullanıcı grupları arasındaki izinleri yönetmenize izin veren bir ACL stratejisiyle de gelir.",
"plugin.description.short": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun",
"plugin.name": "Roller ve İzinler",
"popUpWarning.button.cancel": "İptal Et",
"popUpWarning.button.confirm": "Onayla",
"popUpWarning.title": "Lütfen onayla",
"popUpWarning.warning.cancel": "Değişiklikleri iptal etmek istediğinden emin misin?"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "Пов'язано з",
"EditForm.inputSelect.description.role": "Підключає нового автентифікованого користувача до вибраної ролі.",
"EditForm.inputSelect.label.role": "Роль за замовчуванням для автентифікованих користувачів",
"EditForm.inputToggle.description.email": "Не дозволяти користувачам створювати кілька аккаунтів з тим самим email, але різним провайдером автентифікації.",
"EditForm.inputToggle.description.email-confirmation": "Якщо увімкнено (ON), щойно зареєстровані користувачі отримують листа для підтверждення.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Куди ви будете перенаправлені після підтвердження свого email.",
"EditForm.inputToggle.description.email-reset-password": "URL-адреса сторінки скидання пароля вашого додатку",
"EditForm.inputToggle.description.sign-up": "Якщо вимкнено (OFF), реєстрація заборонена. Незалежно від використовуваного провайдера більше ніхто не зможе приєднатись.",
"EditForm.inputToggle.label.email": "Один аккаунт на email",
"EditForm.inputToggle.label.email-confirmation": "Увімкнути підтверження email",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL для перенаправлення",
"EditForm.inputToggle.label.email-reset-password": "Сторінка скидання пароля",
"EditForm.inputToggle.label.sign-up": "Увімкнути реєстрацію",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "наприклад: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "наприклад: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Деталі ролі",
"Email.template.data.loaded": "Шаблони електронної пошти завантажено",
"Email.template.email_confirmation": "Підтвердження електронної адреси",
"Email.template.form.edit.label": "Редагувати шаблон",
"Email.template.table.action.label": "дія",
"Email.template.table.icon.label": "іконка",
"Email.template.table.name.label": "назва",
"Form.advancedSettings.data.loaded": "Дані розширених налаштувань завантажено",
"HeaderNav.link.advancedSettings": "Розширені налаштування",
"HeaderNav.link.emailTemplates": "Шаблони листів",
"HeaderNav.link.providers": "Провайдери",
"Plugin.permissions.plugins.description": "Встановіть всі дозволені дії у плаґіні {name}.",
"Plugins.header.description": "Нижче перераховано лише дії, пов'язані з маршрутом.",
"Plugins.header.title": "Дозволи",
"Policies.header.hint": "Виберіть дії вашого додатку або дії плаґіну та натисніть на значок шестірні, щоб відобразити пов'язаний маршрут",
"Policies.header.title": "Розширені налашрування",
"PopUpForm.Email.email_templates.inputDescription": "Якщо ви не впевнені, як використовувати змінні, {link}",
"PopUpForm.Email.link.documentation": "перегляньте документацію.",
"PopUpForm.Email.options.from.email.label": "Email відправника",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Ім'я відправника",
"PopUpForm.Email.options.from.name.placeholder": "Тарас Шевченко",
"PopUpForm.Email.options.message.label": "Повідомлення",
"PopUpForm.Email.options.object.label": "Тема",
"PopUpForm.Email.options.object.placeholder": "Будь ласка, підтвердьте свою електронну адресу для %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email для відповіді",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Якщо вимкнуто, користувачі не зможуть вікористати цей провайдер.",
"PopUpForm.Providers.enabled.label": "Увімкнути",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "URL переадресації для вашего front-end додатку",
"PopUpForm.Providers.redirectURL.label": "URL -адреса для переадресації, щоб додати у ваші конфігурації програми {постачальник}",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Редагування шаблону листів",
"PopUpForm.header.edit.providers": "Редагувати провайдера",
"Providers.data.loaded": "Провайдери завантажено",
"Providers.status": "Статус",
"Roles.empty": "У вас ще немає ролей.",
"Roles.empty.search": "Не знайдено ролей, що відповідають пошуку.",
"Settings.roles.deleted": "Роль видалено",
"Settings.roles.edited": "Роль редаговано",
"Settings.section-label": "Плаґін користувачів та дозволів",
"components.Input.error.validation.email": "Це неправильна електронна адреса",
"components.Input.error.validation.json": "Це не відповідає формату JSON",
"components.Input.error.validation.max": "Значення занадто велике.",
"components.Input.error.validation.maxLength": "Значення занадто довге.",
"components.Input.error.validation.min": "Значення занадто низьке.",
"components.Input.error.validation.minLength": "Значення занадто коротке.",
"components.Input.error.validation.minSupMax": "Не може бути більшим",
"components.Input.error.validation.regex": "Значення не відповідає регулярному виразу.",
"components.Input.error.validation.required": "Це значення є обов’язковим.",
"components.Input.error.validation.unique": "Це значення вже використовується.",
"notification.success.submit": "Налаштування оновлено",
"page.title": "Налаштування - Ролі",
"plugin.description.long": "Захистіть API за допомогою процесу аутентифікації на основі JWT. Цей плаґін також включає можливості ACL, які дозволяють керувати дозволами між групами користувачів.",
"plugin.description.short": "Захистіть API за допомогою процесу аутентифікації на основі JWT",
"plugin.name": "Плаґін користувачів та дозволів",
"popUpWarning.button.cancel": "Скасувати",
"popUpWarning.button.confirm": "Підтвердити",
"popUpWarning.title": "Будь ласка, підтвердіть",
"popUpWarning.warning.cancel": "Ви впевнені, що хочете скасувати свої зміни?"
}

View File

@@ -0,0 +1,46 @@
{
"BoundRoute.title": "Đến tới",
"EditForm.inputSelect.description.role": "Đính kèm người dùng mới đã được xác thực vào quyền được chọn.",
"EditForm.inputSelect.label.role": "Quyền mặc định cho các người dùng đã được chứng thực",
"EditForm.inputToggle.description.email": "Không cho phép người dùng tạo nhiều tài khoản có cùng địa chỉ email với nhiều nhà cung cấp chứng thực.",
"EditForm.inputToggle.description.email-confirmation": "Khi được kích hoạt (ON), người dùng đăng ký mới nhận được một email xác nhận.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Sau khi xác nhận email của bạn, chọn nơi bạn sẽ được đưa về.",
"EditForm.inputToggle.description.email-reset-password": "URL của trang lấy lại mật khẩu của ứng dụng của bạn",
"EditForm.inputToggle.description.sign-up": "Khi không kích hoạt (OFF), quá trình đăng ký bị cấm. Không ai có thể đăng ký thêm dù dùng bất kỳ nhà cung cấp nào.",
"EditForm.inputToggle.label.email": "Một tài khoản trên một địa chỉ email",
"EditForm.inputToggle.label.email-confirmation": "Kích hoạt email xác nhận",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL đưa về",
"EditForm.inputToggle.label.email-reset-password": "Trang lấy lại mật khẩu",
"EditForm.inputToggle.label.sign-up": "Kích hoạt đăng ký",
"HeaderNav.link.advancedSettings": "Cài đặt nâng cao",
"HeaderNav.link.emailTemplates": "Mẫu email",
"HeaderNav.link.providers": "Các nhà cung cấp",
"Plugin.permissions.plugins.description": "Định nghĩa tất cả hành động được phép cho {name} plugin.",
"Plugins.header.description": "Chỉ các hành động đến bởi một đường dẫn được liệt kê bên dưới.",
"Plugins.header.title": "Các Quyền",
"Policies.header.hint": "Chọn các hành động của ứng dựng hoặc hành động của plugin và nhấn vào biểu tượng bánh răng để hiển thị đường đến",
"Policies.header.title": "Các cài đặt nâng cao",
"PopUpForm.Email.email_templates.inputDescription": "Nếu bạn không chắc sử dụng các biến như thế nào, {link}",
"PopUpForm.Email.options.from.email.label": "Email người gửi",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Tên người gửi",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Thông điệp",
"PopUpForm.Email.options.object.label": "Chủ đề",
"PopUpForm.Email.options.response_email.label": "Email phản hồi",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Nếu không kích hoạt, người dùng sẽ không thể dùng nhà cung cấp này.",
"PopUpForm.Providers.enabled.label": "Kích hoạt",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "VĂN BẢN",
"PopUpForm.Providers.redirectURL.front-end.label": "URL chuyển tiếp đến ứng dụng bên ngoài của bạn",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "VĂN BẢN",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Sửa Các Mẫu Email",
"notification.success.submit": "Các cấu hình đã được cập nhật",
"plugin.description.long": "Bảo vệ API của bạn với quá trình chứng thực đầy đủ dựa trên JWT. Plugin này cũng kèm với chiến lược ACL cho phép bạn quản lý quyền giữa các nhóm người dùng.",
"plugin.description.short": "Bảo vệ API của bạn với quá trình chứng thực đầy đủ dựa trên JWT",
"plugin.name": "Vai trò và Quyền"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "绑定路由到",
"EditForm.inputSelect.description.role": "新验证身份的用户将被赋予所选角色。",
"EditForm.inputSelect.label.role": "认证用户的默认角色",
"EditForm.inputToggle.description.email": "不允许用户使用不同的认证提供商但相同的电子邮件地址来创建多个账户。",
"EditForm.inputToggle.description.email-confirmation": "启用(开)后,新注册的用户会收到一封确认电子邮件。",
"EditForm.inputToggle.description.email-confirmation-redirection": "确认您的电子邮件后,选择将您重定向到的位置。",
"EditForm.inputToggle.description.email-reset-password": "应用程序的重置密码页面的网址",
"EditForm.inputToggle.description.sign-up": "当禁用(关)时,注册过程将被禁止。任何人无论使用任何的供应商都不可以订阅。",
"EditForm.inputToggle.label.email": "每个电子邮件地址对应一个账户",
"EditForm.inputToggle.label.email-confirmation": "启用电子邮件确认",
"EditForm.inputToggle.label.email-confirmation-redirection": "重定向网址",
"EditForm.inputToggle.label.email-reset-password": "重置密码页面网址",
"EditForm.inputToggle.label.sign-up": "启用注册",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "例如: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "例如: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "角色详情",
"Email.template.data.loaded": "电子邮件模板已加载",
"Email.template.email_confirmation": "邮箱地址确认",
"Email.template.form.edit.label": "编辑模板",
"Email.template.table.action.label": "操作",
"Email.template.table.icon.label": "图标",
"Email.template.table.name.label": "名称",
"Form.advancedSettings.data.loaded": "高级设置数据已加载",
"HeaderNav.link.advancedSettings": "高级设置",
"HeaderNav.link.emailTemplates": "电子邮件模板",
"HeaderNav.link.providers": "提供商",
"Plugin.permissions.plugins.description": "定义 {name} 插件所有允许的操作。",
"Plugins.header.description": "下面只列出路由绑定的操作。",
"Plugins.header.title": "权限",
"Policies.header.hint": "选择应用程序或插件对应的操作,然后点击齿轮图标显示绑定的路由",
"Policies.header.title": "高级设置",
"PopUpForm.Email.email_templates.inputDescription": "如果你不确定如何使用变量, {link}",
"PopUpForm.Email.link.documentation": "查看我们的文档",
"PopUpForm.Email.options.from.email.label": "发件人地址",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "发件人名称",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "消息",
"PopUpForm.Email.options.object.label": "主题",
"PopUpForm.Email.options.object.placeholder": "请为%APP_NAME%确认邮箱地址",
"PopUpForm.Email.options.response_email.label": "回复邮件",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "如果禁用,用户将无法使用此供应商。",
"PopUpForm.Providers.enabled.label": "启用",
"PopUpForm.Providers.key.label": "客户端 ID",
"PopUpForm.Providers.key.placeholder": "文本",
"PopUpForm.Providers.redirectURL.front-end.label": "重定向网址",
"PopUpForm.Providers.redirectURL.label": "添加到{provider}应用配置的跳转网址",
"PopUpForm.Providers.secret.label": "客户端秘钥",
"PopUpForm.Providers.secret.placeholder": "文本",
"PopUpForm.Providers.subdomain.label": "主机URI子域名",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "编辑电子邮件模版",
"PopUpForm.header.edit.providers": "编辑提供商",
"Providers.data.loaded": "提供商已加载",
"Providers.status": "状态",
"Roles.empty": "您还没有任何角色。",
"Roles.empty.search": "没有与搜索相匹配的角色。",
"Settings.roles.deleted": "角色已被删除",
"Settings.roles.edited": "角色编辑完成",
"Settings.section-label": "用户及权限插件",
"components.Input.error.validation.email": "这是一个无效的电子邮件",
"components.Input.error.validation.json": "这不符合JSON格式",
"components.Input.error.validation.max": "值过高。",
"components.Input.error.validation.maxLength": "值过长。",
"components.Input.error.validation.min": "值太低。",
"components.Input.error.validation.minLength": "值太短。",
"components.Input.error.validation.minSupMax": "不能超过上限",
"components.Input.error.validation.regex": "该值不符合正则表达式。",
"components.Input.error.validation.required": "该值为必填项。",
"components.Input.error.validation.unique": "该值已被使用。",
"notification.success.submit": "设置已被更新",
"page.title": "设置 - 角色",
"plugin.description.long": "使用基于 JWT 的完整身份验证过程来保护 API。这个插件还有一个 ACL 策略,允许你管理用户组之间的权限。",
"plugin.description.short": "使用基于 JWT 的完整身份验证过程保护 API",
"plugin.name": "用户及权限插件",
"popUpWarning.button.cancel": "取消",
"popUpWarning.button.confirm": "确认",
"popUpWarning.title": "请确认",
"popUpWarning.warning.cancel": "你确定你要取消你的修改?"
}

View File

@@ -0,0 +1,82 @@
{
"BoundRoute.title": "綁定路徑到",
"EditForm.inputSelect.description.role": "將新的驗證使用者加入此身份。",
"EditForm.inputSelect.label.role": "驗證使用者預設身份",
"EditForm.inputToggle.description.email": "禁止使用者使用同一個電子郵件地址 + 不同的驗證方式註冊多個帳號",
"EditForm.inputToggle.description.email-confirmation": "當啟用後,新註冊的使用者將會收到一封認證郵件。",
"EditForm.inputToggle.description.email-confirmation-redirection": "認證完後後,使用者被重新導向的網址。",
"EditForm.inputToggle.description.email-reset-password": "您的應用程式的重設密碼頁面的網址",
"EditForm.inputToggle.description.sign-up": "當停用後,不論使用任何驗證方式使用者將無法註冊。",
"EditForm.inputToggle.label.email": "電子郵件地址單一帳號限制",
"EditForm.inputToggle.label.email-confirmation": "啟用電子郵件地址驗證",
"EditForm.inputToggle.label.email-confirmation-redirection": "重新導向網址",
"EditForm.inputToggle.label.email-reset-password": "密碼重設頁面",
"EditForm.inputToggle.label.sign-up": "啟用註冊",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "例如https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "例如https://yourfrontend.com/reset-password",
"EditPage.form.roles": "角色詳細資訊",
"Email.template.data.loaded": "已載入電子郵件範本",
"Email.template.email_confirmation": "電子郵件地址確認",
"Email.template.form.edit.label": "編輯範本",
"Email.template.table.action.label": "操作",
"Email.template.table.icon.label": "圖示",
"Email.template.table.name.label": "名稱",
"Form.advancedSettings.data.loaded": "已載入進階設定資料",
"HeaderNav.link.advancedSettings": "進階設定",
"HeaderNav.link.emailTemplates": "郵件範本",
"HeaderNav.link.providers": "驗證方式",
"Plugin.permissions.plugins.description": "為 {name} 擴充功能定義所有可用的操作",
"Plugins.header.description": "只有綁定路徑的操作會顯示在下方",
"Plugins.header.title": "權限",
"Policies.header.hint": "選取應用程式或擴充功能的操作然後點擊齒輪圖示以顯示綁定路徑",
"Policies.header.title": "進階設定",
"PopUpForm.Email.email_templates.inputDescription": "如果您不確定要怎麼使用變數,請 {link}",
"PopUpForm.Email.link.documentation": "查閱我們的說明文件。",
"PopUpForm.Email.options.from.email.label": "寄件人地址",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "寄件人名稱",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "訊息",
"PopUpForm.Email.options.object.label": "主旨",
"PopUpForm.Email.options.object.placeholder": "請驗證 %APP_NAME% 的電子郵件地址",
"PopUpForm.Email.options.response_email.label": "回覆地址",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "如果停用,使用者將無法使用這個驗證方式",
"PopUpForm.Providers.enabled.label": "啟用",
"PopUpForm.Providers.key.label": "客戶端 ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "您應用程式的前端頁面網址",
"PopUpForm.Providers.redirectURL.label": "The redirect URL to add in your {provider} application configurations",
"PopUpForm.Providers.secret.label": "客戶端密鑰",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (子網域)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "編輯郵件範本",
"PopUpForm.header.edit.providers": "編輯供應者",
"Providers.data.loaded": "已載入供應者",
"Providers.status": "狀態",
"Roles.empty": "您目前沒有任何角色。",
"Roles.empty.search": "沒有符合搜尋的角色。",
"Settings.roles.deleted": "已刪除角色",
"Settings.roles.edited": "已編輯角色",
"Settings.section-label": "使用者與權限外掛程式",
"components.Input.error.validation.email": "此電子郵件地址無效",
"components.Input.error.validation.json": "不符合 JSON 格式",
"components.Input.error.validation.max": "數值過高。",
"components.Input.error.validation.maxLength": "數值過長。",
"components.Input.error.validation.min": "數值過低。",
"components.Input.error.validation.minLength": "數值過短。",
"components.Input.error.validation.minSupMax": "Can't be superior",
"components.Input.error.validation.regex": "數值與 regex 不符。",
"components.Input.error.validation.required": "此數值為必填。",
"components.Input.error.validation.unique": "此值已被使用。",
"notification.success.submit": "設定已更新",
"page.title": "設定 - 角色",
"plugin.description.long": "使用 JWT 認證保護您的 API。這個擴充功能也使用 ACL 來讓你管理不同群組使用者的權限。",
"plugin.description.short": "使用 JWT 認證保護您的 API",
"plugin.name": "身份與權限",
"popUpWarning.button.cancel": "取消",
"popUpWarning.button.confirm": "確認",
"popUpWarning.title": "請確認",
"popUpWarning.warning.cancel": "您確定要取消變更嗎?"
}

View File

@@ -0,0 +1,25 @@
import isEmpty from 'lodash/isEmpty';
const cleanPermissions = (permissions) =>
Object.keys(permissions).reduce((acc, current) => {
const currentPermission = permissions[current].controllers;
const cleanedControllers = Object.keys(currentPermission).reduce((acc2, curr) => {
if (isEmpty(currentPermission[curr])) {
return acc2;
}
acc2[curr] = currentPermission[curr];
return acc2;
}, {});
if (isEmpty(cleanedControllers)) {
return acc;
}
acc[current] = { controllers: cleanedControllers };
return acc;
}, {});
export default cleanPermissions;

View File

@@ -0,0 +1,26 @@
import upperFirst from 'lodash/upperFirst';
function formatPluginName(pluginSlug) {
switch (pluginSlug) {
case 'application':
return 'Application';
case 'plugin::content-manager':
return 'Content manager';
case 'plugin::content-type-builder':
return 'Content types builder';
case 'plugin::documentation':
return 'Documentation';
case 'plugin::email':
return 'Email';
case 'plugin::i18n':
return 'i18n';
case 'plugin::upload':
return 'Upload';
case 'plugin::users-permissions':
return 'Users-permissions';
default:
return upperFirst(pluginSlug.replace('api::', '').replace('plugin::', ''));
}
}
export default formatPluginName;

View File

@@ -0,0 +1,8 @@
const formatPolicies = (policies) =>
policies.reduce((acc, current) => {
acc.push({ label: current, value: current });
return acc;
}, []);
export default formatPolicies;

View File

@@ -0,0 +1,5 @@
import pluginId from '../pluginId';
const getTrad = (id) => `${pluginId}.${id}`;
export default getTrad;

View File

@@ -0,0 +1,3 @@
export { default as cleanPermissions } from './cleanPermissions';
export { default as formatPolicies } from './formatPolicies';
export { default as getTrad } from './getTrad';

View File

@@ -0,0 +1,13 @@
const prefixPluginTranslations = (trad, pluginId) => {
if (!pluginId) {
throw new TypeError("pluginId can't be empty");
}
return Object.keys(trad).reduce((acc, current) => {
acc[`${pluginId}.${current}`] = trad[current];
return acc;
}, {});
};
export { prefixPluginTranslations };

View File

@@ -0,0 +1,49 @@
'use strict';
const getMethodColor = (verb)=>{
switch(verb){
case 'POST':
{
return {
text: 'success600',
border: 'success200',
background: 'success100'
};
}
case 'GET':
{
return {
text: 'secondary600',
border: 'secondary200',
background: 'secondary100'
};
}
case 'PUT':
{
return {
text: 'warning600',
border: 'warning200',
background: 'warning100'
};
}
case 'DELETE':
{
return {
text: 'danger600',
border: 'danger200',
background: 'danger100'
};
}
default:
{
return {
text: 'neutral600',
border: 'neutral200',
background: 'neutral100'
};
}
}
};
module.exports = getMethodColor;
//# sourceMappingURL=getMethodColor.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getMethodColor.js","sources":["../../../../admin/src/components/BoundRoute/getMethodColor.js"],"sourcesContent":["const getMethodColor = (verb) => {\n switch (verb) {\n case 'POST': {\n return {\n text: 'success600',\n border: 'success200',\n background: 'success100',\n };\n }\n case 'GET': {\n return {\n text: 'secondary600',\n border: 'secondary200',\n background: 'secondary100',\n };\n }\n case 'PUT': {\n return {\n text: 'warning600',\n border: 'warning200',\n background: 'warning100',\n };\n }\n case 'DELETE': {\n return {\n text: 'danger600',\n border: 'danger200',\n background: 'danger100',\n };\n }\n default: {\n return {\n text: 'neutral600',\n border: 'neutral200',\n background: 'neutral100',\n };\n }\n }\n};\n\nexport default getMethodColor;\n"],"names":["getMethodColor","verb","text","border","background"],"mappings":";;AAAA,MAAMA,iBAAiB,CAACC,IAAAA,GAAAA;IACtB,OAAQA,IAAAA;QACN,KAAK,MAAA;AAAQ,YAAA;gBACX,OAAO;oBACLC,IAAM,EAAA,YAAA;oBACNC,MAAQ,EAAA,YAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;QACA,KAAK,KAAA;AAAO,YAAA;gBACV,OAAO;oBACLF,IAAM,EAAA,cAAA;oBACNC,MAAQ,EAAA,cAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;QACA,KAAK,KAAA;AAAO,YAAA;gBACV,OAAO;oBACLF,IAAM,EAAA,YAAA;oBACNC,MAAQ,EAAA,YAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;QACA,KAAK,QAAA;AAAU,YAAA;gBACb,OAAO;oBACLF,IAAM,EAAA,WAAA;oBACNC,MAAQ,EAAA,WAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;AACA,QAAA;AAAS,YAAA;gBACP,OAAO;oBACLF,IAAM,EAAA,YAAA;oBACNC,MAAQ,EAAA,YAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;AACF;AACF;;;;"}

View File

@@ -0,0 +1,47 @@
const getMethodColor = (verb)=>{
switch(verb){
case 'POST':
{
return {
text: 'success600',
border: 'success200',
background: 'success100'
};
}
case 'GET':
{
return {
text: 'secondary600',
border: 'secondary200',
background: 'secondary100'
};
}
case 'PUT':
{
return {
text: 'warning600',
border: 'warning200',
background: 'warning100'
};
}
case 'DELETE':
{
return {
text: 'danger600',
border: 'danger200',
background: 'danger100'
};
}
default:
{
return {
text: 'neutral600',
border: 'neutral200',
background: 'neutral100'
};
}
}
};
export { getMethodColor as default };
//# sourceMappingURL=getMethodColor.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getMethodColor.mjs","sources":["../../../../admin/src/components/BoundRoute/getMethodColor.js"],"sourcesContent":["const getMethodColor = (verb) => {\n switch (verb) {\n case 'POST': {\n return {\n text: 'success600',\n border: 'success200',\n background: 'success100',\n };\n }\n case 'GET': {\n return {\n text: 'secondary600',\n border: 'secondary200',\n background: 'secondary100',\n };\n }\n case 'PUT': {\n return {\n text: 'warning600',\n border: 'warning200',\n background: 'warning100',\n };\n }\n case 'DELETE': {\n return {\n text: 'danger600',\n border: 'danger200',\n background: 'danger100',\n };\n }\n default: {\n return {\n text: 'neutral600',\n border: 'neutral200',\n background: 'neutral100',\n };\n }\n }\n};\n\nexport default getMethodColor;\n"],"names":["getMethodColor","verb","text","border","background"],"mappings":"AAAA,MAAMA,iBAAiB,CAACC,IAAAA,GAAAA;IACtB,OAAQA,IAAAA;QACN,KAAK,MAAA;AAAQ,YAAA;gBACX,OAAO;oBACLC,IAAM,EAAA,YAAA;oBACNC,MAAQ,EAAA,YAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;QACA,KAAK,KAAA;AAAO,YAAA;gBACV,OAAO;oBACLF,IAAM,EAAA,cAAA;oBACNC,MAAQ,EAAA,cAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;QACA,KAAK,KAAA;AAAO,YAAA;gBACV,OAAO;oBACLF,IAAM,EAAA,YAAA;oBACNC,MAAQ,EAAA,YAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;QACA,KAAK,QAAA;AAAU,YAAA;gBACb,OAAO;oBACLF,IAAM,EAAA,WAAA;oBACNC,MAAQ,EAAA,WAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;AACA,QAAA;AAAS,YAAA;gBACP,OAAO;oBACLF,IAAM,EAAA,YAAA;oBACNC,MAAQ,EAAA,YAAA;oBACRC,UAAY,EAAA;AACd,iBAAA;AACF;AACF;AACF;;;;"}

View File

@@ -0,0 +1,98 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
require('react');
var designSystem = require('@strapi/design-system');
var map = require('lodash/map');
var tail = require('lodash/tail');
var PropTypes = require('prop-types');
var reactIntl = require('react-intl');
var styledComponents = require('styled-components');
var getMethodColor = require('./getMethodColor.js');
const MethodBox = styledComponents.styled(designSystem.Box)`
margin: -1px;
border-radius: ${({ theme })=>theme.spaces[1]} 0 0 ${({ theme })=>theme.spaces[1]};
`;
function BoundRoute({ route }) {
const { formatMessage } = reactIntl.useIntl();
const { method, handler: title, path } = route;
const formattedRoute = path ? tail(path.split('/')) : [];
const [controller = '', action = ''] = title ? title.split('.') : [];
const colors = getMethodColor(route.method);
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
alignItems: "stretch",
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Typography, {
variant: "delta",
tag: "h3",
children: [
formatMessage({
id: 'users-permissions.BoundRoute.title',
defaultMessage: 'Bound route to'
}),
" ",
/*#__PURE__*/ jsxRuntime.jsx("span", {
children: controller
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Typography, {
variant: "delta",
textColor: "primary600",
children: [
".",
action
]
})
]
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
hasRadius: true,
background: "neutral0",
borderColor: "neutral200",
gap: 0,
children: [
/*#__PURE__*/ jsxRuntime.jsx(MethodBox, {
background: colors.background,
borderColor: colors.border,
padding: 2,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
fontWeight: "bold",
textColor: colors.text,
children: method
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
paddingLeft: 2,
paddingRight: 2,
children: map(formattedRoute, (value)=>/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Typography, {
textColor: value.includes(':') ? 'neutral600' : 'neutral900',
children: [
"/",
value
]
}, value))
})
]
})
]
});
}
BoundRoute.defaultProps = {
route: {
handler: 'Nocontroller.error',
method: 'GET',
path: '/there-is-no-path'
}
};
BoundRoute.propTypes = {
route: PropTypes.shape({
handler: PropTypes.string,
method: PropTypes.string,
path: PropTypes.string
})
};
module.exports = BoundRoute;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../../../../admin/src/components/BoundRoute/index.jsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Flex, Typography } from '@strapi/design-system';\nimport map from 'lodash/map';\nimport tail from 'lodash/tail';\nimport PropTypes from 'prop-types';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport getMethodColor from './getMethodColor';\n\nconst MethodBox = styled(Box)`\n margin: -1px;\n border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};\n`;\n\nfunction BoundRoute({ route }) {\n const { formatMessage } = useIntl();\n\n const { method, handler: title, path } = route;\n const formattedRoute = path ? tail(path.split('/')) : [];\n const [controller = '', action = ''] = title ? title.split('.') : [];\n const colors = getMethodColor(route.method);\n\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" gap={2}>\n <Typography variant=\"delta\" tag=\"h3\">\n {formatMessage({\n id: 'users-permissions.BoundRoute.title',\n defaultMessage: 'Bound route to',\n })}\n &nbsp;\n <span>{controller}</span>\n <Typography variant=\"delta\" textColor=\"primary600\">\n .{action}\n </Typography>\n </Typography>\n <Flex hasRadius background=\"neutral0\" borderColor=\"neutral200\" gap={0}>\n <MethodBox background={colors.background} borderColor={colors.border} padding={2}>\n <Typography fontWeight=\"bold\" textColor={colors.text}>\n {method}\n </Typography>\n </MethodBox>\n <Box paddingLeft={2} paddingRight={2}>\n {map(formattedRoute, (value) => (\n <Typography key={value} textColor={value.includes(':') ? 'neutral600' : 'neutral900'}>\n /{value}\n </Typography>\n ))}\n </Box>\n </Flex>\n </Flex>\n );\n}\n\nBoundRoute.defaultProps = {\n route: {\n handler: 'Nocontroller.error',\n method: 'GET',\n path: '/there-is-no-path',\n },\n};\n\nBoundRoute.propTypes = {\n route: PropTypes.shape({\n handler: PropTypes.string,\n method: PropTypes.string,\n path: PropTypes.string,\n }),\n};\n\nexport default BoundRoute;\n"],"names":["MethodBox","styled","Box","theme","spaces","BoundRoute","route","formatMessage","useIntl","method","handler","title","path","formattedRoute","tail","split","controller","action","colors","getMethodColor","_jsxs","Flex","direction","alignItems","gap","Typography","variant","tag","id","defaultMessage","_jsx","span","textColor","hasRadius","background","borderColor","border","padding","fontWeight","text","paddingLeft","paddingRight","map","value","includes","defaultProps","propTypes","PropTypes","shape","string"],"mappings":";;;;;;;;;;;;AAWA,MAAMA,SAAAA,GAAYC,uBAAOC,CAAAA,gBAAAA,CAAI;;iBAEZ,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAAC,CAAE,CAAA,CAAC,KAAK,EAAE,CAAC,EAAED,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAAC,CAAA,CAAE,CAAC;AACxF,CAAC;AAED,SAASC,UAAAA,CAAW,EAAEC,KAAK,EAAE,EAAA;IAC3B,MAAM,EAAEC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;IAE1B,MAAM,EAAEC,MAAM,EAAEC,OAAAA,EAASC,KAAK,EAAEC,IAAI,EAAE,GAAGN,KAAAA;AACzC,IAAA,MAAMO,iBAAiBD,IAAOE,GAAAA,IAAAA,CAAKF,KAAKG,KAAK,CAAC,QAAQ,EAAE;AACxD,IAAA,MAAM,CAACC,UAAAA,GAAa,EAAE,EAAEC,MAAS,GAAA,EAAE,CAAC,GAAGN,KAAQA,GAAAA,KAAAA,CAAMI,KAAK,CAAC,OAAO,EAAE;IACpE,MAAMG,MAAAA,GAASC,cAAeb,CAAAA,KAAAA,CAAMG,MAAM,CAAA;AAE1C,IAAA,qBACEW,eAACC,CAAAA,iBAAAA,EAAAA;QAAKC,SAAU,EAAA,QAAA;QAASC,UAAW,EAAA,SAAA;QAAUC,GAAK,EAAA,CAAA;;0BACjDJ,eAACK,CAAAA,uBAAAA,EAAAA;gBAAWC,OAAQ,EAAA,OAAA;gBAAQC,GAAI,EAAA,IAAA;;oBAC7BpB,aAAc,CAAA;wBACbqB,EAAI,EAAA,oCAAA;wBACJC,cAAgB,EAAA;AAClB,qBAAA,CAAA;AAAG,oBAAA,GAAA;kCAEHC,cAACC,CAAAA,MAAAA,EAAAA;AAAMf,wBAAAA,QAAAA,EAAAA;;kCACPI,eAACK,CAAAA,uBAAAA,EAAAA;wBAAWC,OAAQ,EAAA,OAAA;wBAAQM,SAAU,EAAA,YAAA;;AAAa,4BAAA,GAAA;AAC/Cf,4BAAAA;;;;;0BAGNG,eAACC,CAAAA,iBAAAA,EAAAA;gBAAKY,SAAS,EAAA,IAAA;gBAACC,UAAW,EAAA,UAAA;gBAAWC,WAAY,EAAA,YAAA;gBAAaX,GAAK,EAAA,CAAA;;kCAClEM,cAAC9B,CAAAA,SAAAA,EAAAA;AAAUkC,wBAAAA,UAAAA,EAAYhB,OAAOgB,UAAU;AAAEC,wBAAAA,WAAAA,EAAajB,OAAOkB,MAAM;wBAAEC,OAAS,EAAA,CAAA;AAC7E,wBAAA,QAAA,gBAAAP,cAACL,CAAAA,uBAAAA,EAAAA;4BAAWa,UAAW,EAAA,MAAA;AAAON,4BAAAA,SAAAA,EAAWd,OAAOqB,IAAI;AACjD9B,4BAAAA,QAAAA,EAAAA;;;kCAGLqB,cAAC5B,CAAAA,gBAAAA,EAAAA;wBAAIsC,WAAa,EAAA,CAAA;wBAAGC,YAAc,EAAA,CAAA;kCAChCC,GAAI7B,CAAAA,cAAAA,EAAgB,CAAC8B,KAAAA,iBACpBvB,eAACK,CAAAA,uBAAAA,EAAAA;AAAuBO,gCAAAA,SAAAA,EAAWW,KAAMC,CAAAA,QAAQ,CAAC,GAAA,CAAA,GAAO,YAAe,GAAA,YAAA;;AAAc,oCAAA,GAAA;AAClFD,oCAAAA;;AADaA,6BAAAA,EAAAA,KAAAA,CAAAA;;;;;;AAQ7B;AAEAtC,UAAAA,CAAWwC,YAAY,GAAG;IACxBvC,KAAO,EAAA;QACLI,OAAS,EAAA,oBAAA;QACTD,MAAQ,EAAA,KAAA;QACRG,IAAM,EAAA;AACR;AACF,CAAA;AAEAP,UAAAA,CAAWyC,SAAS,GAAG;IACrBxC,KAAOyC,EAAAA,SAAAA,CAAUC,KAAK,CAAC;AACrBtC,QAAAA,OAAAA,EAASqC,UAAUE,MAAM;AACzBxC,QAAAA,MAAAA,EAAQsC,UAAUE,MAAM;AACxBrC,QAAAA,IAAAA,EAAMmC,UAAUE;AAClB,KAAA;AACF,CAAA;;;;"}

View File

@@ -0,0 +1,96 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import 'react';
import { Box, Flex, Typography } from '@strapi/design-system';
import map from 'lodash/map';
import tail from 'lodash/tail';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { styled } from 'styled-components';
import getMethodColor from './getMethodColor.mjs';
const MethodBox = styled(Box)`
margin: -1px;
border-radius: ${({ theme })=>theme.spaces[1]} 0 0 ${({ theme })=>theme.spaces[1]};
`;
function BoundRoute({ route }) {
const { formatMessage } = useIntl();
const { method, handler: title, path } = route;
const formattedRoute = path ? tail(path.split('/')) : [];
const [controller = '', action = ''] = title ? title.split('.') : [];
const colors = getMethodColor(route.method);
return /*#__PURE__*/ jsxs(Flex, {
direction: "column",
alignItems: "stretch",
gap: 2,
children: [
/*#__PURE__*/ jsxs(Typography, {
variant: "delta",
tag: "h3",
children: [
formatMessage({
id: 'users-permissions.BoundRoute.title',
defaultMessage: 'Bound route to'
}),
" ",
/*#__PURE__*/ jsx("span", {
children: controller
}),
/*#__PURE__*/ jsxs(Typography, {
variant: "delta",
textColor: "primary600",
children: [
".",
action
]
})
]
}),
/*#__PURE__*/ jsxs(Flex, {
hasRadius: true,
background: "neutral0",
borderColor: "neutral200",
gap: 0,
children: [
/*#__PURE__*/ jsx(MethodBox, {
background: colors.background,
borderColor: colors.border,
padding: 2,
children: /*#__PURE__*/ jsx(Typography, {
fontWeight: "bold",
textColor: colors.text,
children: method
})
}),
/*#__PURE__*/ jsx(Box, {
paddingLeft: 2,
paddingRight: 2,
children: map(formattedRoute, (value)=>/*#__PURE__*/ jsxs(Typography, {
textColor: value.includes(':') ? 'neutral600' : 'neutral900',
children: [
"/",
value
]
}, value))
})
]
})
]
});
}
BoundRoute.defaultProps = {
route: {
handler: 'Nocontroller.error',
method: 'GET',
path: '/there-is-no-path'
}
};
BoundRoute.propTypes = {
route: PropTypes.shape({
handler: PropTypes.string,
method: PropTypes.string,
path: PropTypes.string
})
};
export { BoundRoute as default };
//# sourceMappingURL=index.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":["../../../../admin/src/components/BoundRoute/index.jsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Flex, Typography } from '@strapi/design-system';\nimport map from 'lodash/map';\nimport tail from 'lodash/tail';\nimport PropTypes from 'prop-types';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport getMethodColor from './getMethodColor';\n\nconst MethodBox = styled(Box)`\n margin: -1px;\n border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};\n`;\n\nfunction BoundRoute({ route }) {\n const { formatMessage } = useIntl();\n\n const { method, handler: title, path } = route;\n const formattedRoute = path ? tail(path.split('/')) : [];\n const [controller = '', action = ''] = title ? title.split('.') : [];\n const colors = getMethodColor(route.method);\n\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" gap={2}>\n <Typography variant=\"delta\" tag=\"h3\">\n {formatMessage({\n id: 'users-permissions.BoundRoute.title',\n defaultMessage: 'Bound route to',\n })}\n &nbsp;\n <span>{controller}</span>\n <Typography variant=\"delta\" textColor=\"primary600\">\n .{action}\n </Typography>\n </Typography>\n <Flex hasRadius background=\"neutral0\" borderColor=\"neutral200\" gap={0}>\n <MethodBox background={colors.background} borderColor={colors.border} padding={2}>\n <Typography fontWeight=\"bold\" textColor={colors.text}>\n {method}\n </Typography>\n </MethodBox>\n <Box paddingLeft={2} paddingRight={2}>\n {map(formattedRoute, (value) => (\n <Typography key={value} textColor={value.includes(':') ? 'neutral600' : 'neutral900'}>\n /{value}\n </Typography>\n ))}\n </Box>\n </Flex>\n </Flex>\n );\n}\n\nBoundRoute.defaultProps = {\n route: {\n handler: 'Nocontroller.error',\n method: 'GET',\n path: '/there-is-no-path',\n },\n};\n\nBoundRoute.propTypes = {\n route: PropTypes.shape({\n handler: PropTypes.string,\n method: PropTypes.string,\n path: PropTypes.string,\n }),\n};\n\nexport default BoundRoute;\n"],"names":["MethodBox","styled","Box","theme","spaces","BoundRoute","route","formatMessage","useIntl","method","handler","title","path","formattedRoute","tail","split","controller","action","colors","getMethodColor","_jsxs","Flex","direction","alignItems","gap","Typography","variant","tag","id","defaultMessage","_jsx","span","textColor","hasRadius","background","borderColor","border","padding","fontWeight","text","paddingLeft","paddingRight","map","value","includes","defaultProps","propTypes","PropTypes","shape","string"],"mappings":";;;;;;;;;;AAWA,MAAMA,SAAAA,GAAYC,MAAOC,CAAAA,GAAAA,CAAI;;iBAEZ,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAAC,CAAE,CAAA,CAAC,KAAK,EAAE,CAAC,EAAED,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAAC,CAAA,CAAE,CAAC;AACxF,CAAC;AAED,SAASC,UAAAA,CAAW,EAAEC,KAAK,EAAE,EAAA;IAC3B,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;IAE1B,MAAM,EAAEC,MAAM,EAAEC,OAAAA,EAASC,KAAK,EAAEC,IAAI,EAAE,GAAGN,KAAAA;AACzC,IAAA,MAAMO,iBAAiBD,IAAOE,GAAAA,IAAAA,CAAKF,KAAKG,KAAK,CAAC,QAAQ,EAAE;AACxD,IAAA,MAAM,CAACC,UAAAA,GAAa,EAAE,EAAEC,MAAS,GAAA,EAAE,CAAC,GAAGN,KAAQA,GAAAA,KAAAA,CAAMI,KAAK,CAAC,OAAO,EAAE;IACpE,MAAMG,MAAAA,GAASC,cAAeb,CAAAA,KAAAA,CAAMG,MAAM,CAAA;AAE1C,IAAA,qBACEW,IAACC,CAAAA,IAAAA,EAAAA;QAAKC,SAAU,EAAA,QAAA;QAASC,UAAW,EAAA,SAAA;QAAUC,GAAK,EAAA,CAAA;;0BACjDJ,IAACK,CAAAA,UAAAA,EAAAA;gBAAWC,OAAQ,EAAA,OAAA;gBAAQC,GAAI,EAAA,IAAA;;oBAC7BpB,aAAc,CAAA;wBACbqB,EAAI,EAAA,oCAAA;wBACJC,cAAgB,EAAA;AAClB,qBAAA,CAAA;AAAG,oBAAA,GAAA;kCAEHC,GAACC,CAAAA,MAAAA,EAAAA;AAAMf,wBAAAA,QAAAA,EAAAA;;kCACPI,IAACK,CAAAA,UAAAA,EAAAA;wBAAWC,OAAQ,EAAA,OAAA;wBAAQM,SAAU,EAAA,YAAA;;AAAa,4BAAA,GAAA;AAC/Cf,4BAAAA;;;;;0BAGNG,IAACC,CAAAA,IAAAA,EAAAA;gBAAKY,SAAS,EAAA,IAAA;gBAACC,UAAW,EAAA,UAAA;gBAAWC,WAAY,EAAA,YAAA;gBAAaX,GAAK,EAAA,CAAA;;kCAClEM,GAAC9B,CAAAA,SAAAA,EAAAA;AAAUkC,wBAAAA,UAAAA,EAAYhB,OAAOgB,UAAU;AAAEC,wBAAAA,WAAAA,EAAajB,OAAOkB,MAAM;wBAAEC,OAAS,EAAA,CAAA;AAC7E,wBAAA,QAAA,gBAAAP,GAACL,CAAAA,UAAAA,EAAAA;4BAAWa,UAAW,EAAA,MAAA;AAAON,4BAAAA,SAAAA,EAAWd,OAAOqB,IAAI;AACjD9B,4BAAAA,QAAAA,EAAAA;;;kCAGLqB,GAAC5B,CAAAA,GAAAA,EAAAA;wBAAIsC,WAAa,EAAA,CAAA;wBAAGC,YAAc,EAAA,CAAA;kCAChCC,GAAI7B,CAAAA,cAAAA,EAAgB,CAAC8B,KAAAA,iBACpBvB,IAACK,CAAAA,UAAAA,EAAAA;AAAuBO,gCAAAA,SAAAA,EAAWW,KAAMC,CAAAA,QAAQ,CAAC,GAAA,CAAA,GAAO,YAAe,GAAA,YAAA;;AAAc,oCAAA,GAAA;AAClFD,oCAAAA;;AADaA,6BAAAA,EAAAA,KAAAA,CAAAA;;;;;;AAQ7B;AAEAtC,UAAAA,CAAWwC,YAAY,GAAG;IACxBvC,KAAO,EAAA;QACLI,OAAS,EAAA,oBAAA;QACTD,MAAQ,EAAA,KAAA;QACRG,IAAM,EAAA;AACR;AACF,CAAA;AAEAP,UAAAA,CAAWyC,SAAS,GAAG;IACrBxC,KAAOyC,EAAAA,SAAAA,CAAUC,KAAK,CAAC;AACrBtC,QAAAA,OAAAA,EAASqC,UAAUE,MAAM;AACzBxC,QAAAA,MAAAA,EAAQsC,UAAUE,MAAM;AACxBrC,QAAAA,IAAAA,EAAMmC,UAAUE;AAClB,KAAA;AACF,CAAA;;;;"}

View File

@@ -0,0 +1,123 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
require('react');
var designSystem = require('@strapi/design-system');
var PropTypes = require('prop-types');
var reactIntl = require('react-intl');
const Input = ({ description, disabled, intlLabel, error, name, onChange, placeholder, providerToEditName, type, value })=>{
const { formatMessage } = reactIntl.useIntl();
const inputValue = name === 'noName' ? `${window.strapi.backendURL}/api/connect/${providerToEditName}/callback` : value;
const label = formatMessage({
id: intlLabel.id,
defaultMessage: intlLabel.defaultMessage
}, {
provider: providerToEditName,
...intlLabel.values
});
const hint = description ? formatMessage({
id: description.id,
defaultMessage: description.defaultMessage
}, {
provider: providerToEditName,
...description.values
}) : '';
if (type === 'bool') {
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
hint: hint,
name: name,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: label
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Toggle, {
"aria-label": name,
checked: value,
disabled: disabled,
offLabel: formatMessage({
id: 'app.components.ToggleCheckbox.off-label',
defaultMessage: 'Off'
}),
onLabel: formatMessage({
id: 'app.components.ToggleCheckbox.on-label',
defaultMessage: 'On'
}),
onChange: (e)=>{
onChange({
target: {
name,
value: e.target.checked
}
});
}
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Hint, {})
]
});
}
const formattedPlaceholder = placeholder ? formatMessage({
id: placeholder.id,
defaultMessage: placeholder.defaultMessage
}, {
...placeholder.values
}) : '';
const errorMessage = error ? formatMessage({
id: error,
defaultMessage: error
}) : '';
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
error: errorMessage,
name: name,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: label
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.TextInput, {
disabled: disabled,
onChange: onChange,
placeholder: formattedPlaceholder,
type: type,
value: inputValue
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {})
]
});
};
Input.defaultProps = {
description: null,
disabled: false,
error: '',
placeholder: null,
value: ''
};
Input.propTypes = {
description: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object
}),
disabled: PropTypes.bool,
error: PropTypes.string,
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object
}).isRequired,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object
}),
providerToEditName: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string
])
};
module.exports = Input;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,121 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import 'react';
import { Field, Toggle, TextInput } from '@strapi/design-system';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
const Input = ({ description, disabled, intlLabel, error, name, onChange, placeholder, providerToEditName, type, value })=>{
const { formatMessage } = useIntl();
const inputValue = name === 'noName' ? `${window.strapi.backendURL}/api/connect/${providerToEditName}/callback` : value;
const label = formatMessage({
id: intlLabel.id,
defaultMessage: intlLabel.defaultMessage
}, {
provider: providerToEditName,
...intlLabel.values
});
const hint = description ? formatMessage({
id: description.id,
defaultMessage: description.defaultMessage
}, {
provider: providerToEditName,
...description.values
}) : '';
if (type === 'bool') {
return /*#__PURE__*/ jsxs(Field.Root, {
hint: hint,
name: name,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: label
}),
/*#__PURE__*/ jsx(Toggle, {
"aria-label": name,
checked: value,
disabled: disabled,
offLabel: formatMessage({
id: 'app.components.ToggleCheckbox.off-label',
defaultMessage: 'Off'
}),
onLabel: formatMessage({
id: 'app.components.ToggleCheckbox.on-label',
defaultMessage: 'On'
}),
onChange: (e)=>{
onChange({
target: {
name,
value: e.target.checked
}
});
}
}),
/*#__PURE__*/ jsx(Field.Hint, {})
]
});
}
const formattedPlaceholder = placeholder ? formatMessage({
id: placeholder.id,
defaultMessage: placeholder.defaultMessage
}, {
...placeholder.values
}) : '';
const errorMessage = error ? formatMessage({
id: error,
defaultMessage: error
}) : '';
return /*#__PURE__*/ jsxs(Field.Root, {
error: errorMessage,
name: name,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: label
}),
/*#__PURE__*/ jsx(TextInput, {
disabled: disabled,
onChange: onChange,
placeholder: formattedPlaceholder,
type: type,
value: inputValue
}),
/*#__PURE__*/ jsx(Field.Error, {})
]
});
};
Input.defaultProps = {
description: null,
disabled: false,
error: '',
placeholder: null,
value: ''
};
Input.propTypes = {
description: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object
}),
disabled: PropTypes.bool,
error: PropTypes.string,
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object
}).isRequired,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object
}),
providerToEditName: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string
])
};
export { Input as default };
//# sourceMappingURL=index.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,110 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
require('react');
var designSystem = require('@strapi/design-system');
var formik = require('formik');
var PropTypes = require('prop-types');
var reactIntl = require('react-intl');
var index = require('./Input/index.js');
const FormModal = ({ headerBreadcrumbs, initialData, isSubmiting, layout, isOpen, onSubmit, onToggle, providerToEditName })=>{
const { formatMessage } = reactIntl.useIntl();
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Root, {
open: isOpen,
onOpenChange: onToggle,
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Modal.Content, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Header, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Breadcrumbs, {
label: headerBreadcrumbs.join(', '),
children: headerBreadcrumbs.map((crumb, index, arr)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Crumb, {
isCurrent: index === arr.length - 1,
children: crumb
}, crumb))
})
}),
/*#__PURE__*/ jsxRuntime.jsx(formik.Formik, {
onSubmit: (values)=>onSubmit(values),
initialValues: initialData,
validationSchema: layout.schema,
validateOnChange: false,
children: ({ errors, handleChange, values })=>{
return /*#__PURE__*/ jsxRuntime.jsxs(formik.Form, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Body, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
direction: "column",
alignItems: "stretch",
gap: 1,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Root, {
gap: 5,
children: layout.form.map((row)=>{
return row.map((input)=>{
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: input.size,
xs: 12,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsx(index, {
...input,
error: errors[input.name],
onChange: handleChange,
value: values[input.name],
providerToEditName: providerToEditName
})
}, input.name);
});
})
})
})
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Modal.Footer, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
variant: "tertiary",
onClick: onToggle,
type: "button",
children: formatMessage({
id: 'app.components.Button.cancel',
defaultMessage: 'Cancel'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
type: "submit",
loading: isSubmiting,
children: formatMessage({
id: 'global.save',
defaultMessage: 'Save'
})
})
]
})
]
});
}
})
]
})
});
};
FormModal.defaultProps = {
initialData: null,
providerToEditName: null
};
FormModal.propTypes = {
headerBreadcrumbs: PropTypes.arrayOf(PropTypes.string).isRequired,
initialData: PropTypes.object,
layout: PropTypes.shape({
form: PropTypes.arrayOf(PropTypes.array),
schema: PropTypes.object
}).isRequired,
isOpen: PropTypes.bool.isRequired,
isSubmiting: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
providerToEditName: PropTypes.string
};
module.exports = FormModal;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,108 @@
import { jsx, jsxs } from 'react/jsx-runtime';
import 'react';
import { Modal, Breadcrumbs, Crumb, Flex, Grid, Button } from '@strapi/design-system';
import { Formik, Form } from 'formik';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import Input from './Input/index.mjs';
const FormModal = ({ headerBreadcrumbs, initialData, isSubmiting, layout, isOpen, onSubmit, onToggle, providerToEditName })=>{
const { formatMessage } = useIntl();
return /*#__PURE__*/ jsx(Modal.Root, {
open: isOpen,
onOpenChange: onToggle,
children: /*#__PURE__*/ jsxs(Modal.Content, {
children: [
/*#__PURE__*/ jsx(Modal.Header, {
children: /*#__PURE__*/ jsx(Breadcrumbs, {
label: headerBreadcrumbs.join(', '),
children: headerBreadcrumbs.map((crumb, index, arr)=>/*#__PURE__*/ jsx(Crumb, {
isCurrent: index === arr.length - 1,
children: crumb
}, crumb))
})
}),
/*#__PURE__*/ jsx(Formik, {
onSubmit: (values)=>onSubmit(values),
initialValues: initialData,
validationSchema: layout.schema,
validateOnChange: false,
children: ({ errors, handleChange, values })=>{
return /*#__PURE__*/ jsxs(Form, {
children: [
/*#__PURE__*/ jsx(Modal.Body, {
children: /*#__PURE__*/ jsx(Flex, {
direction: "column",
alignItems: "stretch",
gap: 1,
children: /*#__PURE__*/ jsx(Grid.Root, {
gap: 5,
children: layout.form.map((row)=>{
return row.map((input)=>{
return /*#__PURE__*/ jsx(Grid.Item, {
col: input.size,
xs: 12,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsx(Input, {
...input,
error: errors[input.name],
onChange: handleChange,
value: values[input.name],
providerToEditName: providerToEditName
})
}, input.name);
});
})
})
})
}),
/*#__PURE__*/ jsxs(Modal.Footer, {
children: [
/*#__PURE__*/ jsx(Button, {
variant: "tertiary",
onClick: onToggle,
type: "button",
children: formatMessage({
id: 'app.components.Button.cancel',
defaultMessage: 'Cancel'
})
}),
/*#__PURE__*/ jsx(Button, {
type: "submit",
loading: isSubmiting,
children: formatMessage({
id: 'global.save',
defaultMessage: 'Save'
})
})
]
})
]
});
}
})
]
})
});
};
FormModal.defaultProps = {
initialData: null,
providerToEditName: null
};
FormModal.propTypes = {
headerBreadcrumbs: PropTypes.arrayOf(PropTypes.string).isRequired,
initialData: PropTypes.object,
layout: PropTypes.shape({
form: PropTypes.arrayOf(PropTypes.array),
schema: PropTypes.object
}).isRequired,
isOpen: PropTypes.bool.isRequired,
isSubmiting: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
providerToEditName: PropTypes.string
};
export { FormModal as default };
//# sourceMappingURL=index.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,33 @@
'use strict';
var designSystem = require('@strapi/design-system');
var styledComponents = require('styled-components');
const activeCheckboxWrapperStyles = styledComponents.css`
background: ${(props)=>props.theme.colors.primary100};
#cog {
opacity: 1;
}
`;
const CheckboxWrapper = styledComponents.styled(designSystem.Box)`
display: flex;
justify-content: space-between;
align-items: center;
#cog {
opacity: 0;
path {
fill: ${(props)=>props.theme.colors.primary600};
}
}
/* Show active style both on hover and when the action is selected */
${(props)=>props.isActive && activeCheckboxWrapperStyles}
&:hover {
${activeCheckboxWrapperStyles}
}
`;
module.exports = CheckboxWrapper;
//# sourceMappingURL=CheckboxWrapper.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CheckboxWrapper.js","sources":["../../../../../admin/src/components/Permissions/PermissionRow/CheckboxWrapper.jsx"],"sourcesContent":["import { Box } from '@strapi/design-system';\nimport { styled, css } from 'styled-components';\n\nconst activeCheckboxWrapperStyles = css`\n background: ${(props) => props.theme.colors.primary100};\n\n #cog {\n opacity: 1;\n }\n`;\n\nconst CheckboxWrapper = styled(Box)`\n display: flex;\n justify-content: space-between;\n align-items: center;\n\n #cog {\n opacity: 0;\n path {\n fill: ${(props) => props.theme.colors.primary600};\n }\n }\n\n /* Show active style both on hover and when the action is selected */\n ${(props) => props.isActive && activeCheckboxWrapperStyles}\n &:hover {\n ${activeCheckboxWrapperStyles}\n }\n`;\n\nexport default CheckboxWrapper;\n"],"names":["activeCheckboxWrapperStyles","css","props","theme","colors","primary100","CheckboxWrapper","styled","Box","primary600","isActive"],"mappings":";;;;;AAGA,MAAMA,2BAAAA,GAA8BC,oBAAG;cACzB,EAAE,CAACC,QAAUA,KAAMC,CAAAA,KAAK,CAACC,MAAM,CAACC,UAAU,CAAC;;;;;AAKzD,CAAC;AAEKC,MAAAA,eAAAA,GAAkBC,uBAAOC,CAAAA,gBAAAA,CAAI;;;;;;;;YAQvB,EAAE,CAACN,QAAUA,KAAMC,CAAAA,KAAK,CAACC,MAAM,CAACK,UAAU,CAAC;;;;;AAKrD,EAAA,EAAE,CAACP,KAAAA,GAAUA,KAAMQ,CAAAA,QAAQ,IAAIV,2BAA4B;;AAEzD,IAAA,EAAEA,2BAA4B;;AAElC;;;;"}

View File

@@ -0,0 +1,31 @@
import { Box } from '@strapi/design-system';
import { css, styled } from 'styled-components';
const activeCheckboxWrapperStyles = css`
background: ${(props)=>props.theme.colors.primary100};
#cog {
opacity: 1;
}
`;
const CheckboxWrapper = styled(Box)`
display: flex;
justify-content: space-between;
align-items: center;
#cog {
opacity: 0;
path {
fill: ${(props)=>props.theme.colors.primary600};
}
}
/* Show active style both on hover and when the action is selected */
${(props)=>props.isActive && activeCheckboxWrapperStyles}
&:hover {
${activeCheckboxWrapperStyles}
}
`;
export { CheckboxWrapper as default };
//# sourceMappingURL=CheckboxWrapper.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CheckboxWrapper.mjs","sources":["../../../../../admin/src/components/Permissions/PermissionRow/CheckboxWrapper.jsx"],"sourcesContent":["import { Box } from '@strapi/design-system';\nimport { styled, css } from 'styled-components';\n\nconst activeCheckboxWrapperStyles = css`\n background: ${(props) => props.theme.colors.primary100};\n\n #cog {\n opacity: 1;\n }\n`;\n\nconst CheckboxWrapper = styled(Box)`\n display: flex;\n justify-content: space-between;\n align-items: center;\n\n #cog {\n opacity: 0;\n path {\n fill: ${(props) => props.theme.colors.primary600};\n }\n }\n\n /* Show active style both on hover and when the action is selected */\n ${(props) => props.isActive && activeCheckboxWrapperStyles}\n &:hover {\n ${activeCheckboxWrapperStyles}\n }\n`;\n\nexport default CheckboxWrapper;\n"],"names":["activeCheckboxWrapperStyles","css","props","theme","colors","primary100","CheckboxWrapper","styled","Box","primary600","isActive"],"mappings":";;;AAGA,MAAMA,2BAAAA,GAA8BC,GAAG;cACzB,EAAE,CAACC,QAAUA,KAAMC,CAAAA,KAAK,CAACC,MAAM,CAACC,UAAU,CAAC;;;;;AAKzD,CAAC;AAEKC,MAAAA,eAAAA,GAAkBC,MAAOC,CAAAA,GAAAA,CAAI;;;;;;;;YAQvB,EAAE,CAACN,QAAUA,KAAMC,CAAAA,KAAK,CAACC,MAAM,CAACK,UAAU,CAAC;;;;;AAKrD,EAAA,EAAE,CAACP,KAAAA,GAAUA,KAAMQ,CAAAA,QAAQ,IAAIV,2BAA4B;;AAEzD,IAAA,EAAEA,2BAA4B;;AAElC;;;;"}

View File

@@ -0,0 +1,156 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
var get = require('lodash/get');
var PropTypes = require('prop-types');
var reactIntl = require('react-intl');
var styledComponents = require('styled-components');
var index = require('../../../contexts/UsersPermissionsContext/index.js');
var CheckboxWrapper = require('./CheckboxWrapper.js');
const Border = styledComponents.styled.div`
flex: 1;
align-self: center;
border-top: 1px solid ${({ theme })=>theme.colors.neutral150};
`;
const SubCategory = ({ subCategory })=>{
const { formatMessage } = reactIntl.useIntl();
const { onChange, onChangeSelectAll, onSelectedAction, selectedAction, modifiedData } = index.useUsersPermissions();
const currentScopedModifiedData = React.useMemo(()=>{
return get(modifiedData, subCategory.name, {});
}, [
modifiedData,
subCategory
]);
const hasAllActionsSelected = React.useMemo(()=>{
return Object.values(currentScopedModifiedData).every((action)=>action.enabled === true);
}, [
currentScopedModifiedData
]);
const hasSomeActionsSelected = React.useMemo(()=>{
return Object.values(currentScopedModifiedData).some((action)=>action.enabled === true) && !hasAllActionsSelected;
}, [
currentScopedModifiedData,
hasAllActionsSelected
]);
const handleChangeSelectAll = React.useCallback(({ target: { name } })=>{
onChangeSelectAll({
target: {
name,
value: !hasAllActionsSelected
}
});
}, [
hasAllActionsSelected,
onChangeSelectAll
]);
const isActionSelected = React.useCallback((actionName)=>{
return selectedAction === actionName;
}, [
selectedAction
]);
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
justifyContent: "space-between",
alignItems: "center",
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
paddingRight: 4,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
variant: "sigma",
textColor: "neutral600",
children: subCategory.label
})
}),
/*#__PURE__*/ jsxRuntime.jsx(Border, {}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
paddingLeft: 4,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Checkbox, {
name: subCategory.name,
checked: hasSomeActionsSelected ? 'indeterminate' : hasAllActionsSelected,
onCheckedChange: (value)=>handleChangeSelectAll({
target: {
name: subCategory.name,
value
}
}),
children: formatMessage({
id: 'app.utils.select-all',
defaultMessage: 'Select all'
})
})
})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
paddingTop: 6,
paddingBottom: 6,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Root, {
gap: 2,
style: {
flex: 1
},
children: subCategory.actions.map((action)=>{
const name = `${action.name}.enabled`;
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsxs(CheckboxWrapper, {
isActive: isActionSelected(action.name),
padding: 2,
hasRadius: true,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Checkbox, {
checked: get(modifiedData, name, false),
name: name,
onCheckedChange: (value)=>onChange({
target: {
name,
value
}
}),
children: action.label
}),
/*#__PURE__*/ jsxRuntime.jsxs("button", {
type: "button",
onClick: ()=>onSelectedAction(action.name),
style: {
display: 'inline-flex',
alignItems: 'center'
},
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
tag: "span",
children: formatMessage({
id: 'app.utils.show-bound-route',
defaultMessage: 'Show bound route for {route}'
}, {
route: action.name
})
}),
/*#__PURE__*/ jsxRuntime.jsx(icons.Cog, {
id: "cog",
cursor: "pointer"
})
]
})
]
})
}, action.name);
})
})
})
]
});
};
SubCategory.propTypes = {
subCategory: PropTypes.object.isRequired
};
module.exports = SubCategory;
//# sourceMappingURL=SubCategory.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,154 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import { useMemo, useCallback } from 'react';
import { Box, Flex, Typography, Checkbox, Grid, VisuallyHidden } from '@strapi/design-system';
import { Cog } from '@strapi/icons';
import get from 'lodash/get';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { styled } from 'styled-components';
import { useUsersPermissions } from '../../../contexts/UsersPermissionsContext/index.mjs';
import CheckboxWrapper from './CheckboxWrapper.mjs';
const Border = styled.div`
flex: 1;
align-self: center;
border-top: 1px solid ${({ theme })=>theme.colors.neutral150};
`;
const SubCategory = ({ subCategory })=>{
const { formatMessage } = useIntl();
const { onChange, onChangeSelectAll, onSelectedAction, selectedAction, modifiedData } = useUsersPermissions();
const currentScopedModifiedData = useMemo(()=>{
return get(modifiedData, subCategory.name, {});
}, [
modifiedData,
subCategory
]);
const hasAllActionsSelected = useMemo(()=>{
return Object.values(currentScopedModifiedData).every((action)=>action.enabled === true);
}, [
currentScopedModifiedData
]);
const hasSomeActionsSelected = useMemo(()=>{
return Object.values(currentScopedModifiedData).some((action)=>action.enabled === true) && !hasAllActionsSelected;
}, [
currentScopedModifiedData,
hasAllActionsSelected
]);
const handleChangeSelectAll = useCallback(({ target: { name } })=>{
onChangeSelectAll({
target: {
name,
value: !hasAllActionsSelected
}
});
}, [
hasAllActionsSelected,
onChangeSelectAll
]);
const isActionSelected = useCallback((actionName)=>{
return selectedAction === actionName;
}, [
selectedAction
]);
return /*#__PURE__*/ jsxs(Box, {
children: [
/*#__PURE__*/ jsxs(Flex, {
justifyContent: "space-between",
alignItems: "center",
children: [
/*#__PURE__*/ jsx(Box, {
paddingRight: 4,
children: /*#__PURE__*/ jsx(Typography, {
variant: "sigma",
textColor: "neutral600",
children: subCategory.label
})
}),
/*#__PURE__*/ jsx(Border, {}),
/*#__PURE__*/ jsx(Box, {
paddingLeft: 4,
children: /*#__PURE__*/ jsx(Checkbox, {
name: subCategory.name,
checked: hasSomeActionsSelected ? 'indeterminate' : hasAllActionsSelected,
onCheckedChange: (value)=>handleChangeSelectAll({
target: {
name: subCategory.name,
value
}
}),
children: formatMessage({
id: 'app.utils.select-all',
defaultMessage: 'Select all'
})
})
})
]
}),
/*#__PURE__*/ jsx(Flex, {
paddingTop: 6,
paddingBottom: 6,
children: /*#__PURE__*/ jsx(Grid.Root, {
gap: 2,
style: {
flex: 1
},
children: subCategory.actions.map((action)=>{
const name = `${action.name}.enabled`;
return /*#__PURE__*/ jsx(Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxs(CheckboxWrapper, {
isActive: isActionSelected(action.name),
padding: 2,
hasRadius: true,
children: [
/*#__PURE__*/ jsx(Checkbox, {
checked: get(modifiedData, name, false),
name: name,
onCheckedChange: (value)=>onChange({
target: {
name,
value
}
}),
children: action.label
}),
/*#__PURE__*/ jsxs("button", {
type: "button",
onClick: ()=>onSelectedAction(action.name),
style: {
display: 'inline-flex',
alignItems: 'center'
},
children: [
/*#__PURE__*/ jsx(VisuallyHidden, {
tag: "span",
children: formatMessage({
id: 'app.utils.show-bound-route',
defaultMessage: 'Show bound route for {route}'
}, {
route: action.name
})
}),
/*#__PURE__*/ jsx(Cog, {
id: "cog",
cursor: "pointer"
})
]
})
]
})
}, action.name);
})
})
})
]
});
};
SubCategory.propTypes = {
subCategory: PropTypes.object.isRequired
};
export { SubCategory as default };
//# sourceMappingURL=SubCategory.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,50 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var designSystem = require('@strapi/design-system');
var sortBy = require('lodash/sortBy');
var PropTypes = require('prop-types');
var SubCategory = require('./SubCategory.js');
const PermissionRow = ({ name, permissions })=>{
const subCategories = React.useMemo(()=>{
return sortBy(Object.values(permissions.controllers).reduce((acc, curr, index)=>{
const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;
const actions = sortBy(Object.keys(curr).reduce((acc, current)=>{
return [
...acc,
{
...curr[current],
label: current,
name: `${currentName}.${current}`
}
];
}, []), 'label');
return [
...acc,
{
actions,
label: Object.keys(permissions.controllers)[index],
name: currentName
}
];
}, []), 'label');
}, [
name,
permissions
]);
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
padding: 6,
children: subCategories.map((subCategory)=>/*#__PURE__*/ jsxRuntime.jsx(SubCategory, {
subCategory: subCategory
}, subCategory.name))
});
};
PermissionRow.propTypes = {
name: PropTypes.string.isRequired,
permissions: PropTypes.object.isRequired
};
module.exports = PermissionRow;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../../../../../admin/src/components/Permissions/PermissionRow/index.jsx"],"sourcesContent":["import React, { useMemo } from 'react';\n\nimport { Box } from '@strapi/design-system';\nimport sortBy from 'lodash/sortBy';\nimport PropTypes from 'prop-types';\n\nimport SubCategory from './SubCategory';\n\nconst PermissionRow = ({ name, permissions }) => {\n const subCategories = useMemo(() => {\n return sortBy(\n Object.values(permissions.controllers).reduce((acc, curr, index) => {\n const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;\n const actions = sortBy(\n Object.keys(curr).reduce((acc, current) => {\n return [\n ...acc,\n {\n ...curr[current],\n label: current,\n name: `${currentName}.${current}`,\n },\n ];\n }, []),\n 'label'\n );\n\n return [\n ...acc,\n {\n actions,\n label: Object.keys(permissions.controllers)[index],\n name: currentName,\n },\n ];\n }, []),\n 'label'\n );\n }, [name, permissions]);\n\n return (\n <Box padding={6}>\n {subCategories.map((subCategory) => (\n <SubCategory key={subCategory.name} subCategory={subCategory} />\n ))}\n </Box>\n );\n};\n\nPermissionRow.propTypes = {\n name: PropTypes.string.isRequired,\n permissions: PropTypes.object.isRequired,\n};\n\nexport default PermissionRow;\n"],"names":["PermissionRow","name","permissions","subCategories","useMemo","sortBy","Object","values","controllers","reduce","acc","curr","index","currentName","keys","actions","current","label","_jsx","Box","padding","map","subCategory","SubCategory","propTypes","PropTypes","string","isRequired","object"],"mappings":";;;;;;;;;AAQA,MAAMA,gBAAgB,CAAC,EAAEC,IAAI,EAAEC,WAAW,EAAE,GAAA;AAC1C,IAAA,MAAMC,gBAAgBC,aAAQ,CAAA,IAAA;QAC5B,OAAOC,MAAAA,CACLC,MAAOC,CAAAA,MAAM,CAACL,WAAAA,CAAYM,WAAW,CAAA,CAAEC,MAAM,CAAC,CAACC,GAAAA,EAAKC,IAAMC,EAAAA,KAAAA,GAAAA;AACxD,YAAA,MAAMC,WAAc,GAAA,CAAC,EAAEZ,IAAAA,CAAK,aAAa,EAAEK,MAAAA,CAAOQ,IAAI,CAACZ,YAAYM,WAAW,CAAC,CAACI,KAAAA,CAAM,CAAC,CAAC;YACxF,MAAMG,OAAAA,GAAUV,OACdC,MAAOQ,CAAAA,IAAI,CAACH,IAAMF,CAAAA,CAAAA,MAAM,CAAC,CAACC,GAAKM,EAAAA,OAAAA,GAAAA;gBAC7B,OAAO;AACFN,oBAAAA,GAAAA,GAAAA;AACH,oBAAA;wBACE,GAAGC,IAAI,CAACK,OAAQ,CAAA;wBAChBC,KAAOD,EAAAA,OAAAA;AACPf,wBAAAA,IAAAA,EAAM,CAAC,EAAEY,WAAAA,CAAY,CAAC,EAAEG,QAAQ;AAClC;AACD,iBAAA;AACH,aAAA,EAAG,EAAE,CACL,EAAA,OAAA,CAAA;YAGF,OAAO;AACFN,gBAAAA,GAAAA,GAAAA;AACH,gBAAA;AACEK,oBAAAA,OAAAA;AACAE,oBAAAA,KAAAA,EAAOX,OAAOQ,IAAI,CAACZ,YAAYM,WAAW,CAAC,CAACI,KAAM,CAAA;oBAClDX,IAAMY,EAAAA;AACR;AACD,aAAA;AACH,SAAA,EAAG,EAAE,CACL,EAAA,OAAA,CAAA;KAED,EAAA;AAACZ,QAAAA,IAAAA;AAAMC,QAAAA;AAAY,KAAA,CAAA;AAEtB,IAAA,qBACEgB,cAACC,CAAAA,gBAAAA,EAAAA;QAAIC,OAAS,EAAA,CAAA;AACXjB,QAAAA,QAAAA,EAAAA,aAAAA,CAAckB,GAAG,CAAC,CAACC,WAAAA,iBAClBJ,cAACK,CAAAA,WAAAA,EAAAA;gBAAmCD,WAAaA,EAAAA;AAA/BA,aAAAA,EAAAA,WAAAA,CAAYrB,IAAI,CAAA;;AAI1C;AAEAD,aAAAA,CAAcwB,SAAS,GAAG;IACxBvB,IAAMwB,EAAAA,SAAAA,CAAUC,MAAM,CAACC,UAAU;IACjCzB,WAAauB,EAAAA,SAAAA,CAAUG,MAAM,CAACD;AAChC,CAAA;;;;"}

View File

@@ -0,0 +1,48 @@
import { jsx } from 'react/jsx-runtime';
import { useMemo } from 'react';
import { Box } from '@strapi/design-system';
import sortBy from 'lodash/sortBy';
import PropTypes from 'prop-types';
import SubCategory from './SubCategory.mjs';
const PermissionRow = ({ name, permissions })=>{
const subCategories = useMemo(()=>{
return sortBy(Object.values(permissions.controllers).reduce((acc, curr, index)=>{
const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;
const actions = sortBy(Object.keys(curr).reduce((acc, current)=>{
return [
...acc,
{
...curr[current],
label: current,
name: `${currentName}.${current}`
}
];
}, []), 'label');
return [
...acc,
{
actions,
label: Object.keys(permissions.controllers)[index],
name: currentName
}
];
}, []), 'label');
}, [
name,
permissions
]);
return /*#__PURE__*/ jsx(Box, {
padding: 6,
children: subCategories.map((subCategory)=>/*#__PURE__*/ jsx(SubCategory, {
subCategory: subCategory
}, subCategory.name))
});
};
PermissionRow.propTypes = {
name: PropTypes.string.isRequired,
permissions: PropTypes.object.isRequired
};
export { PermissionRow as default };
//# sourceMappingURL=index.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":["../../../../../admin/src/components/Permissions/PermissionRow/index.jsx"],"sourcesContent":["import React, { useMemo } from 'react';\n\nimport { Box } from '@strapi/design-system';\nimport sortBy from 'lodash/sortBy';\nimport PropTypes from 'prop-types';\n\nimport SubCategory from './SubCategory';\n\nconst PermissionRow = ({ name, permissions }) => {\n const subCategories = useMemo(() => {\n return sortBy(\n Object.values(permissions.controllers).reduce((acc, curr, index) => {\n const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;\n const actions = sortBy(\n Object.keys(curr).reduce((acc, current) => {\n return [\n ...acc,\n {\n ...curr[current],\n label: current,\n name: `${currentName}.${current}`,\n },\n ];\n }, []),\n 'label'\n );\n\n return [\n ...acc,\n {\n actions,\n label: Object.keys(permissions.controllers)[index],\n name: currentName,\n },\n ];\n }, []),\n 'label'\n );\n }, [name, permissions]);\n\n return (\n <Box padding={6}>\n {subCategories.map((subCategory) => (\n <SubCategory key={subCategory.name} subCategory={subCategory} />\n ))}\n </Box>\n );\n};\n\nPermissionRow.propTypes = {\n name: PropTypes.string.isRequired,\n permissions: PropTypes.object.isRequired,\n};\n\nexport default PermissionRow;\n"],"names":["PermissionRow","name","permissions","subCategories","useMemo","sortBy","Object","values","controllers","reduce","acc","curr","index","currentName","keys","actions","current","label","_jsx","Box","padding","map","subCategory","SubCategory","propTypes","PropTypes","string","isRequired","object"],"mappings":";;;;;;;AAQA,MAAMA,gBAAgB,CAAC,EAAEC,IAAI,EAAEC,WAAW,EAAE,GAAA;AAC1C,IAAA,MAAMC,gBAAgBC,OAAQ,CAAA,IAAA;QAC5B,OAAOC,MAAAA,CACLC,MAAOC,CAAAA,MAAM,CAACL,WAAAA,CAAYM,WAAW,CAAA,CAAEC,MAAM,CAAC,CAACC,GAAAA,EAAKC,IAAMC,EAAAA,KAAAA,GAAAA;AACxD,YAAA,MAAMC,WAAc,GAAA,CAAC,EAAEZ,IAAAA,CAAK,aAAa,EAAEK,MAAAA,CAAOQ,IAAI,CAACZ,YAAYM,WAAW,CAAC,CAACI,KAAAA,CAAM,CAAC,CAAC;YACxF,MAAMG,OAAAA,GAAUV,OACdC,MAAOQ,CAAAA,IAAI,CAACH,IAAMF,CAAAA,CAAAA,MAAM,CAAC,CAACC,GAAKM,EAAAA,OAAAA,GAAAA;gBAC7B,OAAO;AACFN,oBAAAA,GAAAA,GAAAA;AACH,oBAAA;wBACE,GAAGC,IAAI,CAACK,OAAQ,CAAA;wBAChBC,KAAOD,EAAAA,OAAAA;AACPf,wBAAAA,IAAAA,EAAM,CAAC,EAAEY,WAAAA,CAAY,CAAC,EAAEG,QAAQ;AAClC;AACD,iBAAA;AACH,aAAA,EAAG,EAAE,CACL,EAAA,OAAA,CAAA;YAGF,OAAO;AACFN,gBAAAA,GAAAA,GAAAA;AACH,gBAAA;AACEK,oBAAAA,OAAAA;AACAE,oBAAAA,KAAAA,EAAOX,OAAOQ,IAAI,CAACZ,YAAYM,WAAW,CAAC,CAACI,KAAM,CAAA;oBAClDX,IAAMY,EAAAA;AACR;AACD,aAAA;AACH,SAAA,EAAG,EAAE,CACL,EAAA,OAAA,CAAA;KAED,EAAA;AAACZ,QAAAA,IAAAA;AAAMC,QAAAA;AAAY,KAAA,CAAA;AAEtB,IAAA,qBACEgB,GAACC,CAAAA,GAAAA,EAAAA;QAAIC,OAAS,EAAA,CAAA;AACXjB,QAAAA,QAAAA,EAAAA,aAAAA,CAAckB,GAAG,CAAC,CAACC,WAAAA,iBAClBJ,GAACK,CAAAA,WAAAA,EAAAA;gBAAmCD,WAAaA,EAAAA;AAA/BA,aAAAA,EAAAA,WAAAA,CAAYrB,IAAI,CAAA;;AAI1C;AAEAD,aAAAA,CAAcwB,SAAS,GAAG;IACxBvB,IAAMwB,EAAAA,SAAAA,CAAUC,MAAM,CAACC,UAAU;IACjCzB,WAAauB,EAAAA,SAAAA,CAAUG,MAAM,CAACD;AAChC,CAAA;;;;"}

View File

@@ -0,0 +1,52 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var designSystem = require('@strapi/design-system');
var reactIntl = require('react-intl');
var index = require('../../contexts/UsersPermissionsContext/index.js');
var formatPluginName = require('../../utils/formatPluginName.js');
var init = require('./init.js');
var index$1 = require('./PermissionRow/index.js');
var reducer = require('./reducer.js');
const Permissions = ()=>{
const { modifiedData } = index.useUsersPermissions();
const { formatMessage } = reactIntl.useIntl();
const [{ collapses }] = React.useReducer(reducer.reducer, reducer.initialState, (state)=>init(state, modifiedData));
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Accordion.Root, {
size: "M",
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
direction: "column",
alignItems: "stretch",
gap: 1,
children: collapses.map((collapse, index)=>/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Accordion.Item, {
value: collapse.name,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Accordion.Header, {
variant: index % 2 === 0 ? 'secondary' : undefined,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Accordion.Trigger, {
caretPosition: "right",
description: formatMessage({
id: 'users-permissions.Plugin.permissions.plugins.description',
defaultMessage: 'Define all allowed actions for the {name} plugin.'
}, {
name: collapse.name
}),
children: formatPluginName(collapse.name)
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Accordion.Content, {
children: /*#__PURE__*/ jsxRuntime.jsx(index$1, {
permissions: modifiedData[collapse.name],
name: collapse.name
})
})
]
}, collapse.name))
})
});
};
module.exports = Permissions;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../../../../admin/src/components/Permissions/index.jsx"],"sourcesContent":["import React, { useReducer } from 'react';\n\nimport { Accordion, Flex } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { useUsersPermissions } from '../../contexts/UsersPermissionsContext';\nimport formatPluginName from '../../utils/formatPluginName';\n\nimport init from './init';\nimport PermissionRow from './PermissionRow';\nimport { initialState, reducer } from './reducer';\n\nconst Permissions = () => {\n const { modifiedData } = useUsersPermissions();\n const { formatMessage } = useIntl();\n const [{ collapses }] = useReducer(reducer, initialState, (state) => init(state, modifiedData));\n\n return (\n <Accordion.Root size=\"M\">\n <Flex direction=\"column\" alignItems=\"stretch\" gap={1}>\n {collapses.map((collapse, index) => (\n <Accordion.Item key={collapse.name} value={collapse.name}>\n <Accordion.Header variant={index % 2 === 0 ? 'secondary' : undefined}>\n <Accordion.Trigger\n caretPosition=\"right\"\n description={formatMessage(\n {\n id: 'users-permissions.Plugin.permissions.plugins.description',\n defaultMessage: 'Define all allowed actions for the {name} plugin.',\n },\n { name: collapse.name }\n )}\n >\n {formatPluginName(collapse.name)}\n </Accordion.Trigger>\n </Accordion.Header>\n <Accordion.Content>\n <PermissionRow permissions={modifiedData[collapse.name]} name={collapse.name} />\n </Accordion.Content>\n </Accordion.Item>\n ))}\n </Flex>\n </Accordion.Root>\n );\n};\n\nexport default Permissions;\n"],"names":["Permissions","modifiedData","useUsersPermissions","formatMessage","useIntl","collapses","useReducer","reducer","initialState","state","init","_jsx","Accordion","Root","size","Flex","direction","alignItems","gap","map","collapse","index","_jsxs","Item","value","name","Header","variant","undefined","Trigger","caretPosition","description","id","defaultMessage","formatPluginName","Content","PermissionRow","permissions"],"mappings":";;;;;;;;;;;;AAYA,MAAMA,WAAc,GAAA,IAAA;IAClB,MAAM,EAAEC,YAAY,EAAE,GAAGC,yBAAAA,EAAAA;IACzB,MAAM,EAAEC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;AAC1B,IAAA,MAAM,CAAC,EAAEC,SAAS,EAAE,CAAC,GAAGC,gBAAWC,CAAAA,eAAAA,EAASC,oBAAc,EAAA,CAACC,KAAUC,GAAAA,IAAAA,CAAKD,KAAOR,EAAAA,YAAAA,CAAAA,CAAAA;IAEjF,qBACEU,cAAA,CAACC,uBAAUC,IAAI,EAAA;QAACC,IAAK,EAAA,GAAA;AACnB,QAAA,QAAA,gBAAAH,cAACI,CAAAA,iBAAAA,EAAAA;YAAKC,SAAU,EAAA,QAAA;YAASC,UAAW,EAAA,SAAA;YAAUC,GAAK,EAAA,CAAA;AAChDb,YAAAA,QAAAA,EAAAA,SAAAA,CAAUc,GAAG,CAAC,CAACC,UAAUC,KACxB,iBAAAC,eAAA,CAACV,uBAAUW,IAAI,EAAA;AAAqBC,oBAAAA,KAAAA,EAAOJ,SAASK,IAAI;;AACtD,sCAAAd,cAAA,CAACC,uBAAUc,MAAM,EAAA;4BAACC,OAASN,EAAAA,KAAAA,GAAQ,CAAM,KAAA,CAAA,GAAI,WAAcO,GAAAA,SAAAA;oDACzDjB,cAAA,CAACC,uBAAUiB,OAAO,EAAA;gCAChBC,aAAc,EAAA,OAAA;AACdC,gCAAAA,WAAAA,EAAa5B,aACX,CAAA;oCACE6B,EAAI,EAAA,0DAAA;oCACJC,cAAgB,EAAA;iCAElB,EAAA;AAAER,oCAAAA,IAAAA,EAAML,SAASK;AAAK,iCAAA,CAAA;AAGvBS,gCAAAA,QAAAA,EAAAA,gBAAAA,CAAiBd,SAASK,IAAI;;;AAGnC,sCAAAd,cAAA,CAACC,uBAAUuB,OAAO,EAAA;AAChB,4BAAA,QAAA,gBAAAxB,cAACyB,CAAAA,OAAAA,EAAAA;AAAcC,gCAAAA,WAAAA,EAAapC,YAAY,CAACmB,QAASK,CAAAA,IAAI,CAAC;AAAEA,gCAAAA,IAAAA,EAAML,SAASK;;;;AAhBvDL,iBAAAA,EAAAA,QAAAA,CAASK,IAAI,CAAA;;;AAuB5C;;;;"}

View File

@@ -0,0 +1,50 @@
import { jsx, jsxs } from 'react/jsx-runtime';
import { useReducer } from 'react';
import { Accordion, Flex } from '@strapi/design-system';
import { useIntl } from 'react-intl';
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext/index.mjs';
import formatPluginName from '../../utils/formatPluginName.mjs';
import init from './init.mjs';
import PermissionRow from './PermissionRow/index.mjs';
import { reducer, initialState } from './reducer.mjs';
const Permissions = ()=>{
const { modifiedData } = useUsersPermissions();
const { formatMessage } = useIntl();
const [{ collapses }] = useReducer(reducer, initialState, (state)=>init(state, modifiedData));
return /*#__PURE__*/ jsx(Accordion.Root, {
size: "M",
children: /*#__PURE__*/ jsx(Flex, {
direction: "column",
alignItems: "stretch",
gap: 1,
children: collapses.map((collapse, index)=>/*#__PURE__*/ jsxs(Accordion.Item, {
value: collapse.name,
children: [
/*#__PURE__*/ jsx(Accordion.Header, {
variant: index % 2 === 0 ? 'secondary' : undefined,
children: /*#__PURE__*/ jsx(Accordion.Trigger, {
caretPosition: "right",
description: formatMessage({
id: 'users-permissions.Plugin.permissions.plugins.description',
defaultMessage: 'Define all allowed actions for the {name} plugin.'
}, {
name: collapse.name
}),
children: formatPluginName(collapse.name)
})
}),
/*#__PURE__*/ jsx(Accordion.Content, {
children: /*#__PURE__*/ jsx(PermissionRow, {
permissions: modifiedData[collapse.name],
name: collapse.name
})
})
]
}, collapse.name))
})
});
};
export { Permissions as default };
//# sourceMappingURL=index.mjs.map

Some files were not shown because too many files have changed in this diff Show More