@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,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import House from "@strapi/icons/House";
|
|
3
|
+
import Download from "@strapi/icons/Download";
|
|
4
|
+
import Upload from "@strapi/icons/Upload";
|
|
5
|
+
import pluginId from "../../../pluginId";
|
|
6
|
+
import i18n from "../../../i18n";
|
|
7
|
+
|
|
8
|
+
const BASE_PATH = `/admin/plugins/${pluginId}`;
|
|
9
|
+
const t = i18n.t;
|
|
10
|
+
const gevNav = () => {
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
id: "settings",
|
|
14
|
+
label: t("common.settings"),
|
|
15
|
+
description: t("settings.description"),
|
|
16
|
+
icon: <House />,
|
|
17
|
+
to: `${BASE_PATH}/settings`,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "upload",
|
|
21
|
+
label: t("common.upload_to_localazy"),
|
|
22
|
+
description: t("upload.description"),
|
|
23
|
+
icon: < Upload />,
|
|
24
|
+
to: `${BASE_PATH}/upload`,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "download",
|
|
28
|
+
label: t("common.download_to_strapi"),
|
|
29
|
+
description: t("download.description"),
|
|
30
|
+
icon: <Download />,
|
|
31
|
+
to: `${BASE_PATH}/download`,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
};
|
|
35
|
+
export default gevNav;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import pluginId from "../../../pluginId";
|
|
2
|
+
|
|
3
|
+
export default (location, path = "") => {
|
|
4
|
+
if (path) {
|
|
5
|
+
return (
|
|
6
|
+
location.pathname.endsWith(`${pluginId}/${path}`) ||
|
|
7
|
+
location.pathname.endsWith(`${pluginId}/${path}/`)
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
location.pathname.endsWith(pluginId) ||
|
|
13
|
+
location.pathname.endsWith(`${pluginId}/`)
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const isoStrapiToLocalazy = (isoStrapi) => {
|
|
2
|
+
if (!isoStrapi) {
|
|
3
|
+
return null;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return isoStrapi.replace("_", "-");
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const isoLocalazyToStrapi = (isoLocalazy) => {
|
|
10
|
+
if (!isoLocalazy) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return isoLocalazy.replace("-", "_");
|
|
15
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import pluginId from "../../../pluginId";
|
|
2
|
+
import history from "./history";
|
|
3
|
+
|
|
4
|
+
export const PLUGIN_ROUTES = {
|
|
5
|
+
ROOT: "",
|
|
6
|
+
LOGIN: "login",
|
|
7
|
+
UPLOAD: "upload",
|
|
8
|
+
DOWNLOAD: "download",
|
|
9
|
+
SETTINGS: "settings",
|
|
10
|
+
// settings routes
|
|
11
|
+
CONTENT_TRANSFER_SETUP: "content-transfer-setup",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default (route) => {
|
|
15
|
+
if (route === PLUGIN_ROUTES.CONTENT_TRANSFER_SETUP) {
|
|
16
|
+
history.push(`/admin/settings/${pluginId}/${route}`);
|
|
17
|
+
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
history.push(`/admin/plugins/${pluginId}/${route}`);
|
|
22
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
description: "Download content in multiple languages to your Strapi project",
|
|
3
|
+
download_to_strapi: "Start download",
|
|
4
|
+
content_types_model_changed: "Content Types Model Changed",
|
|
5
|
+
close: "Close",
|
|
6
|
+
please_update_your_content:
|
|
7
|
+
"Please update your content transfer setup before proceeding to upload/download",
|
|
8
|
+
languages_incompatible: "Languages incompatible",
|
|
9
|
+
languages_incompatible_message:
|
|
10
|
+
"Strapi default language and Localazy source language are incompatible, to proceed, please update one of them.",
|
|
11
|
+
download_result: "Download completed:",
|
|
12
|
+
download_success: "Content successfully imported to Strapi.",
|
|
13
|
+
download_failed: "Download partially failed, please check the report for details...",
|
|
14
|
+
translate_in_localazy: "Translate in Localazy",
|
|
15
|
+
download_note_a: "Download ",
|
|
16
|
+
download_note_b: "will rewrite all previous translations.",
|
|
17
|
+
make_sure_note_a: "Make sure the translations are approved in Localazy, otherwise they ",
|
|
18
|
+
make_sure_note_b: "will not ",
|
|
19
|
+
make_sure_note_c: "be downloaded to Strapi.",
|
|
20
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import createAxiosInstance from "../../../utils/createAxiosInstance";
|
|
2
|
+
|
|
3
|
+
const BASE_PATH = "/transfer";
|
|
4
|
+
const axiosInstance = createAxiosInstance();
|
|
5
|
+
|
|
6
|
+
export default class LocalazyDownloadService {
|
|
7
|
+
static async download(data = {}) {
|
|
8
|
+
try {
|
|
9
|
+
const result = await axiosInstance.post(`${BASE_PATH}/download`, data);
|
|
10
|
+
|
|
11
|
+
return result.data;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw e.data;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Button } from "@strapi/design-system/Button";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import "../../../i18n";
|
|
5
|
+
|
|
6
|
+
function ReadDocsButton() {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
|
|
9
|
+
const link = "https://localazy.com/docs/strapi";
|
|
10
|
+
const onReadDocumentationClick = () => {
|
|
11
|
+
window.open(link, "_blank");
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Button variant="tertiary" onClick={onReadDocumentationClick}>
|
|
16
|
+
{t("upload.read_documentation")}
|
|
17
|
+
</Button>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default ReadDocsButton;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
description: "Upload your content from Strapi to Localazy",
|
|
3
|
+
upload_to_localazy: "Start upload",
|
|
4
|
+
default_strapi_language: "Default Strapi language",
|
|
5
|
+
localazy_source_language: "Localazy source language",
|
|
6
|
+
change_settings: "Change settings",
|
|
7
|
+
read_documentation: "Read documentation",
|
|
8
|
+
content_types_model_changed: "Content Types Model Changed",
|
|
9
|
+
close: "Close",
|
|
10
|
+
please_update_your_content:
|
|
11
|
+
"Please update your content transfer configuration before proceeding to upload/download.",
|
|
12
|
+
languages_incompatible: "Languages mismatch!",
|
|
13
|
+
languages_incompatible_message: "The source language at Localazy doesn't match the Strapi default language setting. To continue, please set both languages to be the same.",
|
|
14
|
+
upload_result: "Upload completed:",
|
|
15
|
+
upload_success: "Content successfully imported to the Localazy project.",
|
|
16
|
+
upload_failed:
|
|
17
|
+
"Upload partially failed, please check the report for details...",
|
|
18
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import createAxiosInstance from "../../../utils/createAxiosInstance";
|
|
2
|
+
|
|
3
|
+
const BASE_PATH = "/transfer";
|
|
4
|
+
const axiosInstance = createAxiosInstance();
|
|
5
|
+
|
|
6
|
+
export default class LocalazyUploadService {
|
|
7
|
+
static async upload(data = {}) {
|
|
8
|
+
try {
|
|
9
|
+
const result = await axiosInstance.post(`${BASE_PATH}/upload`, data);
|
|
10
|
+
|
|
11
|
+
return result.data;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw e.data;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
*
|
|
3
|
+
* LoginButton
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState } from "react";
|
|
8
|
+
import PropTypes from "prop-types";
|
|
9
|
+
import { Button } from "@strapi/design-system/Button";
|
|
10
|
+
import { useTranslation } from "react-i18next";
|
|
11
|
+
import LocalazyLoginService from "../../services/localazy-login-service";
|
|
12
|
+
import { getStrapiDefaultLocale } from "../../../@common/utils/get-default-locale";
|
|
13
|
+
import { isoStrapiToLocalazy } from "../../../@common/utils/iso-locales-utils";
|
|
14
|
+
import { config } from "../../../../../../server";
|
|
15
|
+
import "../../../../i18n";
|
|
16
|
+
|
|
17
|
+
function LoginButton(props) {
|
|
18
|
+
const { t } = useTranslation();
|
|
19
|
+
|
|
20
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
21
|
+
const login = async () => {
|
|
22
|
+
setIsLoading(true);
|
|
23
|
+
|
|
24
|
+
const strapiDefaultLocale = await getStrapiDefaultLocale();
|
|
25
|
+
const localazyFormatLocaleCode = isoStrapiToLocalazy(strapiDefaultLocale.code);
|
|
26
|
+
const keys = await LocalazyLoginService.generateKeys();
|
|
27
|
+
const params = new URLSearchParams({
|
|
28
|
+
client_id: config.default.LOCALAZY_OAUTH_APP_CLIENT_ID,
|
|
29
|
+
custom_id: keys.writeKey,
|
|
30
|
+
allow_create: "true",
|
|
31
|
+
create_locale: localazyFormatLocaleCode,
|
|
32
|
+
});
|
|
33
|
+
const url = `${config.default.LOCALAZY_OAUTH_URL}?${params.toString()}`;
|
|
34
|
+
window.open(url);
|
|
35
|
+
|
|
36
|
+
const pollResult = await LocalazyLoginService.continuousPoll(keys.readKey);
|
|
37
|
+
|
|
38
|
+
setIsLoading(false);
|
|
39
|
+
|
|
40
|
+
props.onResultFetched(pollResult);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div>
|
|
45
|
+
<Button variant="default" size="L" loading={isLoading} onClick={login}>
|
|
46
|
+
{t("login.login_with_localazy")}
|
|
47
|
+
</Button>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
LoginButton.propTypes = {
|
|
53
|
+
onResultFetched: PropTypes.func.isRequired,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default LoginButton;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
*
|
|
3
|
+
* LogoutButton
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState } from "react";
|
|
8
|
+
import PropTypes from "prop-types";
|
|
9
|
+
import { Button } from "@strapi/design-system/Button";
|
|
10
|
+
import { useTranslation } from "react-i18next";
|
|
11
|
+
import Exit from "@strapi/icons/Exit";
|
|
12
|
+
import LocalazyUserService from "../../../user/services/localazy-user-service";
|
|
13
|
+
import { setLocalazyIdentity } from "../../../../state/localazy-identity";
|
|
14
|
+
import "../../../../i18n";
|
|
15
|
+
|
|
16
|
+
function LogoutButton(props) {
|
|
17
|
+
const { t } = useTranslation();
|
|
18
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
19
|
+
const logout = async () => {
|
|
20
|
+
setIsLoading(true);
|
|
21
|
+
|
|
22
|
+
// delete identity from db
|
|
23
|
+
// delete identity from app state
|
|
24
|
+
LocalazyUserService.deleteIdentity();
|
|
25
|
+
setLocalazyIdentity();
|
|
26
|
+
|
|
27
|
+
setIsLoading(false);
|
|
28
|
+
|
|
29
|
+
props.onResultFetched();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div>
|
|
34
|
+
<Button
|
|
35
|
+
startIcon={<Exit />}
|
|
36
|
+
variant="secondary"
|
|
37
|
+
loading={isLoading}
|
|
38
|
+
onClick={logout}
|
|
39
|
+
>
|
|
40
|
+
{t("login.logout_from_localazy")}
|
|
41
|
+
</Button>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
LogoutButton.propTypes = {
|
|
47
|
+
onResultFetched: PropTypes.func.isRequired,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default LogoutButton;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
login_with_localazy: "Login with Localazy",
|
|
3
|
+
login_and_start_translating_your_project: "Login and start translating your project with powerful Localazy tools.",
|
|
4
|
+
you_have_to_own_account_for_the_plugin_to_work_properly: "You have to own a Localazy account for the plugin to work properly.",
|
|
5
|
+
read_the_documentation: "Read the documentation",
|
|
6
|
+
logout_from_localazy: "Disconnect from Localazy",
|
|
7
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable no-useless-catch */
|
|
2
|
+
import createAxiosInstance from "../../../utils/createAxiosInstance";
|
|
3
|
+
|
|
4
|
+
const BASE_PATH = "/auth";
|
|
5
|
+
const axiosInstance = createAxiosInstance();
|
|
6
|
+
|
|
7
|
+
export default class LocalazyLoginService {
|
|
8
|
+
static async generateKeys() {
|
|
9
|
+
try {
|
|
10
|
+
const result = await axiosInstance.get(`${BASE_PATH}/generate-keys`);
|
|
11
|
+
|
|
12
|
+
return result.data;
|
|
13
|
+
} catch (e) {
|
|
14
|
+
throw e;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static async continuousPoll(readKey) {
|
|
19
|
+
try {
|
|
20
|
+
const result = await axiosInstance.get(
|
|
21
|
+
`${BASE_PATH}/continuous-poll?readKey=${readKey}`
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return result.data;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
throw e;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
import isEqual from "lodash-es/isEqual";
|
|
4
|
+
import cloneDeep from "lodash-es/cloneDeep";
|
|
5
|
+
import { HeaderLayout } from "@strapi/design-system/Layout";
|
|
6
|
+
import Check from "@strapi/icons/Check";
|
|
7
|
+
import { Box } from "@strapi/design-system/Box";
|
|
8
|
+
import { Button } from "@strapi/design-system/Button";
|
|
9
|
+
import { Alert } from "@strapi/design-system/Alert";
|
|
10
|
+
import { Redirect } from "react-router-dom";
|
|
11
|
+
import { Flex } from "@strapi/design-system/Flex";
|
|
12
|
+
import { Divider } from "@strapi/design-system/Divider";
|
|
13
|
+
import { Typography } from "@strapi/design-system/Typography";
|
|
14
|
+
import set from "lodash-es/set";
|
|
15
|
+
import get from "lodash-es/get";
|
|
16
|
+
import PluginSettingsService from "../../services/plugin-settings-service";
|
|
17
|
+
import StrapiModelService from "../../services/strapi-model-service";
|
|
18
|
+
import getFilteredModelsSchemas from "../../utils/get-filtered-models-schemas";
|
|
19
|
+
import getModelsTree from "../../utils/get-models-tree";
|
|
20
|
+
import hasModelChanged from "../../functions/has-model-changed";
|
|
21
|
+
import buildContentTransferSetupSchema from "../../functions/build-content-transfer-setup-schema";
|
|
22
|
+
import { getLocalazyIdentity } from "../../../../state/localazy-identity";
|
|
23
|
+
import Tree from "../Tree";
|
|
24
|
+
|
|
25
|
+
import "../../../../i18n";
|
|
26
|
+
|
|
27
|
+
function ContentTransferSetup() {
|
|
28
|
+
/**
|
|
29
|
+
* Translation function
|
|
30
|
+
*/
|
|
31
|
+
// eslint-disable-next-line no-unused-vars
|
|
32
|
+
const { t } = useTranslation();
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Is user logged in
|
|
36
|
+
*/
|
|
37
|
+
const [localazyIdentity] = getLocalazyIdentity();
|
|
38
|
+
const hasLocalazyIdentity = () => !!localazyIdentity.accessToken;
|
|
39
|
+
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Component state
|
|
43
|
+
*/
|
|
44
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
45
|
+
const [showAlert, setShowAlert] = useState(false);
|
|
46
|
+
const [showModalChangedAlert, setShowModalChangedAlert] = useState(false);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Accordion expanded state model
|
|
50
|
+
*/
|
|
51
|
+
const [, setItemsExpandedModel] = useState([]);
|
|
52
|
+
const buildItemsExpandedModel = (models) => {
|
|
53
|
+
const r = {};
|
|
54
|
+
getFilteredModelsSchemas(models).forEach((model, index) => {
|
|
55
|
+
r[model.modelUid] = index === 0;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return r;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Helper form model object
|
|
63
|
+
*/
|
|
64
|
+
const [, setTreeModelsSchemas] = useState([]);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Content transfer setup form model
|
|
68
|
+
*/
|
|
69
|
+
const [originalFormModel, setOriginalFormModel] = useState([]);
|
|
70
|
+
const [formModel, setFormModel] = useState([]);
|
|
71
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
|
72
|
+
|
|
73
|
+
const onCancelClick = () => {
|
|
74
|
+
setFormModel(cloneDeep(originalFormModel));
|
|
75
|
+
setHasUnsavedChanges(false);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Save the content transfer setup
|
|
80
|
+
*/
|
|
81
|
+
const saveContentTransferSetup = async (data) => {
|
|
82
|
+
try {
|
|
83
|
+
await PluginSettingsService.updateContentTransferSetup(data);
|
|
84
|
+
setOriginalFormModel(cloneDeep(data));
|
|
85
|
+
setHasUnsavedChanges(false);
|
|
86
|
+
setShowAlert(true);
|
|
87
|
+
setShowModalChangedAlert(false);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
throw e.data;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const onTreeItemClick = (keys, currentValue) => {
|
|
94
|
+
setFormModel((prevState) => {
|
|
95
|
+
// model of a subtree is the same for each of the keys
|
|
96
|
+
const modelName = keys[0].split(".")[0];
|
|
97
|
+
let arrayIndex;
|
|
98
|
+
const model = prevState.find((m, index) => {
|
|
99
|
+
if (Object.keys(m).includes(modelName)) {
|
|
100
|
+
arrayIndex = index;
|
|
101
|
+
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return false;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (model === undefined) {
|
|
109
|
+
return prevState;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const newState = cloneDeep(prevState);
|
|
113
|
+
keys.forEach((key) => {
|
|
114
|
+
const isEditable = get(model, key) !== null;
|
|
115
|
+
|
|
116
|
+
if (isEditable) {
|
|
117
|
+
set(model, key, !currentValue);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
newState.splice(arrayIndex, 1, model);
|
|
121
|
+
setHasUnsavedChanges(!isEqual(originalFormModel, newState) || showModalChangedAlert);
|
|
122
|
+
|
|
123
|
+
return newState;
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const link = "https://localazy.com/docs/strapi";
|
|
128
|
+
const onReadDocumentationClick = () => {
|
|
129
|
+
window.open(link, "_blank");
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
async function fetchData() {
|
|
134
|
+
setIsLoading(true);
|
|
135
|
+
setIsLoggedIn(hasLocalazyIdentity());
|
|
136
|
+
|
|
137
|
+
if (!hasLocalazyIdentity()) {
|
|
138
|
+
setIsLoading(false);
|
|
139
|
+
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Fetch current models schemas
|
|
145
|
+
*/
|
|
146
|
+
const [models, localizableModels] = await Promise.all([
|
|
147
|
+
StrapiModelService.getModels(),
|
|
148
|
+
StrapiModelService.getLocalizableModels(),
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Fetch stored content transfer setup
|
|
153
|
+
*/
|
|
154
|
+
const storedContentTransferSetup =
|
|
155
|
+
await PluginSettingsService.getContentTransferSetup();
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Build and set accordion expanded state model
|
|
159
|
+
*/
|
|
160
|
+
const itemsExpandedModel = buildItemsExpandedModel(localizableModels);
|
|
161
|
+
setItemsExpandedModel(itemsExpandedModel);
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Build and set form model
|
|
165
|
+
*/
|
|
166
|
+
const allModelsTree = getModelsTree(models, models);
|
|
167
|
+
|
|
168
|
+
const localizableTree = getModelsTree(models, localizableModels);
|
|
169
|
+
setTreeModelsSchemas(localizableTree);
|
|
170
|
+
|
|
171
|
+
const computedFormModel = buildContentTransferSetupSchema(
|
|
172
|
+
localizableTree,
|
|
173
|
+
storedContentTransferSetup.setup,
|
|
174
|
+
allModelsTree
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
setFormModel(computedFormModel);
|
|
178
|
+
setOriginalFormModel(cloneDeep(computedFormModel));
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Handle alerts onload apperance
|
|
182
|
+
*/
|
|
183
|
+
const localHasModelChanged = await hasModelChanged(localizableTree, storedContentTransferSetup.setup);
|
|
184
|
+
setShowModalChangedAlert(localHasModelChanged);
|
|
185
|
+
setHasUnsavedChanges(localHasModelChanged)
|
|
186
|
+
|
|
187
|
+
setIsLoading(false);
|
|
188
|
+
}
|
|
189
|
+
fetchData();
|
|
190
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
191
|
+
}, []);
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<>
|
|
195
|
+
{!isLoading && !isLoggedIn && <Redirect to="/plugins/localazy/login" />}
|
|
196
|
+
|
|
197
|
+
<HeaderLayout
|
|
198
|
+
title={t("plugin_settings.content_transfer_setup")}
|
|
199
|
+
subtitle={t("plugin_settings.content_transfer_setup_description")}
|
|
200
|
+
primaryAction={
|
|
201
|
+
<Flex gap={2}>
|
|
202
|
+
<Button
|
|
203
|
+
variant="secondary"
|
|
204
|
+
disabled={!hasUnsavedChanges}
|
|
205
|
+
onClick={onCancelClick}
|
|
206
|
+
>
|
|
207
|
+
{t("plugin_settings.cancel")}
|
|
208
|
+
</Button>
|
|
209
|
+
<Button
|
|
210
|
+
startIcon={<Check />}
|
|
211
|
+
disabled={!hasUnsavedChanges}
|
|
212
|
+
onClick={() => { saveContentTransferSetup(formModel) }}
|
|
213
|
+
>
|
|
214
|
+
{t("plugin_settings.save")}
|
|
215
|
+
</Button>
|
|
216
|
+
</Flex>
|
|
217
|
+
}
|
|
218
|
+
as="h2"
|
|
219
|
+
/>
|
|
220
|
+
<Box marginRight={10} marginLeft={10}>
|
|
221
|
+
{!isLoading && showAlert && (
|
|
222
|
+
<Box marginBottom={8}>
|
|
223
|
+
<Alert
|
|
224
|
+
onClose={() => setShowAlert(false)}
|
|
225
|
+
closeLabel={t("plugin_settings.close")}
|
|
226
|
+
title={t("plugin_settings.content_transfer_setup_saved")}
|
|
227
|
+
variant="success"
|
|
228
|
+
>
|
|
229
|
+
{t("plugin_settings.content_transfer_setup_saved_successfully")}
|
|
230
|
+
</Alert>
|
|
231
|
+
</Box>
|
|
232
|
+
)}
|
|
233
|
+
{!isLoading && showModalChangedAlert && (
|
|
234
|
+
<Box marginBottom={8}>
|
|
235
|
+
<Alert
|
|
236
|
+
onClose={() => setShowModalChangedAlert(false)}
|
|
237
|
+
closeLabel={t("plugin_settings.close")}
|
|
238
|
+
title={t("plugin_settings.content_types_model_changed")}
|
|
239
|
+
variant="default"
|
|
240
|
+
>
|
|
241
|
+
{t("plugin_settings.please_update_your_content")}
|
|
242
|
+
</Alert>
|
|
243
|
+
</Box>
|
|
244
|
+
)}
|
|
245
|
+
{!isLoading && (
|
|
246
|
+
<Box
|
|
247
|
+
background="neutral0"
|
|
248
|
+
padding={7}
|
|
249
|
+
paddingTop={6}
|
|
250
|
+
shadow="tableShadow"
|
|
251
|
+
hasRadius
|
|
252
|
+
>
|
|
253
|
+
{formModel.map((tree, index) => {
|
|
254
|
+
return (
|
|
255
|
+
<Box
|
|
256
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
257
|
+
key={`box_tree_${index}`}
|
|
258
|
+
marginBottom={3}
|
|
259
|
+
>
|
|
260
|
+
<Tree onTreeItemClick={onTreeItemClick} objects={tree} />
|
|
261
|
+
</Box>
|
|
262
|
+
);
|
|
263
|
+
})}
|
|
264
|
+
<Box
|
|
265
|
+
paddingTop={6}
|
|
266
|
+
paddingBottom={6}
|
|
267
|
+
>
|
|
268
|
+
<Divider />
|
|
269
|
+
</Box>
|
|
270
|
+
<Typography variant="omega">{t("plugin_settings.you_can_upload_download")}</Typography>
|
|
271
|
+
<Typography variant="omega" fontWeight="semiBold">{t("plugin_settings.only_text_based_content")}</Typography>
|
|
272
|
+
<br />
|
|
273
|
+
<br />
|
|
274
|
+
<Typography variant="omega">{t("plugin_settings.learn_more_in_docs_message_a")}</Typography>
|
|
275
|
+
<Typography
|
|
276
|
+
onClick={onReadDocumentationClick}
|
|
277
|
+
variant="omega"
|
|
278
|
+
fontWeight="semiBold"
|
|
279
|
+
textColor="primary600"
|
|
280
|
+
style={{ cursor: "pointer" }}
|
|
281
|
+
>
|
|
282
|
+
{t("plugin_settings.learn_more_in_docs_message_b")}
|
|
283
|
+
</Typography>
|
|
284
|
+
</Box>
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
</Box>
|
|
288
|
+
</>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export default ContentTransferSetup;
|