@localazy/strapi-plugin 0.1.0

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 (150) hide show
  1. package/.babelrc +7 -0
  2. package/.eslintrc +7 -0
  3. package/.github/workflows/.build.yml +39 -0
  4. package/.nvmrc +1 -0
  5. package/LICENSE +21 -0
  6. package/README.md +40 -0
  7. package/admin/src/.eslintrc +3 -0
  8. package/admin/src/components/Initializer/index.js +26 -0
  9. package/admin/src/components/PluginIcon/index.js +14 -0
  10. package/admin/src/i18n.js +37 -0
  11. package/admin/src/index.js +106 -0
  12. package/admin/src/modules/@common/components/Icons/Localazy/index.js +12 -0
  13. package/admin/src/modules/@common/components/SideNav/index.js +46 -0
  14. package/admin/src/modules/@common/components/TransferReport/index.js +54 -0
  15. package/admin/src/modules/@common/locale/en.js +13 -0
  16. package/admin/src/modules/@common/services/i18n-service.js +15 -0
  17. package/admin/src/modules/@common/services/project-service.js +15 -0
  18. package/admin/src/modules/@common/services/user-service.js +38 -0
  19. package/admin/src/modules/@common/utils/are-locales-compatible.js +42 -0
  20. package/admin/src/modules/@common/utils/functions/flatten-deep.js +23 -0
  21. package/admin/src/modules/@common/utils/get-default-locale.js +32 -0
  22. package/admin/src/modules/@common/utils/get-header-subtitle.js +21 -0
  23. package/admin/src/modules/@common/utils/get-header-title.js +24 -0
  24. package/admin/src/modules/@common/utils/get-nav.js +35 -0
  25. package/admin/src/modules/@common/utils/history.js +6 -0
  26. package/admin/src/modules/@common/utils/is-plugin-route.js +15 -0
  27. package/admin/src/modules/@common/utils/iso-locales-utils.js +15 -0
  28. package/admin/src/modules/@common/utils/redirect-to-plugin-route.js +22 -0
  29. package/admin/src/modules/@common/utils/sort-by-model-name.js +10 -0
  30. package/admin/src/modules/localazy-download/locale/en.js +20 -0
  31. package/admin/src/modules/localazy-download/services/localazy-download-service.js +16 -0
  32. package/admin/src/modules/localazy-upload/components/ReadDocsButton.js +21 -0
  33. package/admin/src/modules/localazy-upload/locale/en.js +18 -0
  34. package/admin/src/modules/localazy-upload/services/localazy-upload-service.js +16 -0
  35. package/admin/src/modules/login/components/LoginButton/index.js +56 -0
  36. package/admin/src/modules/login/components/LogoutButton/index.js +50 -0
  37. package/admin/src/modules/login/locale/en.js +7 -0
  38. package/admin/src/modules/login/services/localazy-login-service.js +29 -0
  39. package/admin/src/modules/plugin-settings/components/ContentTransferSetup/index.js +292 -0
  40. package/admin/src/modules/plugin-settings/components/Tree/index.js +120 -0
  41. package/admin/src/modules/plugin-settings/components/TreeItem/index.js +48 -0
  42. package/admin/src/modules/plugin-settings/functions/build-content-transfer-setup-schema.js +71 -0
  43. package/admin/src/modules/plugin-settings/functions/has-model-changed.js +85 -0
  44. package/admin/src/modules/plugin-settings/locale/en.js +19 -0
  45. package/admin/src/modules/plugin-settings/services/plugin-settings-service.js +32 -0
  46. package/admin/src/modules/plugin-settings/services/strapi-model-service.js +26 -0
  47. package/admin/src/modules/plugin-settings/utils/__tests__/get-models-tree.test.js +135 -0
  48. package/admin/src/modules/plugin-settings/utils/array-of-models-to-object.js +6 -0
  49. package/admin/src/modules/plugin-settings/utils/find-model-value-by-key.js +8 -0
  50. package/admin/src/modules/plugin-settings/utils/get-filtered-models-schemas.js +34 -0
  51. package/admin/src/modules/plugin-settings/utils/get-models-tree.js +73 -0
  52. package/admin/src/modules/settings/components/OverviewItem/index.js +44 -0
  53. package/admin/src/modules/settings/components/OverviewItemLink/index.js +34 -0
  54. package/admin/src/modules/settings/components/PrerequisitiesInfo/index.js +30 -0
  55. package/admin/src/modules/settings/locale/en.js +13 -0
  56. package/admin/src/modules/user/model/localazy-identity.js +14 -0
  57. package/admin/src/modules/user/services/localazy-user-service.js +38 -0
  58. package/admin/src/pages/App/index.js +152 -0
  59. package/admin/src/pages/Download/index.js +179 -0
  60. package/admin/src/pages/Index/index.js +8 -0
  61. package/admin/src/pages/Login/index.js +94 -0
  62. package/admin/src/pages/PluginSettings/index.js +42 -0
  63. package/admin/src/pages/Settings/index.js +120 -0
  64. package/admin/src/pages/Upload/index.js +187 -0
  65. package/admin/src/pluginId.js +5 -0
  66. package/admin/src/plugins/apolloClient.js +33 -0
  67. package/admin/src/state/localazy-identity.js +29 -0
  68. package/admin/src/tests/fixtures/all-models.js +877 -0
  69. package/admin/src/tests/fixtures/restaurant-model.js +230 -0
  70. package/admin/src/translations/en.json +4 -0
  71. package/admin/src/translations/fr.json +1 -0
  72. package/admin/src/utils/createAxiosInstance.js +52 -0
  73. package/admin/src/utils/getTrad.js +5 -0
  74. package/jest.config.js +0 -0
  75. package/package.json +60 -0
  76. package/server/bootstrap.js +5 -0
  77. package/server/config/development/index.js +15 -0
  78. package/server/config/example/index.js +15 -0
  79. package/server/config/index.js +15 -0
  80. package/server/config/production/index.js +16 -0
  81. package/server/config/schema.graphql.js +21 -0
  82. package/server/content-types/index.js +3 -0
  83. package/server/controllers/index.js +19 -0
  84. package/server/controllers/localazy-auth-controller.js +46 -0
  85. package/server/controllers/localazy-project-controller.js +21 -0
  86. package/server/controllers/localazy-transfer-controller.js +469 -0
  87. package/server/controllers/localazy-user-controller.js +24 -0
  88. package/server/controllers/my-controller.js +10 -0
  89. package/server/controllers/plugin-settings-controller.js +17 -0
  90. package/server/controllers/strapi-controller.js +16 -0
  91. package/server/db/model/content-transfer-setup.js +13 -0
  92. package/server/db/model/localazy-user.js +23 -0
  93. package/server/db/model/utils/get-strapi-store.js +9 -0
  94. package/server/destroy.js +5 -0
  95. package/server/index.js +25 -0
  96. package/server/middlewares/index.js +3 -0
  97. package/server/policies/index.js +3 -0
  98. package/server/register.js +5 -0
  99. package/server/routes/index.js +26 -0
  100. package/server/routes/localazy-auth.js +22 -0
  101. package/server/routes/localazy-project.js +14 -0
  102. package/server/routes/localazy-transfer.js +22 -0
  103. package/server/routes/localazy-user.js +30 -0
  104. package/server/routes/plugin-settings.js +22 -0
  105. package/server/routes/strapi.js +22 -0
  106. package/server/services/index.js +21 -0
  107. package/server/services/localazy-auth-service.js +38 -0
  108. package/server/services/localazy-download-service.js +54 -0
  109. package/server/services/localazy-pubapi-service.js +47 -0
  110. package/server/services/localazy-upload-service.js +95 -0
  111. package/server/services/localazy-user-service.js +29 -0
  112. package/server/services/plugin-settings-service.js +30 -0
  113. package/server/services/strapi-i18n-service.js +132 -0
  114. package/server/services/strapi-service.js +23 -0
  115. package/server/tests/fixtures/all-models-with-multimedia.js +1064 -0
  116. package/server/tests/fixtures/all-models.js +869 -0
  117. package/server/tests/fixtures/collection-flattened.js +76 -0
  118. package/server/tests/fixtures/restaurant-flattened.js +46 -0
  119. package/server/tests/fixtures/restaurant-model.js +230 -0
  120. package/server/tests/fixtures/restaurants-entries.js +152 -0
  121. package/server/tests/fixtures/restaurants-pick-paths.js +15 -0
  122. package/server/tests/fixtures/strapi-book-with-multimedia-components-cs.js +31 -0
  123. package/server/tests/fixtures/stringified-book-cs.js +3 -0
  124. package/server/tests/fixtures/stringified-book-with-multimedia-components-cs.js +3 -0
  125. package/server/tests/fixtures/stringified-restaurant-cs.js +3 -0
  126. package/server/tests/fixtures/stringified-restaurant-de.js +5 -0
  127. package/server/utils/__tests__/build-populate.test.js +85 -0
  128. package/server/utils/__tests__/flatten-object.test.js +171 -0
  129. package/server/utils/__tests__/get-models-tree.test.js +170 -0
  130. package/server/utils/__tests__/parsed-localazy-entry-to-create-entry.test.js +153 -0
  131. package/server/utils/__tests__/parsed-localazy-entry-to-update-entry.test.js +172 -0
  132. package/server/utils/__tests__/pick-entries.test.js +83 -0
  133. package/server/utils/build-populate.js +43 -0
  134. package/server/utils/delay.js +6 -0
  135. package/server/utils/flatten-object.js +52 -0
  136. package/server/utils/get-localazy-api.js +22 -0
  137. package/server/utils/get-main-keys-of-nested-array-objects.js +5 -0
  138. package/server/utils/get-models-tree.js +43 -0
  139. package/server/utils/intl-display-name.js +7 -0
  140. package/server/utils/is-generally-applicable-content-type.js +33 -0
  141. package/server/utils/is-localazy-applicable-content-type.js +36 -0
  142. package/server/utils/iso-locales-utils.js +22 -0
  143. package/server/utils/objectivise-entry.js +41 -0
  144. package/server/utils/omit-deep.js +17 -0
  145. package/server/utils/parsed-localazy-entry-to-create-entry.js +115 -0
  146. package/server/utils/parsed-localazy-entry-to-update-entry.js +31 -0
  147. package/server/utils/pick-entries.js +14 -0
  148. package/server/utils/transfer-setup-utils.js +39 -0
  149. package/strapi-admin.js +14 -0
  150. package/strapi-server.js +5 -0
