@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, { useState } from "react";
2
+ import PropTypes from "prop-types";
3
+ import { Box } from "@strapi/design-system/Box";
4
+ import { Switch } from '@strapi/design-system/Switch';
5
+ import { Checkbox } from '@strapi/design-system/Checkbox';
6
+ import { Accordion, AccordionToggle, AccordionContent } from '@strapi/design-system/Accordion';
7
+ import TreeItem from "../TreeItem";
8
+ import flattenObject from "../../../@common/utils/functions/flatten-deep";
9
+
10
+ function Tree(props) {
11
+ const [isExpanded, setIsExpanded] = useState(false);
12
+ const onTreeItemClick = (key, currentValue) => {
13
+ props.onTreeItemClick(key, currentValue);
14
+ };
15
+
16
+ const createTree = (name, branch, path = "") => {
17
+ const isBranchObject = typeof branch === "object" && branch !== null;
18
+
19
+ if (isBranchObject) {
20
+ return (
21
+ <>
22
+ {Object.entries(branch).map(([key, value]) => {
23
+ const isSubbranchObject = typeof value === "object" && value !== null;
24
+ const flattened = flattenObject(value);
25
+ const flattenedKeys = Object.keys(flattened).map((k) => `${path}.${key}.${k}`);
26
+
27
+ const hasTruthyValue = Object.values(flattened).some(v => v);
28
+ const hasFalsyValue = Object.values(flattened).some(v => !v && v !== null);
29
+
30
+ if (key === "__model__") {
31
+ return false;
32
+ }
33
+ const passedKey = `${path}.${key}`;
34
+
35
+ return (
36
+ <Box
37
+ key={passedKey}
38
+ marginTop={6}
39
+ marginBottom={6}
40
+ marginLeft={6}
41
+ >
42
+ {isSubbranchObject && (
43
+ <Checkbox
44
+ checked={hasTruthyValue && !hasFalsyValue}
45
+ indeterminate={hasTruthyValue && hasFalsyValue}
46
+ onChange={() => onTreeItemClick(flattenedKeys, hasTruthyValue && !hasFalsyValue)}
47
+ >
48
+ {key || "-"}
49
+ </Checkbox>)
50
+ }
51
+ <TreeItem
52
+ onTreeItemClick={onTreeItemClick}
53
+ passedKey={passedKey}
54
+ >
55
+ {createTree(key, value, passedKey)}
56
+ </TreeItem>
57
+ </Box>
58
+ );
59
+ })}
60
+ </>
61
+ );
62
+ }
63
+
64
+ return (
65
+ <TreeItem
66
+ onTreeItemClick={onTreeItemClick}
67
+ key={path}
68
+ passedKey={path}
69
+ label={name}
70
+ value={branch}
71
+ />
72
+ );
73
+ };
74
+
75
+ return (
76
+ <Box>
77
+ {Object.entries(props.objects).map(([key, value]) => {
78
+ return (
79
+ value.__model__ !== undefined && (
80
+ <Box borderColor="neutral200" hasRadius>
81
+ <Accordion
82
+ size="S"
83
+ expanded={isExpanded}
84
+ onToggle={() => { setIsExpanded(!isExpanded) }}
85
+ >
86
+ <AccordionToggle
87
+ variant="secondary"
88
+ title={key}
89
+ togglePosition="left"
90
+ action={
91
+ <Switch
92
+ label={`switch_tree_${key}`}
93
+ onChange={() =>
94
+ onTreeItemClick([`${key}.__model__`], value.__model__)
95
+ }
96
+ selected={!!value.__model__}
97
+ />}
98
+ />
99
+
100
+ <AccordionContent>
101
+ {createTree(key, value, key)}
102
+ </AccordionContent>
103
+ </Accordion>
104
+ </Box>
105
+ )
106
+
107
+ )
108
+
109
+ }
110
+ )}
111
+ </Box>
112
+ );
113
+ }
114
+
115
+ Tree.propTypes = {
116
+ objects: PropTypes.object.isRequired,
117
+ onTreeItemClick: PropTypes.func.isRequired,
118
+ };
119
+
120
+ export default Tree;
@@ -0,0 +1,48 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { Checkbox } from '@strapi/design-system/Checkbox';
4
+
5
+ function TreeItem(props) {
6
+ const onChange = (key, currentValue) => {
7
+ props.onTreeItemClick(key, currentValue);
8
+ };
9
+
10
+ return (
11
+ <>
12
+ {typeof props.value === "boolean" && (
13
+ <Checkbox
14
+ checked={props.value}
15
+ onChange={() => onChange([props.passedKey], props.value)}
16
+ >
17
+ {props.label || "-"}
18
+ </Checkbox>
19
+ )}
20
+ {props.value === null && (
21
+ <Checkbox
22
+ checked={false}
23
+ disabled
24
+ >
25
+ {props.label || "-"}
26
+ </Checkbox>
27
+ )}
28
+ {props.children && <div key={props.passedKey}>{props.children}</div>}
29
+ </>
30
+ );
31
+ }
32
+
33
+ TreeItem.propTypes = {
34
+ label: PropTypes.string,
35
+ value: PropTypes.any,
36
+ children: PropTypes.any,
37
+ passedKey: PropTypes.string,
38
+ onTreeItemClick: PropTypes.func.isRequired,
39
+ };
40
+
41
+ TreeItem.defaultProps = {
42
+ label: undefined,
43
+ value: undefined,
44
+ children: undefined,
45
+ passedKey: "",
46
+ };
47
+
48
+ export default TreeItem;
@@ -0,0 +1,71 @@
1
+ import set from "lodash-es/set";
2
+ import get from "lodash-es/get";
3
+ import deepKeys from "deep-keys";
4
+ import sortByModelName from "../../@common/utils/sort-by-model-name";
5
+ import arrayOfModelsToObject from "../utils/array-of-models-to-object";
6
+ import findModelValueByKey from "../utils/find-model-value-by-key";
7
+
8
+ export default (
9
+ localizableTree = [],
10
+ storedSetupSchema = [],
11
+ allModelsTree = []
12
+ ) => {
13
+ localizableTree = arrayOfModelsToObject(
14
+ localizableTree.sort(sortByModelName)
15
+ );
16
+ storedSetupSchema = arrayOfModelsToObject(
17
+ storedSetupSchema.sort(sortByModelName)
18
+ );
19
+
20
+ const currentModelsSchemaKeys = deepKeys(localizableTree);
21
+ const storedSetupSchemaKeys = deepKeys(storedSetupSchema);
22
+
23
+ const removedKeys = storedSetupSchemaKeys.filter(
24
+ (x) => !currentModelsSchemaKeys.includes(x)
25
+ );
26
+
27
+ const newKeys = currentModelsSchemaKeys.filter(
28
+ (key) => !storedSetupSchemaKeys.includes(key)
29
+ );
30
+
31
+ const filteredStoredSetupSchemaKeys = storedSetupSchemaKeys.filter(
32
+ (key) => !removedKeys.includes(key)
33
+ );
34
+
35
+ const destinationObject = {};
36
+ filteredStoredSetupSchemaKeys.forEach((key) => {
37
+ const localizableTreeValueToSet = get(storedSetupSchema, key);
38
+ const allModelsTreeValueToSet = findModelValueByKey(allModelsTree, key);
39
+
40
+ if (allModelsTreeValueToSet === null) {
41
+ set(destinationObject, key, null);
42
+ } else if (localizableTreeValueToSet !== null) {
43
+ set(destinationObject, key, localizableTreeValueToSet);
44
+ } else {
45
+ // check for newly activated localizable fields & update model accordingly
46
+ const newValueToSet = findModelValueByKey(allModelsTree, key);
47
+ set(destinationObject, key, newValueToSet);
48
+ }
49
+ });
50
+ newKeys.forEach((key) => {
51
+ set(destinationObject, key, get(localizableTree, key));
52
+ });
53
+
54
+ const destinationArray = [];
55
+ const sortedDestinationObjectKeys = Object.keys(destinationObject).sort(
56
+ (a, b) => {
57
+ if (a < b) return -1;
58
+
59
+ if (a > b) return 1;
60
+
61
+ return 0;
62
+ }
63
+ );
64
+
65
+ // eslint-disable-next-line no-restricted-syntax
66
+ for (const key of sortedDestinationObjectKeys) {
67
+ destinationArray.push(destinationObject[key]);
68
+ }
69
+
70
+ return destinationArray;
71
+ };
@@ -0,0 +1,85 @@
1
+ import deepKeys from "deep-keys";
2
+ import get from "lodash-es/get";
3
+ import PluginSettingsService from "../services/plugin-settings-service";
4
+ import StrapiModelService from "../services/strapi-model-service";
5
+ import getModelsTree from "../utils/get-models-tree";
6
+ import sortByModelName from "../../@common/utils/sort-by-model-name";
7
+ import arrayOfModelsToObject from "../utils/array-of-models-to-object";
8
+ import findModelValueByKey from "../utils/find-model-value-by-key";
9
+
10
+ /**
11
+ * Pass parameters optionally so we don't have to fetch them again
12
+ * Returns whether the content transfer setup has changed
13
+ */
14
+ export default async (
15
+ localizableTree = null,
16
+ storedSetupSchema = null,
17
+ allModelsTree = null
18
+ ) => {
19
+ let models;
20
+
21
+ if (!localizableTree || !allModelsTree) {
22
+ models = await StrapiModelService.getModels();
23
+ }
24
+
25
+ if (!localizableTree) {
26
+ const localizableModels = await StrapiModelService.getLocalizableModels();
27
+ localizableTree = getModelsTree(models, localizableModels);
28
+ }
29
+
30
+ if (!storedSetupSchema) {
31
+ storedSetupSchema = (await PluginSettingsService.getContentTransferSetup())
32
+ .setup;
33
+ }
34
+
35
+ if (!allModelsTree) {
36
+ allModelsTree = getModelsTree(models, models);
37
+ }
38
+
39
+ localizableTree = arrayOfModelsToObject(
40
+ localizableTree.sort(sortByModelName)
41
+ );
42
+ storedSetupSchema = arrayOfModelsToObject(
43
+ storedSetupSchema.sort(sortByModelName)
44
+ );
45
+
46
+ const modelsTreeKeys = deepKeys(localizableTree);
47
+ const storedSetupSchemaKeys = deepKeys(storedSetupSchema);
48
+
49
+ const removedKeys = storedSetupSchemaKeys.filter(
50
+ (x) => !modelsTreeKeys.includes(x)
51
+ );
52
+ const newKeys = modelsTreeKeys.filter(
53
+ (key) => !storedSetupSchemaKeys.includes(key)
54
+ );
55
+
56
+ if (newKeys.length || removedKeys.length) {
57
+ return true;
58
+ }
59
+
60
+ const filteredStoredSetupSchemaKeys = storedSetupSchemaKeys.filter(
61
+ (key) => !removedKeys.includes(key)
62
+ );
63
+
64
+ // eslint-disable-next-line no-restricted-syntax
65
+ for (const key of filteredStoredSetupSchemaKeys) {
66
+ const localizableTreeValueToSet = get(storedSetupSchema, key);
67
+ const allModelsTreeValueToSet = findModelValueByKey(allModelsTree, key);
68
+
69
+ if (
70
+ typeof localizableTreeValueToSet === "boolean" &&
71
+ allModelsTreeValueToSet === null
72
+ ) {
73
+ return true;
74
+ }
75
+
76
+ if (
77
+ localizableTreeValueToSet === null &&
78
+ typeof allModelsTreeValueToSet === "boolean"
79
+ ) {
80
+ return true;
81
+ }
82
+ }
83
+
84
+ return false;
85
+ };
@@ -0,0 +1,19 @@
1
+ export default {
2
+ content_transfer_setup: "Content Transfer Setup",
3
+ content_transfer_setup_description:
4
+ "Setup what content type fields will be uploaded to Localazy",
5
+ save: "Save",
6
+ cancel: "Cancel",
7
+ close: "Close",
8
+
9
+ content_transfer_setup_saved: "Content Transfer Setup saved",
10
+ content_transfer_setup_saved_successfully:
11
+ "Content Transfer Setup saved successfully",
12
+ content_types_model_changed: "Content Types Model Changed",
13
+ please_update_your_content:
14
+ "Please update your content transfer setup before proceeding to upload/download",
15
+ you_can_upload_download: "You can upload/download ",
16
+ only_text_based_content: "only text based content.",
17
+ learn_more_in_docs_message_a: "If you want to learn more about how to setup your Content Transfer settings read the ",
18
+ learn_more_in_docs_message_b: "Localazy documentation.",
19
+ };
@@ -0,0 +1,32 @@
1
+ /* eslint-disable no-useless-catch */
2
+ import createAxiosInstance from "../../../utils/createAxiosInstance";
3
+
4
+ const BASE_PATH = "/plugin-settings";
5
+ const axiosInstance = createAxiosInstance();
6
+
7
+ export default class PluginSettingsService {
8
+ static async getContentTransferSetup() {
9
+ try {
10
+ const result = await axiosInstance.get(
11
+ `${BASE_PATH}/content-transfer-setup`
12
+ );
13
+
14
+ return result.data;
15
+ } catch (e) {
16
+ throw e;
17
+ }
18
+ }
19
+
20
+ static async updateContentTransferSetup(data) {
21
+ try {
22
+ const result = await axiosInstance.put(
23
+ `${BASE_PATH}/content-transfer-setup`,
24
+ data
25
+ );
26
+
27
+ return result.data;
28
+ } catch (e) {
29
+ throw e;
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,26 @@
1
+ import createAxiosInstance from "../../../utils/createAxiosInstance";
2
+
3
+ const BASE_PATH = "/strapi";
4
+ const axiosInstance = createAxiosInstance();
5
+
6
+ export default class StrapiModelService {
7
+ static async getModels() {
8
+ try {
9
+ const result = await axiosInstance.get(`${BASE_PATH}/models`);
10
+
11
+ return result.data;
12
+ } catch (e) {
13
+ throw e.message;
14
+ }
15
+ }
16
+
17
+ static async getLocalizableModels() {
18
+ try {
19
+ const result = await axiosInstance.get(`${BASE_PATH}/localizable-models`);
20
+
21
+ return result.data;
22
+ } catch (e) {
23
+ throw e.message;
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,135 @@
1
+ import getModelsTree from "../get-models-tree";
2
+
3
+ const allModels = require("../../../../tests/fixtures/all-models");
4
+ const restaurantModel = require("../../../../tests/fixtures/restaurant-model");
5
+
6
+ it("should return the tree for restaurants", () => {
7
+ // SETUP
8
+ const object = allModels;
9
+ const localizableModels = [restaurantModel];
10
+
11
+ // EXECUTE
12
+ const result = getModelsTree(object, localizableModels);
13
+
14
+ // VERIFY
15
+ const restaurantModelsTree = result.find((model) => model.restaurants);
16
+ const expected = {
17
+ restaurants: {
18
+ __model__: true,
19
+ title: false,
20
+ description: false,
21
+ books: null,
22
+ recipes: {
23
+ name: false,
24
+ ingredients: {
25
+ name: false,
26
+ pcs: null,
27
+ required: null,
28
+ },
29
+ variants: {
30
+ name: false,
31
+ },
32
+ },
33
+ descs: {
34
+ rich_description: false,
35
+ history: false,
36
+ excerpt: false,
37
+ test_variants: {
38
+ name: false,
39
+ },
40
+ },
41
+ street: false,
42
+ city: false,
43
+ country: false,
44
+ },
45
+ };
46
+ expect(restaurantModelsTree).toEqual(expected);
47
+ });
48
+
49
+ it("should return a tree for all models", () => {
50
+ // SETUP
51
+ const localizableModels = allModels.filter(
52
+ (model) => model.modelType === "contentType"
53
+ );
54
+ const object = allModels;
55
+
56
+ // EXECUTE
57
+ const result = getModelsTree(object, localizableModels);
58
+
59
+ // VERIFY
60
+ const expected = [
61
+ {
62
+ tokens: {
63
+ __model__: true,
64
+ access_token: null,
65
+ },
66
+ },
67
+ {
68
+ testtokens: {
69
+ __model__: true,
70
+ at: null,
71
+ },
72
+ },
73
+ {
74
+ up_users: {
75
+ __model__: true,
76
+ username: null,
77
+ email: null,
78
+ provider: null,
79
+ password: null,
80
+ resetPasswordToken: null,
81
+ confirmationToken: null,
82
+ confirmed: null,
83
+ blocked: null,
84
+ role: null,
85
+ },
86
+ },
87
+ {
88
+ books: {
89
+ __model__: true,
90
+ Title: false,
91
+ Author: null,
92
+ Pages: null,
93
+ additional_info: {
94
+ rich_description: null,
95
+ history: null,
96
+ excerpt: null,
97
+ test_variants: {
98
+ name: null,
99
+ },
100
+ },
101
+ },
102
+ },
103
+ {
104
+ restaurants: {
105
+ __model__: true,
106
+ title: false,
107
+ description: false,
108
+ books: null,
109
+ recipes: {
110
+ name: false,
111
+ ingredients: {
112
+ name: false,
113
+ pcs: null,
114
+ required: null,
115
+ },
116
+ variants: {
117
+ name: false,
118
+ },
119
+ },
120
+ descs: {
121
+ rich_description: false,
122
+ history: false,
123
+ excerpt: false,
124
+ test_variants: {
125
+ name: false,
126
+ },
127
+ },
128
+ street: false,
129
+ city: false,
130
+ country: false,
131
+ },
132
+ },
133
+ ];
134
+ expect(result).toEqual(expected);
135
+ });
@@ -0,0 +1,6 @@
1
+ export default (array) =>
2
+ array.reduce((obj, item) => {
3
+ obj[Object.keys(item)[0]] = item;
4
+
5
+ return obj;
6
+ }, {});
@@ -0,0 +1,8 @@
1
+ import get from "lodash-es/get";
2
+ import arrayOfModelsToObject from "./array-of-models-to-object";
3
+
4
+ export default (allModelsTree, key) => {
5
+ const objectivizedModelsTree = arrayOfModelsToObject(allModelsTree);
6
+
7
+ return get(objectivizedModelsTree, key);
8
+ };
@@ -0,0 +1,34 @@
1
+ const SUPPORTED_CONTENT_TYPE_FIELDS = [
2
+ "string",
3
+ "text",
4
+ "richtext",
5
+ // "relation", // relation cannot be supported field type
6
+ "component",
7
+ ];
8
+
9
+ export default (models) => {
10
+ if (!models) {
11
+ return [];
12
+ }
13
+
14
+ return models.map((model) => {
15
+ const attributesKeys = Object.keys(model.__schema__.attributes);
16
+
17
+ const attributes = attributesKeys.map((attributeKey) => {
18
+ const type = model.__schema__.attributes[attributeKey].type;
19
+
20
+ if (!SUPPORTED_CONTENT_TYPE_FIELDS.includes(type.toLowerCase())) {
21
+ return null;
22
+ }
23
+
24
+ return attributeKey;
25
+ });
26
+
27
+ return {
28
+ modelUid: model.uid,
29
+ collectionName: model.collectionName,
30
+ displayName: model.info.displayName,
31
+ attributes: attributes.filter((attribute) => !!attribute),
32
+ };
33
+ });
34
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Supported kinds of models are expected by the function, needs to be checked before calling the function
3
+ */
4
+ const getModelsTree = (allModels, localizableModels = []) => {
5
+ const modelsTree = [];
6
+
7
+ const getModelTree = (
8
+ attributes,
9
+ isComponentAttributes = false,
10
+ isComponentAttributesObjectTranslatable = null
11
+ ) => {
12
+ const currentModelTree = {};
13
+ // eslint-disable-next-line no-restricted-syntax
14
+ for (const attribute in attributes) {
15
+ if (attributes[attribute].type === "component") {
16
+ const nestedModel = allModels.find(
17
+ (model) => model.uid === attributes[attribute].component
18
+ );
19
+
20
+ currentModelTree[attribute] = {
21
+ ...getModelTree(
22
+ nestedModel.__schema__.attributes,
23
+ true,
24
+ isComponentAttributesObjectTranslatable === null
25
+ ? attributes[attribute].pluginOptions?.i18n?.localized || false
26
+ : isComponentAttributesObjectTranslatable
27
+ ),
28
+ };
29
+ } else if (
30
+ ["string", "text", "richtext"].includes(attributes[attribute].type)
31
+ ) {
32
+ // field might not be localizable
33
+ if (isComponentAttributes) {
34
+ if (isComponentAttributesObjectTranslatable) {
35
+ currentModelTree[attribute] = false;
36
+ } else {
37
+ currentModelTree[attribute] = null;
38
+ }
39
+ } else if (
40
+ !isComponentAttributes &&
41
+ (!attributes[attribute].pluginOptions ||
42
+ !attributes[attribute].pluginOptions.i18n ||
43
+ !attributes[attribute].pluginOptions.i18n.localized)
44
+ ) {
45
+ currentModelTree[attribute] = null;
46
+ } else {
47
+ currentModelTree[attribute] = false;
48
+ }
49
+ } else {
50
+ currentModelTree[attribute] = null;
51
+ }
52
+ }
53
+
54
+ return currentModelTree;
55
+ };
56
+
57
+ // eslint-disable-next-line no-restricted-syntax
58
+ for (const model of localizableModels) {
59
+ if (model.__schema__.collectionName) {
60
+ const modelTree = {
61
+ [model.__schema__.collectionName]: {
62
+ __model__: true,
63
+ ...getModelTree(model.__schema__.attributes),
64
+ },
65
+ };
66
+ modelsTree.push(modelTree);
67
+ }
68
+ }
69
+
70
+ return modelsTree;
71
+ };
72
+
73
+ export default getModelsTree;