@strapi/admin 4.2.0-beta.3 → 4.2.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/components/ConfigurationsProvider/index.js +51 -0
- package/admin/src/components/ConfigurationsProvider/reducer.js +28 -0
- package/admin/src/components/LeftMenu/index.js +12 -2
- package/admin/src/components/Providers/index.js +8 -4
- package/admin/src/components/UnauthenticatedLogo/index.js +4 -2
- package/admin/src/pages/App/index.js +7 -2
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/Form/index.js +85 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/Form/init.js +13 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/Form/reducer.js +43 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/index.js +118 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/reducer.js +28 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/stepper.js +25 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/AddLogoDialog.js +67 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/FromComputerForm.js +176 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/FromUrlForm.js +82 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/ImageCardAsset.js +51 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/PendingLogoDialog.js +97 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/index.js +85 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/reducer.js +28 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +153 -91
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +16 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/constants.js +3 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/getFormData.js +17 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/parseFileMetadatas.js +76 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +17 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/urlToFile.js +21 -0
- package/admin/src/translations/en.json +26 -0
- package/build/1541.6c1c96f9.chunk.js +307 -0
- package/build/3214.9196aeff.chunk.js +235 -0
- package/build/3865.21cec9de.chunk.js +310 -0
- package/build/{4073.41ac1235.chunk.js → 4073.e144a91a.chunk.js} +1 -1
- package/build/{210.014495c1.chunk.js → 472.0350a5bd.chunk.js} +32 -32
- package/build/4800.d3ebc81d.chunk.js +1 -0
- package/build/4982.f53b78a4.chunk.js +308 -0
- package/build/7351.b95e65ae.chunk.js +428 -0
- package/build/7418.6db737ce.chunk.js +112 -0
- package/build/8826.58e236d4.chunk.js +1057 -0
- package/build/9066.118ecccd.chunk.js +101 -0
- package/build/{7191.3bde3cbf.chunk.js → 9298.aff28744.chunk.js} +85 -86
- package/build/948.d64fb515.chunk.js +2 -0
- package/build/9988.f84412d9.chunk.js +162 -0
- package/build/Admin-authenticatedApp.162a5805.chunk.js +80 -0
- package/build/{Admin_homePage.f157e33e.chunk.js → Admin_homePage.0ac648e8.chunk.js} +2 -2
- package/build/Admin_marketplace.0bb91ec8.chunk.js +11 -0
- package/build/{Admin_profilePage.62c203ad.chunk.js → Admin_profilePage.27191ed2.chunk.js} +1 -1
- package/build/Admin_settingsPage.23e873f0.chunk.js +178 -0
- package/build/{admin-edit-roles-page.94e1403b.chunk.js → admin-edit-roles-page.fb374555.chunk.js} +1 -1
- package/build/admin-edit-users.a360deaf.chunk.js +10 -0
- package/build/admin-users.47d06d24.chunk.js +11 -0
- package/build/api-tokens-create-page.698f132d.chunk.js +1 -0
- package/build/api-tokens-edit-page.afece2fe.chunk.js +1 -0
- package/build/{api-tokens-list-page.340750a6.chunk.js → api-tokens-list-page.46d96dee.chunk.js} +1 -1
- package/build/{content-manager.6cdcfb6e.chunk.js → content-manager.7cd28f84.chunk.js} +14 -14
- package/build/{content-type-builder.e73879b9.chunk.js → content-type-builder.7456cabe.chunk.js} +10 -10
- package/build/en-json.40ee00aa.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/main.b632a0d6.js +11625 -0
- package/build/runtime~main.38d418e9.js +2 -0
- package/build/{sso-settings-page.e9034e22.chunk.js → sso-settings-page.dfb0b917.chunk.js} +1 -1
- package/build/webhook-edit-page.a7ae6e3b.chunk.js +23 -0
- package/build/webhook-list-page.83297d98.chunk.js +133 -0
- package/package.json +7 -7
- package/server/config/admin-actions.js +14 -0
- package/server/controllers/admin.js +33 -1
- package/server/routes/admin.js +28 -0
- package/server/services/index.js +1 -0
- package/server/services/project-settings.js +173 -0
- package/server/utils/index.d.ts +2 -0
- package/server/validation/project-settings.js +39 -0
- package/build/1709.ceed0e18.chunk.js +0 -503
- package/build/20.cf744c35.chunk.js +0 -308
- package/build/2135.95ee6de1.chunk.js +0 -162
- package/build/2524.688d0355.chunk.js +0 -1
- package/build/4761.3eabdf46.chunk.js +0 -101
- package/build/6281.f10a7e3a.chunk.js +0 -1
- package/build/7009.79fce86d.chunk.js +0 -164
- package/build/7863.bc7a8f3a.chunk.js +0 -112
- package/build/Admin-authenticatedApp.4ce8d292.chunk.js +0 -80
- package/build/Admin_marketplace.1e3393c9.chunk.js +0 -11
- package/build/Admin_settingsPage.924a7816.chunk.js +0 -170
- package/build/admin-edit-users.6c2bf718.chunk.js +0 -10
- package/build/admin-users.e03db115.chunk.js +0 -11
- package/build/api-tokens-create-page.787ab302.chunk.js +0 -1
- package/build/api-tokens-edit-page.e4010c0c.chunk.js +0 -1
- package/build/en-json.3e1a222e.chunk.js +0 -1
- package/build/main.45472ea9.js +0 -8404
- package/build/runtime~main.e7611418.js +0 -2
- package/build/webhook-edit-page.2fa94db3.chunk.js +0 -23
- package/build/webhook-list-page.b594db49.chunk.js +0 -133
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { useReducer, useRef } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { ConfigurationsContext } from '../../contexts';
|
|
4
|
+
import reducer, { initialState } from './reducer';
|
|
5
|
+
|
|
6
|
+
const ConfigurationsProvider = ({
|
|
7
|
+
children,
|
|
8
|
+
authLogo,
|
|
9
|
+
menuLogo: defaultMenuLogo,
|
|
10
|
+
showReleaseNotification,
|
|
11
|
+
showTutorials,
|
|
12
|
+
}) => {
|
|
13
|
+
const [{ menuLogo }, dispatch] = useReducer(reducer, initialState);
|
|
14
|
+
|
|
15
|
+
const updateProjectSettings = ({ menuLogo }) => {
|
|
16
|
+
return dispatch({
|
|
17
|
+
type: 'UPDATE_PROJECT_SETTINGS',
|
|
18
|
+
values: {
|
|
19
|
+
menuLogo: menuLogo || defaultMenuLogo,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const updateProjectSettingsRef = useRef(updateProjectSettings);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<ConfigurationsContext.Provider
|
|
28
|
+
value={{
|
|
29
|
+
logos: {
|
|
30
|
+
menu: { custom: menuLogo, default: defaultMenuLogo },
|
|
31
|
+
auth: { custom: null, default: authLogo },
|
|
32
|
+
},
|
|
33
|
+
updateProjectSettings: updateProjectSettingsRef.current,
|
|
34
|
+
showReleaseNotification,
|
|
35
|
+
showTutorials,
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
{children}
|
|
39
|
+
</ConfigurationsContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
ConfigurationsProvider.propTypes = {
|
|
44
|
+
authLogo: PropTypes.string.isRequired,
|
|
45
|
+
children: PropTypes.element.isRequired,
|
|
46
|
+
menuLogo: PropTypes.string.isRequired,
|
|
47
|
+
showReleaseNotification: PropTypes.bool.isRequired,
|
|
48
|
+
showTutorials: PropTypes.bool.isRequired,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default ConfigurationsProvider;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* eslint-disable consistent-return */
|
|
2
|
+
/*
|
|
3
|
+
*
|
|
4
|
+
* ConfigurationsProvider reducer
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import produce from 'immer';
|
|
9
|
+
|
|
10
|
+
const initialState = {
|
|
11
|
+
menuLogo: null,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const reducer = (state = initialState, action) =>
|
|
15
|
+
produce(state, draftState => {
|
|
16
|
+
switch (action.type) {
|
|
17
|
+
case 'UPDATE_PROJECT_SETTINGS': {
|
|
18
|
+
Object.assign(draftState, action.values);
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
default: {
|
|
22
|
+
return draftState;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export default reducer;
|
|
28
|
+
export { initialState };
|
|
@@ -53,7 +53,9 @@ const LinkUser = styled(RouterNavLink)`
|
|
|
53
53
|
const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
|
|
54
54
|
const buttonRef = useRef();
|
|
55
55
|
const [userLinksVisible, setUserLinksVisible] = useState(false);
|
|
56
|
-
const {
|
|
56
|
+
const {
|
|
57
|
+
logos: { menu },
|
|
58
|
+
} = useConfigurations();
|
|
57
59
|
const [condensed, setCondensed] = usePersistentState('navbar-condensed', false);
|
|
58
60
|
const { userDisplayName } = useAppInfos();
|
|
59
61
|
const { formatMessage } = useIntl();
|
|
@@ -94,7 +96,15 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
|
|
|
94
96
|
defaultMessage: 'Workplace',
|
|
95
97
|
})}
|
|
96
98
|
title={menuTitle}
|
|
97
|
-
icon={
|
|
99
|
+
icon={
|
|
100
|
+
<img
|
|
101
|
+
src={menu.custom || menu.default}
|
|
102
|
+
alt={formatMessage({
|
|
103
|
+
id: 'app.components.LeftMenu.logo.alt',
|
|
104
|
+
defaultMessage: 'Application logo',
|
|
105
|
+
})}
|
|
106
|
+
/>
|
|
107
|
+
}
|
|
98
108
|
/>
|
|
99
109
|
|
|
100
110
|
<Divider />
|
|
@@ -3,7 +3,8 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { QueryClientProvider, QueryClient } from 'react-query';
|
|
4
4
|
import { LibraryProvider, StrapiAppProvider } from '@strapi/helper-plugin';
|
|
5
5
|
import { Provider } from 'react-redux';
|
|
6
|
-
import { AdminContext
|
|
6
|
+
import { AdminContext } from '../../contexts';
|
|
7
|
+
import ConfigurationsProvider from '../ConfigurationsProvider';
|
|
7
8
|
import LanguageProvider from '../LanguageProvider';
|
|
8
9
|
import GuidedTour from '../GuidedTour';
|
|
9
10
|
import AutoReloadOverlayBlockerProvider from '../AutoReloadOverlayBlockerProvider';
|
|
@@ -47,8 +48,11 @@ const Providers = ({
|
|
|
47
48
|
<QueryClientProvider client={queryClient}>
|
|
48
49
|
<Provider store={store}>
|
|
49
50
|
<AdminContext.Provider value={{ getAdminInjectedComponents }}>
|
|
50
|
-
<
|
|
51
|
-
|
|
51
|
+
<ConfigurationsProvider
|
|
52
|
+
authLogo={authLogo}
|
|
53
|
+
menuLogo={menuLogo}
|
|
54
|
+
showReleaseNotification={showReleaseNotification}
|
|
55
|
+
showTutorials={showTutorials}
|
|
52
56
|
>
|
|
53
57
|
<StrapiAppProvider
|
|
54
58
|
getPlugin={getPlugin}
|
|
@@ -71,7 +75,7 @@ const Providers = ({
|
|
|
71
75
|
</LanguageProvider>
|
|
72
76
|
</LibraryProvider>
|
|
73
77
|
</StrapiAppProvider>
|
|
74
|
-
</
|
|
78
|
+
</ConfigurationsProvider>
|
|
75
79
|
</AdminContext.Provider>
|
|
76
80
|
</Provider>
|
|
77
81
|
</QueryClientProvider>
|
|
@@ -7,9 +7,11 @@ const Img = styled.img`
|
|
|
7
7
|
`;
|
|
8
8
|
|
|
9
9
|
const Logo = () => {
|
|
10
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
logos: { auth },
|
|
12
|
+
} = useConfigurations();
|
|
11
13
|
|
|
12
|
-
return <Img src={
|
|
14
|
+
return <Img src={auth.default} aria-hidden alt="" />;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
export default Logo;
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
request,
|
|
13
13
|
useNotification,
|
|
14
14
|
TrackingContext,
|
|
15
|
+
prefixFileUrlWithBackendUrl,
|
|
15
16
|
} from '@strapi/helper-plugin';
|
|
16
17
|
import axios from 'axios';
|
|
17
18
|
import { SkipToContent } from '@strapi/design-system/Main';
|
|
@@ -23,6 +24,7 @@ import NotFoundPage from '../NotFoundPage';
|
|
|
23
24
|
import UseCasePage from '../UseCasePage';
|
|
24
25
|
import { getUID } from './utils';
|
|
25
26
|
import routes from './utils/routes';
|
|
27
|
+
import { useConfigurations } from '../../hooks';
|
|
26
28
|
|
|
27
29
|
const AuthenticatedApp = lazy(() =>
|
|
28
30
|
import(/* webpackChunkName: "Admin-authenticatedApp" */ '../../components/AuthenticatedApp')
|
|
@@ -30,6 +32,7 @@ const AuthenticatedApp = lazy(() =>
|
|
|
30
32
|
|
|
31
33
|
function App() {
|
|
32
34
|
const toggleNotification = useNotification();
|
|
35
|
+
const { updateProjectSettings } = useConfigurations();
|
|
33
36
|
const { formatMessage } = useIntl();
|
|
34
37
|
const [{ isLoading, hasAdmin, uuid }, setState] = useState({ isLoading: true, hasAdmin: false });
|
|
35
38
|
|
|
@@ -70,10 +73,12 @@ function App() {
|
|
|
70
73
|
try {
|
|
71
74
|
const {
|
|
72
75
|
data: {
|
|
73
|
-
data: { hasAdmin, uuid },
|
|
76
|
+
data: { hasAdmin, uuid, menuLogo },
|
|
74
77
|
},
|
|
75
78
|
} = await axios.get(`${strapi.backendURL}/admin/init`);
|
|
76
79
|
|
|
80
|
+
updateProjectSettings({ menuLogo: prefixFileUrlWithBackendUrl(menuLogo) });
|
|
81
|
+
|
|
77
82
|
if (uuid) {
|
|
78
83
|
const {
|
|
79
84
|
data: { data: properties },
|
|
@@ -113,7 +118,7 @@ function App() {
|
|
|
113
118
|
};
|
|
114
119
|
|
|
115
120
|
getData();
|
|
116
|
-
}, [toggleNotification]);
|
|
121
|
+
}, [toggleNotification, updateProjectSettings]);
|
|
117
122
|
|
|
118
123
|
const setHasAdmin = hasAdmin => setState(prev => ({ ...prev, hasAdmin }));
|
|
119
124
|
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React, { useReducer, forwardRef, useImperativeHandle } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { useIntl } from 'react-intl';
|
|
4
|
+
import { useTracking } from '@strapi/helper-plugin';
|
|
5
|
+
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
|
6
|
+
import { Box } from '@strapi/design-system/Box';
|
|
7
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
8
|
+
import LogoInput from '../LogoInput';
|
|
9
|
+
import { useConfigurations } from '../../../../../../hooks';
|
|
10
|
+
import reducer, { initialState } from './reducer';
|
|
11
|
+
import init from './init';
|
|
12
|
+
|
|
13
|
+
const Form = forwardRef(({ projectSettingsStored }, ref) => {
|
|
14
|
+
const { formatMessage } = useIntl();
|
|
15
|
+
const { trackUsage } = useTracking();
|
|
16
|
+
const {
|
|
17
|
+
logos: { menu },
|
|
18
|
+
} = useConfigurations();
|
|
19
|
+
const [{ menuLogo }, dispatch] = useReducer(reducer, initialState, () =>
|
|
20
|
+
init(initialState, projectSettingsStored)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const handleChangeMenuLogo = asset => {
|
|
24
|
+
dispatch({
|
|
25
|
+
type: 'SET_CUSTOM_MENU_LOGO',
|
|
26
|
+
value: asset,
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const handleResetMenuLogo = () => {
|
|
31
|
+
trackUsage('didClickResetLogo');
|
|
32
|
+
|
|
33
|
+
dispatch({
|
|
34
|
+
type: 'RESET_CUSTOM_MENU_LOGO',
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
useImperativeHandle(ref, () => ({
|
|
39
|
+
getValues: () => ({ menuLogo: menuLogo.submit }),
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Box
|
|
44
|
+
hasRadius
|
|
45
|
+
background="neutral0"
|
|
46
|
+
shadow="tableShadow"
|
|
47
|
+
paddingTop={6}
|
|
48
|
+
paddingBottom={6}
|
|
49
|
+
paddingRight={7}
|
|
50
|
+
paddingLeft={7}
|
|
51
|
+
>
|
|
52
|
+
<Typography variant="delta" as="h3">
|
|
53
|
+
{formatMessage({
|
|
54
|
+
id: 'Settings.application.customization',
|
|
55
|
+
defaultMessage: 'Customization',
|
|
56
|
+
})}
|
|
57
|
+
</Typography>
|
|
58
|
+
<Grid paddingTop={4}>
|
|
59
|
+
<GridItem col={6} s={12}>
|
|
60
|
+
<LogoInput
|
|
61
|
+
onChangeLogo={handleChangeMenuLogo}
|
|
62
|
+
customLogo={menuLogo.display}
|
|
63
|
+
defaultLogo={menu.default}
|
|
64
|
+
onResetMenuLogo={handleResetMenuLogo}
|
|
65
|
+
/>
|
|
66
|
+
</GridItem>
|
|
67
|
+
</Grid>
|
|
68
|
+
</Box>
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
Form.defaultProps = {
|
|
73
|
+
projectSettingsStored: null,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
Form.propTypes = {
|
|
77
|
+
projectSettingsStored: PropTypes.shape({
|
|
78
|
+
menuLogo: PropTypes.shape({
|
|
79
|
+
url: PropTypes.string,
|
|
80
|
+
name: PropTypes.string,
|
|
81
|
+
}),
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default Form;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import merge from 'lodash/merge';
|
|
2
|
+
|
|
3
|
+
const init = (initialState, projectSettingsStored) => {
|
|
4
|
+
const copyInitialState = merge(initialState, {
|
|
5
|
+
menuLogo: {
|
|
6
|
+
display: projectSettingsStored.menuLogo,
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
return copyInitialState;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default init;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* eslint-disable consistent-return */
|
|
2
|
+
/*
|
|
3
|
+
*
|
|
4
|
+
* ApplicationInfosPage Form reducer
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import produce from 'immer';
|
|
9
|
+
|
|
10
|
+
const initialState = {
|
|
11
|
+
menuLogo: {
|
|
12
|
+
display: null,
|
|
13
|
+
submit: {
|
|
14
|
+
rawFile: null,
|
|
15
|
+
isReset: false,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const reducer = (state = initialState, action) =>
|
|
21
|
+
produce(state, draftState => {
|
|
22
|
+
switch (action.type) {
|
|
23
|
+
case 'SET_CUSTOM_MENU_LOGO': {
|
|
24
|
+
draftState.menuLogo.display = action.value;
|
|
25
|
+
draftState.menuLogo.submit.rawFile = action.value.rawFile;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
case 'RESET_CUSTOM_MENU_LOGO': {
|
|
29
|
+
draftState.menuLogo.display = null;
|
|
30
|
+
draftState.menuLogo.submit = {
|
|
31
|
+
rawFile: null,
|
|
32
|
+
isReset: true,
|
|
33
|
+
};
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
default: {
|
|
37
|
+
return draftState;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export default reducer;
|
|
43
|
+
export { initialState };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React, { useReducer } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { CarouselInput, CarouselSlide, CarouselActions } from '@strapi/design-system/CarouselInput';
|
|
5
|
+
import { IconButton } from '@strapi/design-system/IconButton';
|
|
6
|
+
import { Box } from '@strapi/design-system/Box';
|
|
7
|
+
import Plus from '@strapi/icons/Plus';
|
|
8
|
+
import Refresh from '@strapi/icons/Refresh';
|
|
9
|
+
import reducer, { initialState } from './reducer';
|
|
10
|
+
import LogoModalStepper from '../LogoModalStepper';
|
|
11
|
+
import { SIZE, DIMENSION } from '../../utils/constants';
|
|
12
|
+
import stepper from './stepper';
|
|
13
|
+
|
|
14
|
+
const LogoInput = ({ customLogo, defaultLogo, onChangeLogo, onResetMenuLogo }) => {
|
|
15
|
+
const [{ currentStep }, dispatch] = useReducer(reducer, initialState);
|
|
16
|
+
const { Component, next, prev, modalTitle } = stepper[currentStep] || {};
|
|
17
|
+
const { formatMessage } = useIntl();
|
|
18
|
+
|
|
19
|
+
const goTo = to => {
|
|
20
|
+
dispatch({
|
|
21
|
+
type: 'GO_TO',
|
|
22
|
+
to,
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
<CarouselInput
|
|
29
|
+
label={formatMessage({
|
|
30
|
+
id: 'Settings.application.customization.carousel.title',
|
|
31
|
+
defaultMessage: 'Logo',
|
|
32
|
+
})}
|
|
33
|
+
selectedSlide={0}
|
|
34
|
+
hint={formatMessage(
|
|
35
|
+
{
|
|
36
|
+
id: 'Settings.application.customization.carousel-hint',
|
|
37
|
+
defaultMessage:
|
|
38
|
+
'Change the admin panel logo (Max dimension: {dimension}x{dimension}, Max file size: {size}KB)',
|
|
39
|
+
},
|
|
40
|
+
{ size: SIZE, dimension: DIMENSION }
|
|
41
|
+
)}
|
|
42
|
+
// Carousel is used here for a single media,
|
|
43
|
+
// we don't need previous and next labels but these props are required
|
|
44
|
+
previousLabel=""
|
|
45
|
+
nextLabel=""
|
|
46
|
+
onNext={() => {}}
|
|
47
|
+
onPrevious={() => {}}
|
|
48
|
+
secondaryLabel={customLogo?.name || 'logo.png'}
|
|
49
|
+
actions={
|
|
50
|
+
<CarouselActions>
|
|
51
|
+
<IconButton
|
|
52
|
+
onClick={() => goTo(customLogo ? 'pending' : 'upload')}
|
|
53
|
+
label={formatMessage({
|
|
54
|
+
id: 'Settings.application.customization.carousel.change-action',
|
|
55
|
+
defaultMessage: 'Change logo',
|
|
56
|
+
})}
|
|
57
|
+
icon={<Plus />}
|
|
58
|
+
/>
|
|
59
|
+
{customLogo && (
|
|
60
|
+
<IconButton
|
|
61
|
+
onClick={onResetMenuLogo}
|
|
62
|
+
label={formatMessage({
|
|
63
|
+
id: 'Settings.application.customization.carousel.reset-action',
|
|
64
|
+
defaultMessage: 'Reset logo',
|
|
65
|
+
})}
|
|
66
|
+
icon={<Refresh />}
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
</CarouselActions>
|
|
70
|
+
}
|
|
71
|
+
>
|
|
72
|
+
<CarouselSlide
|
|
73
|
+
label={formatMessage({
|
|
74
|
+
id: 'Settings.application.customization.carousel-slide.label',
|
|
75
|
+
defaultMessage: 'Logo slide',
|
|
76
|
+
})}
|
|
77
|
+
>
|
|
78
|
+
<Box
|
|
79
|
+
maxHeight="40%"
|
|
80
|
+
maxWidth="40%"
|
|
81
|
+
as="img"
|
|
82
|
+
src={customLogo?.url || defaultLogo}
|
|
83
|
+
alt={formatMessage({
|
|
84
|
+
id: 'Settings.application.customization.carousel.title',
|
|
85
|
+
defaultMessage: 'Logo',
|
|
86
|
+
})}
|
|
87
|
+
/>
|
|
88
|
+
</CarouselSlide>
|
|
89
|
+
</CarouselInput>
|
|
90
|
+
<LogoModalStepper
|
|
91
|
+
Component={Component}
|
|
92
|
+
currentStep={currentStep}
|
|
93
|
+
onChangeLogo={onChangeLogo}
|
|
94
|
+
customLogo={customLogo}
|
|
95
|
+
goTo={goTo}
|
|
96
|
+
next={next}
|
|
97
|
+
prev={prev}
|
|
98
|
+
modalTitle={modalTitle}
|
|
99
|
+
/>
|
|
100
|
+
</>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
LogoInput.defaultProps = {
|
|
105
|
+
customLogo: null,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
LogoInput.propTypes = {
|
|
109
|
+
customLogo: PropTypes.shape({
|
|
110
|
+
url: PropTypes.string,
|
|
111
|
+
name: PropTypes.string,
|
|
112
|
+
}),
|
|
113
|
+
defaultLogo: PropTypes.string.isRequired,
|
|
114
|
+
onChangeLogo: PropTypes.func.isRequired,
|
|
115
|
+
onResetMenuLogo: PropTypes.func.isRequired,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export default LogoInput;
|
package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/reducer.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* eslint-disable consistent-return */
|
|
2
|
+
/*
|
|
3
|
+
*
|
|
4
|
+
* LogoInput reducer
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import produce from 'immer';
|
|
9
|
+
|
|
10
|
+
const initialState = {
|
|
11
|
+
currentStep: undefined,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const reducer = (state = initialState, action) =>
|
|
15
|
+
produce(state, draftState => {
|
|
16
|
+
switch (action.type) {
|
|
17
|
+
case 'GO_TO': {
|
|
18
|
+
draftState.currentStep = action.to;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
default: {
|
|
22
|
+
return draftState;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export default reducer;
|
|
28
|
+
export { initialState };
|
package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/stepper.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import AddLogoDialog from '../LogoModalStepper/AddLogoDialog';
|
|
2
|
+
import PendingLogoDialog from '../LogoModalStepper/PendingLogoDialog';
|
|
3
|
+
|
|
4
|
+
const stepper = {
|
|
5
|
+
upload: {
|
|
6
|
+
Component: AddLogoDialog,
|
|
7
|
+
modalTitle: {
|
|
8
|
+
id: 'Settings.application.customization.modal.upload',
|
|
9
|
+
defaultMessage: 'Upload logo',
|
|
10
|
+
},
|
|
11
|
+
next: 'pending',
|
|
12
|
+
prev: null,
|
|
13
|
+
},
|
|
14
|
+
pending: {
|
|
15
|
+
Component: PendingLogoDialog,
|
|
16
|
+
modalTitle: {
|
|
17
|
+
id: 'Settings.application.customization.modal.pending',
|
|
18
|
+
defaultMessage: 'Pending logo',
|
|
19
|
+
},
|
|
20
|
+
next: null,
|
|
21
|
+
prev: 'upload',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default stepper;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { Tabs, Tab, TabGroup, TabPanels, TabPanel } from '@strapi/design-system/Tabs';
|
|
5
|
+
import { Box } from '@strapi/design-system/Box';
|
|
6
|
+
import { Divider } from '@strapi/design-system/Divider';
|
|
7
|
+
import FromComputerForm from './FromComputerForm';
|
|
8
|
+
import FromUrlForm from './FromUrlForm';
|
|
9
|
+
|
|
10
|
+
const AddLogoDialog = ({ setLocalImage, goTo, next, onClose }) => {
|
|
11
|
+
const { formatMessage } = useIntl();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<TabGroup
|
|
15
|
+
label={formatMessage({
|
|
16
|
+
id: 'Settings.application.customization.modal.tab.label',
|
|
17
|
+
defaultMessage: 'How do you want to upload your assets?',
|
|
18
|
+
})}
|
|
19
|
+
variant="simple"
|
|
20
|
+
>
|
|
21
|
+
<Box paddingLeft={8} paddingRight={8}>
|
|
22
|
+
<Tabs>
|
|
23
|
+
<Tab>
|
|
24
|
+
{formatMessage({
|
|
25
|
+
id: 'Settings.application.customization.modal.upload.from-computer',
|
|
26
|
+
defaultMessage: 'From computer',
|
|
27
|
+
})}
|
|
28
|
+
</Tab>
|
|
29
|
+
<Tab>
|
|
30
|
+
{formatMessage({
|
|
31
|
+
id: 'Settings.application.customization.modal.upload.from-url',
|
|
32
|
+
defaultMessage: 'From url',
|
|
33
|
+
})}
|
|
34
|
+
</Tab>
|
|
35
|
+
</Tabs>
|
|
36
|
+
|
|
37
|
+
<Divider />
|
|
38
|
+
</Box>
|
|
39
|
+
<TabPanels>
|
|
40
|
+
<TabPanel>
|
|
41
|
+
<FromComputerForm
|
|
42
|
+
onClose={onClose}
|
|
43
|
+
setLocalImage={setLocalImage}
|
|
44
|
+
goTo={goTo}
|
|
45
|
+
next={next}
|
|
46
|
+
/>
|
|
47
|
+
</TabPanel>
|
|
48
|
+
<TabPanel>
|
|
49
|
+
<FromUrlForm onClose={onClose} setLocalImage={setLocalImage} goTo={goTo} next={next} />
|
|
50
|
+
</TabPanel>
|
|
51
|
+
</TabPanels>
|
|
52
|
+
</TabGroup>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
AddLogoDialog.defaultProps = {
|
|
57
|
+
next: null,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
AddLogoDialog.propTypes = {
|
|
61
|
+
goTo: PropTypes.func.isRequired,
|
|
62
|
+
next: PropTypes.string,
|
|
63
|
+
onClose: PropTypes.func.isRequired,
|
|
64
|
+
setLocalImage: PropTypes.func.isRequired,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default AddLogoDialog;
|