@@ -0,0 +1,120 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import PropTypes from "prop-types";
3
+ import { Loader } from "@strapi/design-system/Loader";
4
+ import { HeaderLayout } from "@strapi/design-system/Layout";
5
+ import { Box } from "@strapi/design-system/Box";
6
+ import { useHistory } from "react-router-dom";
7
+ import { useTranslation } from "react-i18next";
8
+ import { Grid } from '@strapi/design-system/Grid';
9
+ import { Divider } from '@strapi/design-system/Divider';
10
+ import LogoutButton from "../../modules/login/components/LogoutButton";
11
+ import redirectToPluginRoute, {
12
+ PLUGIN_ROUTES,
13
+ } from "../../modules/@common/utils/redirect-to-plugin-route";
14
+ import { getLocalazyIdentity } from "../../state/localazy-identity";
15
+ import OverviewItem from "../../modules/settings/components/OverviewItem";
16
+ import OverviewItemLink from "../../modules/settings/components/OverviewItemLink";
17
+ import PrerequisitiesInfo from "../../modules/settings/components/PrerequisitiesInfo";
18
+ import ProjectService from "../../modules/@common/services/project-service";
19
+
20
+ import "../../i18n";
21
+
22
+ function Settings(props) {
23
+ const history = useHistory();
24
+ const { t } = useTranslation();
25
+
26
+ const [isLoading, setIsLoading] = useState(true);
27
+
28
+ const [localazyIdentity] = getLocalazyIdentity();
29
+ const projectUrl = localazyIdentity.project.url;
30
+
31
+ const [connectedProject, setConnectedProject] = useState({});
32
+
33
+ useEffect(() => {
34
+ async function initComponent() {
35
+ setIsLoading(true);
36
+ const project = await ProjectService.getConnectedProject();
37
+ setConnectedProject(project);
38
+ setIsLoading(false);
39
+ }
40
+
41
+ initComponent();
42
+ }, []);
43
+
44
+ /**
45
+ * On logout action
46
+ */
47
+ const onLoggedOut = () => {
48
+ redirectToPluginRoute(PLUGIN_ROUTES.LOGIN, history);
49
+ };
50
+
51
+ return (
52
+ <>
53
+ <HeaderLayout
54
+ title={props.title}
55
+ subtitle={props.subtitle}
56
+ primaryAction={<LogoutButton onResultFetched={onLoggedOut} />}
57
+ as="h2"
58
+ />
59
+ {(props.isLoading || isLoading) && (<Loader>{t("common.loading_content")}</Loader>)}
60
+ {!(props.isLoading || isLoading) && (
61
+ <Box paddingRight={10} paddingLeft={10}>
62
+ <Box
63
+ background="neutral0"
64
+ paddingTop={6}
65
+ paddingRight={7}
66
+ paddingBottom={6}
67
+ paddingLeft={7}
68
+ hasRadius
69
+ shadow="tableShadow"
70
+ >
71
+ <Grid
72
+ gap={{
73
+ desktop: 5,
74
+ tablet: 2,
75
+ mobile: 1
76
+ }}
77
+ >
78
+ <OverviewItem
79
+ label={t("settings.connected_user")}
80
+ value={localazyIdentity.user.name}
81
+ />
82
+ <OverviewItem
83
+ label={t("settings.connected_project")}
84
+ value={localazyIdentity.project.name}
85
+ />
86
+ <OverviewItem
87
+ label={t("settings.remaining_organization_keys")}
88
+ value={
89
+ connectedProject.organization.availableKeys - connectedProject.organization.usedKeys
90
+ }
91
+ />
92
+ <OverviewItemLink
93
+ label={t("settings.open_project_in_localazy")}
94
+ to={projectUrl}
95
+ />
96
+ </Grid>
97
+ <Box
98
+ paddingTop={4}
99
+ paddingBottom={4}
100
+ >
101
+ <Divider />
102
+ </Box>
103
+ <PrerequisitiesInfo />
104
+ </Box>
105
+ </Box>)}
106
+ </>
107
+ );
108
+ }
109
+
110
+ Settings.propTypes = {
111
+ title: PropTypes.string.isRequired,
112
+ subtitle: PropTypes.string.isRequired,
113
+ isLoading: PropTypes.bool,
114
+ };
115
+
116
+ Settings.defaultProps = {
117
+ isLoading: false,
118
+ };
119
+
120
+ export default Settings;
@@ -0,0 +1,187 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import PropTypes from "prop-types";
3
+ import { HeaderLayout } from "@strapi/design-system/Layout";
4
+ import { useTranslation } from "react-i18next";
5
+ import { Grid } from '@strapi/design-system/Grid';
6
+ import { Flex } from '@strapi/design-system/Flex';
7
+ import { Divider } from '@strapi/design-system/Divider';
8
+ import { Button } from "@strapi/design-system/Button";
9
+ import UploadIcon from "@strapi/icons/Upload";
10
+ import { Box } from "@strapi/design-system/Box";
11
+ import { Alert } from "@strapi/design-system/Alert";
12
+ import { Loader } from "@strapi/design-system/Loader";
13
+ import LocalazyUploadService from "../../modules/localazy-upload/services/localazy-upload-service";
14
+ import areLocalesCompatible from "../../modules/@common/utils/are-locales-compatible";
15
+ import { getStrapiDefaultLocale, getLocalazySourceLanguage } from "../../modules/@common/utils/get-default-locale";
16
+ import hasModelChanged from "../../modules/plugin-settings/functions/has-model-changed";
17
+ import TransferReport from "../../modules/@common/components/TransferReport";
18
+ import OverviewItem from "../../modules/settings/components/OverviewItem";
19
+ import PrerequisitiesInfo from "../../modules/settings/components/PrerequisitiesInfo";
20
+ import ReadDocsButton from "../../modules/localazy-upload/components/ReadDocsButton";
21
+ import redirectToPluginRoute, {
22
+ PLUGIN_ROUTES,
23
+ } from "../../modules/@common/utils/redirect-to-plugin-route";
24
+
25
+ import "../../i18n";
26
+
27
+ function Upload(props) {
28
+ const { t } = useTranslation();
29
+
30
+ /**
31
+ * Component state
32
+ */
33
+ const [isLoading, setIsLoading] = useState(true);
34
+ const [modelChanged, setModelChanged] = useState(false);
35
+ const [localesIncompatible, setLocalesIncompatible] = useState(false);
36
+ const [showUploadFinishedModal, setShowUploadFinishedModal] = useState(false);
37
+ const [uploadResult, setUploadResult] = useState({});
38
+ const [isUploading, setIsUploading] = useState(false);
39
+ const [strapiDefaultLocale, setStrapiDefaultLocale] = useState(null);
40
+ const [localazySourceLanguage, setLocalazySourceLanguage] = useState(null);
41
+
42
+ const onChangeSettingsClick = () => {
43
+ redirectToPluginRoute(PLUGIN_ROUTES.CONTENT_TRANSFER_SETUP);
44
+ // hacky solution, otherwise the route contents won't be instantiated
45
+ window.location.reload();
46
+ };
47
+
48
+ const onUploadClick = async () => {
49
+ setIsUploading(true);
50
+ const result = await LocalazyUploadService.upload();
51
+ setUploadResult(result);
52
+ setIsUploading(false);
53
+ setShowUploadFinishedModal(true);
54
+ };
55
+
56
+ useEffect(() => {
57
+ async function initComponent() {
58
+ setIsLoading(true);
59
+
60
+ setStrapiDefaultLocale(await getStrapiDefaultLocale());
61
+ setLocalazySourceLanguage(await getLocalazySourceLanguage());
62
+
63
+ /**
64
+ * Handle alerts onload apperance
65
+ */
66
+ setModelChanged(await hasModelChanged());
67
+ setLocalesIncompatible(!(await areLocalesCompatible(strapiDefaultLocale, localazySourceLanguage)));
68
+
69
+ setIsLoading(false);
70
+ }
71
+ initComponent();
72
+
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ }, []);
75
+
76
+ return (
77
+ <>
78
+ <HeaderLayout
79
+ title={props.title}
80
+ subtitle={props.subtitle}
81
+ primaryAction={<Button
82
+ startIcon={<UploadIcon />}
83
+ disabled={isLoading || modelChanged || localesIncompatible}
84
+ loading={isUploading}
85
+ onClick={onUploadClick}
86
+ >
87
+ {t("upload.upload_to_localazy")}
88
+ </Button>}
89
+ as="h2"
90
+ />
91
+ {isLoading && <Loader>{t("common.loading_content")}</Loader>}
92
+ {!isLoading && (
93
+ <Box paddingRight={10} paddingLeft={10}>
94
+ <Box
95
+ background="neutral0"
96
+ paddingTop={6}
97
+ paddingRight={7}
98
+ paddingBottom={6}
99
+ paddingLeft={7}
100
+ hasRadius
101
+ shadow="tableShadow"
102
+ >
103
+ <Grid
104
+ gap={{
105
+ desktop: 5,
106
+ tablet: 2,
107
+ mobile: 1
108
+ }}
109
+ >
110
+ <OverviewItem
111
+ label={t("upload.default_strapi_language")}
112
+ value={strapiDefaultLocale.name}
113
+ />
114
+ <OverviewItem
115
+ label={t("upload.localazy_source_language")}
116
+ value={localazySourceLanguage.name}
117
+ />
118
+ </Grid>
119
+ <Box
120
+ paddingTop={4}
121
+ paddingBottom={4}
122
+ >
123
+ <Divider />
124
+ </Box>
125
+ <PrerequisitiesInfo />
126
+ <Box marginTop={4}>
127
+ <Flex gap="2">
128
+ <Button variant="secondary" onClick={onChangeSettingsClick}>
129
+ {t("upload.change_settings")}
130
+ </Button>
131
+ <ReadDocsButton />
132
+ </Flex>
133
+ </Box>
134
+ </Box>
135
+ {showUploadFinishedModal && (
136
+ <Box marginTop={4} marginBottom={4}>
137
+ <Alert
138
+ onClose={() => setShowUploadFinishedModal(false)}
139
+ closeLabel={t("upload.close")}
140
+ title={t("upload.upload_result")}
141
+ variant={uploadResult.success ? "success" : "danger"}
142
+ >
143
+ {uploadResult.success
144
+ ? t("upload.upload_success")
145
+ : t("upload.upload_failed")}
146
+ </Alert>
147
+ </Box>
148
+ )}
149
+ {localesIncompatible && (
150
+ <Box marginTop={4} marginBottom={4}>
151
+ <Alert
152
+ onClose={() => setLocalesIncompatible(false)}
153
+ closeLabel={t("upload.close")}
154
+ title={t("upload.languages_incompatible")}
155
+ variant="danger"
156
+ >
157
+ {t("upload.languages_incompatible_message")}
158
+ </Alert>
159
+ </Box>
160
+ )}
161
+ {modelChanged && (
162
+ <Box marginTop={4} marginBottom={4}>
163
+ <Alert
164
+ onClose={() => setModelChanged(false)}
165
+ closeLabel={t("upload.close")}
166
+ title={t("upload.content_types_model_changed")}
167
+ variant="default"
168
+ >
169
+ {t("upload.please_update_your_content")}
170
+ </Alert>
171
+ </Box>
172
+ )}
173
+ {uploadResult.report && uploadResult.report.length > 0 && (
174
+ <TransferReport report={uploadResult.report} />
175
+ )}
176
+ </Box>
177
+ )}
178
+ </>
179
+ );
180
+ }
181
+
182
+ Upload.propTypes = {
183
+ title: PropTypes.string.isRequired,
184
+ subtitle: PropTypes.string.isRequired,
185
+ };
186
+
187
+ export default Upload;
@@ -0,0 +1,5 @@
1
+ const pluginPkg = require('../../package.json');
2
+
3
+ const pluginId = pluginPkg.strapi.name;
4
+
5
+ module.exports = pluginId;
@@ -0,0 +1,33 @@
1
+ import {
2
+ ApolloClient,
3
+ HttpLink,
4
+ ApolloLink,
5
+ InMemoryCache,
6
+ } from "@apollo/client";
7
+ import Cookies from "js-cookie";
8
+
9
+ const createClient = () => {
10
+ const httpLink = new HttpLink({ uri: process.env.STRAPI_ADMIN_GRAPHQL_URL });
11
+
12
+ const authLink = new ApolloLink((operation, forward) => {
13
+ // Retrieve the authorization token from local storage.
14
+ const token = Cookies.get('LOCALAZY-API-USER-JWT');
15
+
16
+ // Use the setContext method to set the HTTP headers.
17
+ operation.setContext({
18
+ headers: {
19
+ 'Authorization': token ? `Bearer ${token}` : ''
20
+ }
21
+ });
22
+
23
+ // Call the next link in the middleware chain.
24
+ return forward(operation);
25
+ });
26
+
27
+ return new ApolloClient({
28
+ link: authLink.concat(httpLink),
29
+ cache: new InMemoryCache()
30
+ });
31
+ }
32
+
33
+ export default createClient;
@@ -0,0 +1,29 @@
1
+ import { createGlobalState } from "react-hooks-global-state";
2
+ import { emptyIdentity } from "../modules/user/model/localazy-identity";
3
+
4
+ const STATE_NAME = "localazyIdentity";
5
+ const { setGlobalState, useGlobalState } = createGlobalState({
6
+ [STATE_NAME]: emptyIdentity,
7
+ });
8
+
9
+ const setLocalazyIdentity = (identity = emptyIdentity) => {
10
+ setGlobalState(STATE_NAME, () => identity);
11
+ };
12
+
13
+ const getLocalazyIdentity = () => {
14
+ // eslint-disable-next-line react-hooks/rules-of-hooks
15
+ return useGlobalState(STATE_NAME);
16
+ };
17
+
18
+ const hasLocalazyIdentity = () => {
19
+ const identity = getLocalazyIdentity();
20
+
21
+ return !!identity.accessToken;
22
+ };
23
+
24
+ export {
25
+ STATE_NAME,
26
+ getLocalazyIdentity,
27
+ setLocalazyIdentity,
28
+ hasLocalazyIdentity,
29
+ };