@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.
Files changed (89) hide show
  1. package/admin/src/components/ConfigurationsProvider/index.js +51 -0
  2. package/admin/src/components/ConfigurationsProvider/reducer.js +28 -0
  3. package/admin/src/components/LeftMenu/index.js +12 -2
  4. package/admin/src/components/Providers/index.js +8 -4
  5. package/admin/src/components/UnauthenticatedLogo/index.js +4 -2
  6. package/admin/src/pages/App/index.js +7 -2
  7. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/Form/index.js +85 -0
  8. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/Form/init.js +13 -0
  9. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/Form/reducer.js +43 -0
  10. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/index.js +118 -0
  11. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/reducer.js +28 -0
  12. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoInput/stepper.js +25 -0
  13. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/AddLogoDialog.js +67 -0
  14. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/FromComputerForm.js +176 -0
  15. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/FromUrlForm.js +82 -0
  16. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/ImageCardAsset.js +51 -0
  17. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/PendingLogoDialog.js +97 -0
  18. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/index.js +85 -0
  19. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/reducer.js +28 -0
  20. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +153 -91
  21. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +16 -0
  22. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/constants.js +3 -0
  23. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/getFormData.js +17 -0
  24. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/parseFileMetadatas.js +76 -0
  25. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +17 -0
  26. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/urlToFile.js +21 -0
  27. package/admin/src/translations/en.json +26 -0
  28. package/build/1541.6c1c96f9.chunk.js +307 -0
  29. package/build/3214.9196aeff.chunk.js +235 -0
  30. package/build/3865.21cec9de.chunk.js +310 -0
  31. package/build/{4073.41ac1235.chunk.js → 4073.e144a91a.chunk.js} +1 -1
  32. package/build/{210.014495c1.chunk.js → 472.0350a5bd.chunk.js} +32 -32
  33. package/build/4800.d3ebc81d.chunk.js +1 -0
  34. package/build/4982.f53b78a4.chunk.js +308 -0
  35. package/build/7351.b95e65ae.chunk.js +428 -0
  36. package/build/7418.6db737ce.chunk.js +112 -0
  37. package/build/8826.58e236d4.chunk.js +1057 -0
  38. package/build/9066.118ecccd.chunk.js +101 -0
  39. package/build/{7191.3bde3cbf.chunk.js → 9298.aff28744.chunk.js} +85 -86
  40. package/build/948.d64fb515.chunk.js +2 -0
  41. package/build/9988.f84412d9.chunk.js +162 -0
  42. package/build/Admin-authenticatedApp.162a5805.chunk.js +80 -0
  43. package/build/{Admin_homePage.f157e33e.chunk.js → Admin_homePage.0ac648e8.chunk.js} +2 -2
  44. package/build/Admin_marketplace.0bb91ec8.chunk.js +11 -0
  45. package/build/{Admin_profilePage.62c203ad.chunk.js → Admin_profilePage.27191ed2.chunk.js} +1 -1
  46. package/build/Admin_settingsPage.23e873f0.chunk.js +178 -0
  47. package/build/{admin-edit-roles-page.94e1403b.chunk.js → admin-edit-roles-page.fb374555.chunk.js} +1 -1
  48. package/build/admin-edit-users.a360deaf.chunk.js +10 -0
  49. package/build/admin-users.47d06d24.chunk.js +11 -0
  50. package/build/api-tokens-create-page.698f132d.chunk.js +1 -0
  51. package/build/api-tokens-edit-page.afece2fe.chunk.js +1 -0
  52. package/build/{api-tokens-list-page.340750a6.chunk.js → api-tokens-list-page.46d96dee.chunk.js} +1 -1
  53. package/build/{content-manager.6cdcfb6e.chunk.js → content-manager.7cd28f84.chunk.js} +14 -14
  54. package/build/{content-type-builder.e73879b9.chunk.js → content-type-builder.7456cabe.chunk.js} +10 -10
  55. package/build/en-json.40ee00aa.chunk.js +1 -0
  56. package/build/index.html +1 -1
  57. package/build/main.b632a0d6.js +11625 -0
  58. package/build/runtime~main.38d418e9.js +2 -0
  59. package/build/{sso-settings-page.e9034e22.chunk.js → sso-settings-page.dfb0b917.chunk.js} +1 -1
  60. package/build/webhook-edit-page.a7ae6e3b.chunk.js +23 -0
  61. package/build/webhook-list-page.83297d98.chunk.js +133 -0
  62. package/package.json +7 -7
  63. package/server/config/admin-actions.js +14 -0
  64. package/server/controllers/admin.js +33 -1
  65. package/server/routes/admin.js +28 -0
  66. package/server/services/index.js +1 -0
  67. package/server/services/project-settings.js +173 -0
  68. package/server/utils/index.d.ts +2 -0
  69. package/server/validation/project-settings.js +39 -0
  70. package/build/1709.ceed0e18.chunk.js +0 -503
  71. package/build/20.cf744c35.chunk.js +0 -308
  72. package/build/2135.95ee6de1.chunk.js +0 -162
  73. package/build/2524.688d0355.chunk.js +0 -1
  74. package/build/4761.3eabdf46.chunk.js +0 -101
  75. package/build/6281.f10a7e3a.chunk.js +0 -1
  76. package/build/7009.79fce86d.chunk.js +0 -164
  77. package/build/7863.bc7a8f3a.chunk.js +0 -112
  78. package/build/Admin-authenticatedApp.4ce8d292.chunk.js +0 -80
  79. package/build/Admin_marketplace.1e3393c9.chunk.js +0 -11
  80. package/build/Admin_settingsPage.924a7816.chunk.js +0 -170
  81. package/build/admin-edit-users.6c2bf718.chunk.js +0 -10
  82. package/build/admin-users.e03db115.chunk.js +0 -11
  83. package/build/api-tokens-create-page.787ab302.chunk.js +0 -1
  84. package/build/api-tokens-edit-page.e4010c0c.chunk.js +0 -1
  85. package/build/en-json.3e1a222e.chunk.js +0 -1
  86. package/build/main.45472ea9.js +0 -8404
  87. package/build/runtime~main.e7611418.js +0 -2
  88. package/build/webhook-edit-page.2fa94db3.chunk.js +0 -23
  89. 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 { menuLogo } = useConfigurations();
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={<img src={menuLogo} alt={menuTitle} />}
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, ConfigurationsContext } from '../../contexts';
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
- <ConfigurationsContext.Provider
51
- value={{ authLogo, menuLogo, showReleaseNotification, showTutorials }}
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
- </ConfigurationsContext.Provider>
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 { authLogo } = useConfigurations();
10
+ const {
11
+ logos: { auth },
12
+ } = useConfigurations();
11
13
 
12
- return <Img src={authLogo} aria-hidden alt="" />;
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;
@@ -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 };
@@ -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;