@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.
- package/.babelrc +7 -0
- package/.eslintrc +7 -0
- package/.github/workflows/.build.yml +39 -0
- package/.nvmrc +1 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/admin/src/.eslintrc +3 -0
- package/admin/src/components/Initializer/index.js +26 -0
- package/admin/src/components/PluginIcon/index.js +14 -0
- package/admin/src/i18n.js +37 -0
- package/admin/src/index.js +106 -0
- package/admin/src/modules/@common/components/Icons/Localazy/index.js +12 -0
- package/admin/src/modules/@common/components/SideNav/index.js +46 -0
- package/admin/src/modules/@common/components/TransferReport/index.js +54 -0
- package/admin/src/modules/@common/locale/en.js +13 -0
- package/admin/src/modules/@common/services/i18n-service.js +15 -0
- package/admin/src/modules/@common/services/project-service.js +15 -0
- package/admin/src/modules/@common/services/user-service.js +38 -0
- package/admin/src/modules/@common/utils/are-locales-compatible.js +42 -0
- package/admin/src/modules/@common/utils/functions/flatten-deep.js +23 -0
- package/admin/src/modules/@common/utils/get-default-locale.js +32 -0
- package/admin/src/modules/@common/utils/get-header-subtitle.js +21 -0
- package/admin/src/modules/@common/utils/get-header-title.js +24 -0
- package/admin/src/modules/@common/utils/get-nav.js +35 -0
- package/admin/src/modules/@common/utils/history.js +6 -0
- package/admin/src/modules/@common/utils/is-plugin-route.js +15 -0
- package/admin/src/modules/@common/utils/iso-locales-utils.js +15 -0
- package/admin/src/modules/@common/utils/redirect-to-plugin-route.js +22 -0
- package/admin/src/modules/@common/utils/sort-by-model-name.js +10 -0
- package/admin/src/modules/localazy-download/locale/en.js +20 -0
- package/admin/src/modules/localazy-download/services/localazy-download-service.js +16 -0
- package/admin/src/modules/localazy-upload/components/ReadDocsButton.js +21 -0
- package/admin/src/modules/localazy-upload/locale/en.js +18 -0
- package/admin/src/modules/localazy-upload/services/localazy-upload-service.js +16 -0
- package/admin/src/modules/login/components/LoginButton/index.js +56 -0
- package/admin/src/modules/login/components/LogoutButton/index.js +50 -0
- package/admin/src/modules/login/locale/en.js +7 -0
- package/admin/src/modules/login/services/localazy-login-service.js +29 -0
- package/admin/src/modules/plugin-settings/components/ContentTransferSetup/index.js +292 -0
- package/admin/src/modules/plugin-settings/components/Tree/index.js +120 -0
- package/admin/src/modules/plugin-settings/components/TreeItem/index.js +48 -0
- package/admin/src/modules/plugin-settings/functions/build-content-transfer-setup-schema.js +71 -0
- package/admin/src/modules/plugin-settings/functions/has-model-changed.js +85 -0
- package/admin/src/modules/plugin-settings/locale/en.js +19 -0
- package/admin/src/modules/plugin-settings/services/plugin-settings-service.js +32 -0
- package/admin/src/modules/plugin-settings/services/strapi-model-service.js +26 -0
- package/admin/src/modules/plugin-settings/utils/__tests__/get-models-tree.test.js +135 -0
- package/admin/src/modules/plugin-settings/utils/array-of-models-to-object.js +6 -0
- package/admin/src/modules/plugin-settings/utils/find-model-value-by-key.js +8 -0
- package/admin/src/modules/plugin-settings/utils/get-filtered-models-schemas.js +34 -0
- package/admin/src/modules/plugin-settings/utils/get-models-tree.js +73 -0
- package/admin/src/modules/settings/components/OverviewItem/index.js +44 -0
- package/admin/src/modules/settings/components/OverviewItemLink/index.js +34 -0
- package/admin/src/modules/settings/components/PrerequisitiesInfo/index.js +30 -0
- package/admin/src/modules/settings/locale/en.js +13 -0
- package/admin/src/modules/user/model/localazy-identity.js +14 -0
- package/admin/src/modules/user/services/localazy-user-service.js +38 -0
- package/admin/src/pages/App/index.js +152 -0
- package/admin/src/pages/Download/index.js +179 -0
- package/admin/src/pages/Index/index.js +8 -0
- package/admin/src/pages/Login/index.js +94 -0
- package/admin/src/pages/PluginSettings/index.js +42 -0
- package/admin/src/pages/Settings/index.js +120 -0
- package/admin/src/pages/Upload/index.js +187 -0
- package/admin/src/pluginId.js +5 -0
- package/admin/src/plugins/apolloClient.js +33 -0
- package/admin/src/state/localazy-identity.js +29 -0
- package/admin/src/tests/fixtures/all-models.js +877 -0
- package/admin/src/tests/fixtures/restaurant-model.js +230 -0
- package/admin/src/translations/en.json +4 -0
- package/admin/src/translations/fr.json +1 -0
- package/admin/src/utils/createAxiosInstance.js +52 -0
- package/admin/src/utils/getTrad.js +5 -0
- package/jest.config.js +0 -0
- package/package.json +60 -0
- package/server/bootstrap.js +5 -0
- package/server/config/development/index.js +15 -0
- package/server/config/example/index.js +15 -0
- package/server/config/index.js +15 -0
- package/server/config/production/index.js +16 -0
- package/server/config/schema.graphql.js +21 -0
- package/server/content-types/index.js +3 -0
- package/server/controllers/index.js +19 -0
- package/server/controllers/localazy-auth-controller.js +46 -0
- package/server/controllers/localazy-project-controller.js +21 -0
- package/server/controllers/localazy-transfer-controller.js +469 -0
- package/server/controllers/localazy-user-controller.js +24 -0
- package/server/controllers/my-controller.js +10 -0
- package/server/controllers/plugin-settings-controller.js +17 -0
- package/server/controllers/strapi-controller.js +16 -0
- package/server/db/model/content-transfer-setup.js +13 -0
- package/server/db/model/localazy-user.js +23 -0
- package/server/db/model/utils/get-strapi-store.js +9 -0
- package/server/destroy.js +5 -0
- package/server/index.js +25 -0
- package/server/middlewares/index.js +3 -0
- package/server/policies/index.js +3 -0
- package/server/register.js +5 -0
- package/server/routes/index.js +26 -0
- package/server/routes/localazy-auth.js +22 -0
- package/server/routes/localazy-project.js +14 -0
- package/server/routes/localazy-transfer.js +22 -0
- package/server/routes/localazy-user.js +30 -0
- package/server/routes/plugin-settings.js +22 -0
- package/server/routes/strapi.js +22 -0
- package/server/services/index.js +21 -0
- package/server/services/localazy-auth-service.js +38 -0
- package/server/services/localazy-download-service.js +54 -0
- package/server/services/localazy-pubapi-service.js +47 -0
- package/server/services/localazy-upload-service.js +95 -0
- package/server/services/localazy-user-service.js +29 -0
- package/server/services/plugin-settings-service.js +30 -0
- package/server/services/strapi-i18n-service.js +132 -0
- package/server/services/strapi-service.js +23 -0
- package/server/tests/fixtures/all-models-with-multimedia.js +1064 -0
- package/server/tests/fixtures/all-models.js +869 -0
- package/server/tests/fixtures/collection-flattened.js +76 -0
- package/server/tests/fixtures/restaurant-flattened.js +46 -0
- package/server/tests/fixtures/restaurant-model.js +230 -0
- package/server/tests/fixtures/restaurants-entries.js +152 -0
- package/server/tests/fixtures/restaurants-pick-paths.js +15 -0
- package/server/tests/fixtures/strapi-book-with-multimedia-components-cs.js +31 -0
- package/server/tests/fixtures/stringified-book-cs.js +3 -0
- package/server/tests/fixtures/stringified-book-with-multimedia-components-cs.js +3 -0
- package/server/tests/fixtures/stringified-restaurant-cs.js +3 -0
- package/server/tests/fixtures/stringified-restaurant-de.js +5 -0
- package/server/utils/__tests__/build-populate.test.js +85 -0
- package/server/utils/__tests__/flatten-object.test.js +171 -0
- package/server/utils/__tests__/get-models-tree.test.js +170 -0
- package/server/utils/__tests__/parsed-localazy-entry-to-create-entry.test.js +153 -0
- package/server/utils/__tests__/parsed-localazy-entry-to-update-entry.test.js +172 -0
- package/server/utils/__tests__/pick-entries.test.js +83 -0
- package/server/utils/build-populate.js +43 -0
- package/server/utils/delay.js +6 -0
- package/server/utils/flatten-object.js +52 -0
- package/server/utils/get-localazy-api.js +22 -0
- package/server/utils/get-main-keys-of-nested-array-objects.js +5 -0
- package/server/utils/get-models-tree.js +43 -0
- package/server/utils/intl-display-name.js +7 -0
- package/server/utils/is-generally-applicable-content-type.js +33 -0
- package/server/utils/is-localazy-applicable-content-type.js +36 -0
- package/server/utils/iso-locales-utils.js +22 -0
- package/server/utils/objectivise-entry.js +41 -0
- package/server/utils/omit-deep.js +17 -0
- package/server/utils/parsed-localazy-entry-to-create-entry.js +115 -0
- package/server/utils/parsed-localazy-entry-to-update-entry.js +31 -0
- package/server/utils/pick-entries.js +14 -0
- package/server/utils/transfer-setup-utils.js +39 -0
- package/strapi-admin.js +14 -0
- 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,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;
|