@truedat/core 7.2.11 → 7.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/core",
3
- "version": "7.2.11",
3
+ "version": "7.3.1",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -36,7 +36,7 @@
36
36
  "@testing-library/react": "^12.0.0",
37
37
  "@testing-library/react-hooks": "^8.0.1",
38
38
  "@testing-library/user-event": "^13.2.1",
39
- "@truedat/test": "7.2.11",
39
+ "@truedat/test": "7.3.1",
40
40
  "babel-jest": "^28.1.0",
41
41
  "babel-plugin-dynamic-import-node": "^2.3.3",
42
42
  "babel-plugin-lodash": "^3.3.4",
@@ -118,5 +118,5 @@
118
118
  "react-dom": ">= 16.8.6 < 17",
119
119
  "semantic-ui-react": ">= 2.0.3 < 2.2"
120
120
  },
121
- "gitHead": "74eb04f81dd49275229cf3050b56b897ff78410e"
121
+ "gitHead": "7101536d0432c47d5045efaf2cbb3f87d77c4c95"
122
122
  }
@@ -0,0 +1,84 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useEffect, useMemo, useState } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { Tab } from "semantic-ui-react";
5
+ import { useIntl } from "react-intl";
6
+
7
+ const LanguagesTabs = ({
8
+ altLangs = [],
9
+ requiredLangs = [],
10
+ selectedLang,
11
+ onLangChange,
12
+ }) => {
13
+ const [translationTabs, setTranslationTabs] = useState([]);
14
+ const [initLang, setInitLang] = useState(selectedLang);
15
+ const { formatMessage } = useIntl();
16
+
17
+ // Create the translation tabs
18
+ useMemo(() => {
19
+ const updatedTranslationTabs = [
20
+ // First add required languages
21
+ ...requiredLangs
22
+ .filter((lang) => altLangs.includes(lang))
23
+ .sort((a, b) => a.localeCompare(b))
24
+ .map((lang) => ({
25
+ lang,
26
+ menuItem: `${formatMessage({
27
+ id: `i18n.messages.locale.${lang}`,
28
+ defaultMessage: lang,
29
+ })} *`,
30
+ })),
31
+ // Then add non-required languages
32
+ ...altLangs
33
+ .filter((lang) => !requiredLangs.includes(lang))
34
+ .sort((a, b) => a.localeCompare(b))
35
+ .map((lang) => ({
36
+ lang,
37
+ menuItem: formatMessage({
38
+ id: `i18n.messages.locale.${lang}`,
39
+ defaultMessage: lang,
40
+ }),
41
+ })),
42
+ ];
43
+ const initSelectedLang = _.head(updatedTranslationTabs);
44
+ setTranslationTabs(updatedTranslationTabs);
45
+ initSelectedLang?.lang !== initLang && setInitLang(initSelectedLang?.lang);
46
+ // eslint-disable-next-line react-hooks/exhaustive-deps
47
+ }, [requiredLangs, altLangs, formatMessage]);
48
+
49
+ useEffect(() => {
50
+ initLang !== selectedLang && onLangChange(initLang);
51
+ // eslint-disable-next-line react-hooks/exhaustive-deps
52
+ }, [initLang]);
53
+
54
+ // Return null if there are no alternate languages
55
+ if (!altLangs || altLangs.length === 0) {
56
+ return null;
57
+ }
58
+
59
+ return (
60
+ <Tab
61
+ className="attached-tab"
62
+ attached="top"
63
+ panes={translationTabs}
64
+ onTabChange={(e, { activeIndex }) => {
65
+ const selected = translationTabs[activeIndex]?.lang;
66
+ if (selected) {
67
+ onLangChange(selected);
68
+ }
69
+ }}
70
+ activeIndex={translationTabs.findIndex(
71
+ (tab) => tab.lang === selectedLang
72
+ )}
73
+ />
74
+ );
75
+ };
76
+
77
+ LanguagesTabs.propTypes = {
78
+ altLangs: PropTypes.arrayOf(PropTypes.string),
79
+ requiredLangs: PropTypes.arrayOf(PropTypes.string),
80
+ selectedLang: PropTypes.string,
81
+ onLangChange: PropTypes.func.isRequired,
82
+ };
83
+
84
+ export default LanguagesTabs;
@@ -28,6 +28,7 @@ import GroupActions from "./GroupActions";
28
28
  import HierarchySelector from "./HierarchySelector";
29
29
  import HistoryBackButton from "./HistoryBackButton";
30
30
  import IngestMenu from "./IngestMenu";
31
+ import LanguagesTabs from "./LanguagesTabs";
31
32
  import LineageMenu from "./LineageMenu";
32
33
  import Loading from "./Loading";
33
34
  import MembersMenu from "./MembersMenu";
@@ -85,6 +86,7 @@ export {
85
86
  HierarchySelector,
86
87
  HistoryBackButton,
87
88
  IngestMenu,
89
+ LanguagesTabs,
88
90
  LineageMenu,
89
91
  Loading,
90
92
  MembersMenu,
@@ -8,6 +8,7 @@ const toApiLocalesPath = compile(API_LOCALES);
8
8
 
9
9
  export const useLocales = (includeMessages = true) => {
10
10
  const url = toApiLocalesPath() + "?includeMessages=" + includeMessages;
11
+
11
12
  const { data, error, mutate, isValidating, isLoading } = useSWR(
12
13
  url,
13
14
  apiJson,
@@ -25,6 +25,7 @@ const defaultContext = {
25
25
  locales: [{ lang: "en", messages: {} }],
26
26
  localesError: null,
27
27
  mutate: () => {},
28
+ setAltLang: () => {},
28
29
  };
29
30
 
30
31
  export const LanguageContext = createContext(defaultContext);
@@ -44,10 +45,10 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
44
45
  } = useLocales(false);
45
46
 
46
47
  const loading = loadingLocales || loadingAllLocales;
47
- const mutate = () => {
48
+ const mutate = useCallback(() => {
48
49
  mutateLocales();
49
50
  mutateAllLocales();
50
- };
51
+ }, [mutateLocales, mutateAllLocales]);
51
52
 
52
53
  const langsOf = _.map(({ lang }) => lang);
53
54
  const enabledLangs = useMemo(
@@ -56,16 +57,17 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
56
57
  _.filter(({ is_enabled }) => is_enabled),
57
58
  langsOf
58
59
  )(locales),
59
- [locales]
60
+ [locales, langsOf]
60
61
  );
61
62
 
62
63
  const altLangs = useMemo(
63
64
  () =>
64
65
  _.flow(
65
66
  _.filter(({ is_enabled, is_default }) => is_enabled && !is_default),
67
+ _.orderBy(["is_required", "lang"], ["desc", "asc"]),
66
68
  langsOf
67
69
  )(locales),
68
- [locales]
70
+ [locales, langsOf]
69
71
  );
70
72
 
71
73
  const requiredLangs = useMemo(
@@ -74,7 +76,7 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
74
76
  _.filter(({ is_required }) => is_required),
75
77
  langsOf
76
78
  )(locales),
77
- [locales]
79
+ [locales, langsOf]
78
80
  );
79
81
 
80
82
  const defaultLang = useMemo(
@@ -97,7 +99,7 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
97
99
  _.map(({ lang, messages }) => [lang, mapMessages(messages)]),
98
100
  _.fromPairs
99
101
  )(locales),
100
- [locales]
102
+ [locales, mapMessages]
101
103
  );
102
104
 
103
105
  const [lang, setLang] = useState(defaultLang);
@@ -131,7 +133,6 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
131
133
  [
132
134
  defaultLang,
133
135
  altLangs,
134
- enabledLangs,
135
136
  allLocales,
136
137
  locales,
137
138
  enabledLangs,
@@ -161,6 +162,7 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
161
162
  setAltLang(firstNonDefaultLang);
162
163
  }
163
164
  }
165
+ // eslint-disable-next-line react-hooks/exhaustive-deps
164
166
  }, [enabledLangs, altLang]);
165
167
 
166
168
  if (loading || !lang) return <Loading />;
@@ -2,7 +2,7 @@ import {
2
2
  splitTranslatableFields,
3
3
  formatLocales,
4
4
  hasTranslatableFields,
5
- isTranslatetableField,
5
+ isTranslatableField,
6
6
  } from "../i18nContent";
7
7
 
8
8
  describe("services: i18nContent", () => {
@@ -148,17 +148,17 @@ describe("services: i18nContent", () => {
148
148
  });
149
149
  });
150
150
 
151
- describe("isTranslatetableField", () => {
151
+ describe("isTranslatableField", () => {
152
152
  it("should identify translatable fields", () => {
153
- expect(isTranslatetableField({ widget: "string" })).toBe(true);
154
- expect(isTranslatetableField({ widget: "enriched_text" })).toBe(true);
155
- expect(isTranslatetableField({ widget: "textarea" })).toBe(true);
153
+ expect(isTranslatableField({ widget: "string" })).toBe(true);
154
+ expect(isTranslatableField({ widget: "enriched_text" })).toBe(true);
155
+ expect(isTranslatableField({ widget: "textarea" })).toBe(true);
156
156
  });
157
157
 
158
158
  it("should identify non-translatable fields", () => {
159
- expect(isTranslatetableField({ widget: "number" })).toBe(false);
160
- expect(isTranslatetableField({ widget: "date" })).toBe(false);
161
- expect(isTranslatetableField({ widget: "boolean" })).toBe(false);
159
+ expect(isTranslatableField({ widget: "number" })).toBe(false);
160
+ expect(isTranslatableField({ widget: "date" })).toBe(false);
161
+ expect(isTranslatableField({ widget: "boolean" })).toBe(false);
162
162
  });
163
163
  });
164
164
  });
@@ -69,6 +69,6 @@ export const hasTranslatableFields = (fields) => {
69
69
  );
70
70
  };
71
71
 
72
- export const isTranslatetableField = (field) => {
72
+ export const isTranslatableField = (field) => {
73
73
  return translatableFieldTypes.includes(field.widget);
74
74
  };