@truedat/core 7.2.8 → 7.2.10

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.8",
3
+ "version": "7.2.10",
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.8",
39
+ "@truedat/test": "7.2.10",
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": "1afa9892e13cd85f546e008f36008c4d25a6be2f"
121
+ "gitHead": "425c9b112aaab0b8a0b43160f818b21a3b32b926"
122
122
  }
@@ -8,21 +8,22 @@ const toApiLocalesPath = compile(API_LOCALES);
8
8
 
9
9
  export const useLocales = (includeMessages = true) => {
10
10
  const url = toApiLocalesPath() + "?includeMessages=" + includeMessages;
11
- const { data, error, mutate, isValidating } = useSWR(url, apiJson, {
12
- revalidateOnFocus: false,
13
- });
11
+ const { data, error, mutate, isValidating, isLoading } = useSWR(
12
+ url,
13
+ apiJson,
14
+ {
15
+ revalidateOnFocus: false,
16
+ }
17
+ );
14
18
 
15
19
  const locales = data?.data?.data;
16
- return { locales, error, loading: !error && !data, mutate, isValidating };
20
+ return { locales, error, loading: isValidating || isLoading, mutate };
17
21
  };
18
22
 
19
23
  export const useLocalesUpdate = () => {
20
24
  return useSWRMutations("api/locales", (_url, { arg }) => {
21
- const { id, locale, mutateData, handleDimmer } = arg;
25
+ const { id, locale } = arg;
22
26
  const toApiPath = compile(API_LOCALE);
23
- apiJsonPatch(toApiPath({ id }), { id, locale }).then(() => {
24
- mutateData();
25
- handleDimmer(false);
26
- });
27
+ return apiJsonPatch(toApiPath({ id }), { id, locale });
27
28
  });
28
29
  };
@@ -33,10 +33,21 @@ export const useLanguage = () => useContext(LanguageContext);
33
33
  const LanguageContextProvider = ({ children, defaultMessages }) => {
34
34
  const {
35
35
  locales,
36
- mutate,
36
+ mutate: mutateLocales,
37
37
  error: localesError,
38
- isValidating: loading,
38
+ loading: loadingLocales,
39
39
  } = useLocales();
40
+ const {
41
+ locales: allLocales,
42
+ mutate: mutateAllLocales,
43
+ loading: loadingAllLocales,
44
+ } = useLocales(false);
45
+
46
+ const loading = loadingLocales || loadingAllLocales;
47
+ const mutate = () => {
48
+ mutateLocales();
49
+ mutateAllLocales();
50
+ };
40
51
 
41
52
  const langsOf = _.map(({ lang }) => lang);
42
53
  const enabledLangs = useMemo(
@@ -112,6 +123,7 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
112
123
  getMessagesForLang,
113
124
  lang,
114
125
  loading,
126
+ allLocales,
115
127
  locales,
116
128
  localesError,
117
129
  mutate,
@@ -120,6 +132,7 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
120
132
  defaultLang,
121
133
  altLangs,
122
134
  enabledLangs,
135
+ allLocales,
123
136
  locales,
124
137
  enabledLangs,
125
138
  altLang,
@@ -128,6 +141,7 @@ const LanguageContextProvider = ({ children, defaultMessages }) => {
128
141
  loading,
129
142
  getMessagesForLang,
130
143
  localesError,
144
+ mutate,
131
145
  ]
132
146
  );
133
147
 
@@ -19,18 +19,20 @@ import {
19
19
  } from "semantic-ui-react";
20
20
  import { ConfirmModal } from "@truedat/core/components";
21
21
  import { useLocalesUpdate } from "../../hooks/useLocales";
22
+ import { useLanguage } from "./LangProvider";
22
23
 
23
- const LanguajeRow = ({
24
- locale: { id, lang, name, local_name, is_default, is_required, trigger },
24
+ const LanguageRow = ({
25
+ locale: { id, lang, name, local_name, is_default, is_required },
25
26
  anyDefault,
26
- mutate,
27
- handleDimmer,
28
27
  }) => {
29
28
  const { formatMessage } = useIntl();
29
+ const { trigger } = useLocalesUpdate();
30
+ const { mutate } = useLanguage();
30
31
 
31
32
  const handleChange = (data) => {
32
- handleDimmer(true);
33
- trigger(_.merge({ mutateData: mutate, handleDimmer: handleDimmer })(data));
33
+ trigger(data).then(() => {
34
+ mutate();
35
+ });
34
36
  };
35
37
 
36
38
  return (
@@ -112,31 +114,25 @@ const LanguajeRow = ({
112
114
  );
113
115
  };
114
116
 
115
- LanguajeRow.propTypes = {
117
+ LanguageRow.propTypes = {
116
118
  locale: PropTypes.object,
117
119
  anyDefault: PropTypes.bool,
118
- mutate: PropTypes.func,
119
- handleDimmer: PropTypes.func,
120
120
  };
121
121
 
122
- const Languages = ({ locales, mutate, isValidating }) => {
123
- const { formatMessage } = useIntl();
124
- const [newLocale, setNewLocales] = useState(null);
125
- const [dimmerState, setDimmerState] = useState(false);
122
+ const Languages = () => {
123
+ const { allLocales: locales, mutate, loading } = useLanguage();
126
124
  const { trigger } = useLocalesUpdate();
127
125
 
128
- const handleDimmer = (isMutating) => {
129
- setDimmerState(isMutating);
130
- };
126
+ const { formatMessage } = useIntl();
127
+ const [newLocale, setNewLocales] = useState(null);
131
128
 
132
129
  const anyDefault = !!_.find(({ is_default }) => is_default)(locales);
133
130
 
134
131
  const options = _.flow(
135
132
  _.filter(({ is_enabled }) => !is_enabled),
136
133
  _.orderBy("lang", "asc"),
137
- _.keyBy("lang"),
138
- _.map(({ lang, name, local_name }) => {
139
- return { text: `${name} ( ${local_name} )`, value: lang };
134
+ _.map(({ id, name, local_name }) => {
135
+ return { text: `${name} ( ${local_name} )`, value: id };
140
136
  })
141
137
  )(locales);
142
138
 
@@ -147,10 +143,8 @@ const Languages = ({ locales, mutate, isValidating }) => {
147
143
  const handleSubmit = () => {
148
144
  setNewLocales(null);
149
145
  trigger({
150
- id: locales[newLocale].id,
146
+ id: newLocale,
151
147
  locale: { is_enabled: true },
152
- mutateData: mutate,
153
- handleDimmer,
154
148
  }).then(() => {
155
149
  mutate();
156
150
  });
@@ -190,9 +184,8 @@ const Languages = ({ locales, mutate, isValidating }) => {
190
184
  })}
191
185
  </Button>
192
186
  </Form>
193
-
194
- <Dimmer.Dimmable dimmed={isValidating || dimmerState}>
195
- <Dimmer active={isValidating || dimmerState} inverted>
187
+ <Dimmer.Dimmable dimmed={loading}>
188
+ <Dimmer active={loading} inverted>
196
189
  <Loader />
197
190
  </Dimmer>
198
191
  <Table collapsing striped>
@@ -221,18 +214,13 @@ const Languages = ({ locales, mutate, isValidating }) => {
221
214
  ["is_default", "is_required", "lang"],
222
215
  ["desc", "desc", "asc"]
223
216
  ),
224
- _.map((locale) => {
225
- return (
226
- <LanguajeRow
227
- key={locale.lang}
228
- locale={{ ...locale, trigger }}
229
- locales={locales}
230
- anyDefault={anyDefault}
231
- mutate={mutate}
232
- handleDimmer={handleDimmer}
233
- />
234
- );
235
- })
217
+ _.map((locale) => (
218
+ <LanguageRow
219
+ key={locale.lang}
220
+ locale={locale}
221
+ anyDefault={anyDefault}
222
+ />
223
+ ))
236
224
  )(locales)}
237
225
  </TableBody>
238
226
  </Table>
@@ -241,10 +229,4 @@ const Languages = ({ locales, mutate, isValidating }) => {
241
229
  );
242
230
  };
243
231
 
244
- Languages.propTypes = {
245
- locales: PropTypes.array,
246
- mutate: PropTypes.func,
247
- isValidating: PropTypes.bool,
248
- };
249
-
250
232
  export default Languages;
@@ -1,6 +1,6 @@
1
1
  import _ from "lodash/fp";
2
2
  import React, { useState } from "react";
3
- import PropTypes from "prop-types";
3
+ import { Link, useLocation, useHistory } from "react-router-dom";
4
4
  import { useIntl, FormattedMessage } from "react-intl";
5
5
  import {
6
6
  Button,
@@ -10,10 +10,9 @@ import {
10
10
  Segment,
11
11
  Menu,
12
12
  } from "semantic-ui-react";
13
- import { Link } from "react-router-dom";
14
13
  import { SearchInput } from "@truedat/core/components";
15
14
  import { lowerDeburrTrim } from "@truedat/core/services/sort";
16
- import { I18N_MESSAGES_NEW } from "@truedat/core/routes";
15
+ import { I18N_MESSAGES, I18N_MESSAGES_NEW } from "@truedat/core/routes";
17
16
  import { Pagination } from "@truedat/core/components";
18
17
  import { useLanguage } from "./LangProvider";
19
18
  import MessagesTable from "./MessagesTable";
@@ -21,38 +20,55 @@ import Languages from "./Languages";
21
20
 
22
21
  const ITEMS_PER_PAGE = 30;
23
22
 
24
- export function MessagesContent({ locales, mutate }) {
25
- const [selectedLang, setSelectedLang] = useState(
26
- _.flow(
27
- _.find(({ is_default }) => is_default),
28
- _.pathOr("en", "lang")
29
- )(locales)
30
- );
23
+ export function MessagesContent() {
24
+ const { locales, loading } = useLanguage();
25
+
26
+ const history = useHistory();
27
+ const location = useLocation();
28
+ const searchParams = new URLSearchParams(location.search);
29
+ const selectedLang = searchParams.get("lang");
30
+ const filter = searchParams.get("filter") || "";
31
+
32
+ const urlTo = (props) => {
33
+ const queryParams = _.flow(
34
+ _.toPairs,
35
+ _.filter(([_, value]) => value),
36
+ _.fromPairs,
37
+ (params) => new URLSearchParams(params)
38
+ )({
39
+ lang: selectedLang,
40
+ filter,
41
+ ...props,
42
+ });
43
+
44
+ return `${I18N_MESSAGES}?${queryParams.toString()}`;
45
+ };
31
46
 
32
- const [selectedManageView, setSelectedManageView] = useState(false);
33
47
  const [page, setPage] = useState(1);
34
- const [filter, setFilter] = useState("");
35
48
  const { formatMessage } = useIntl();
36
49
 
37
50
  const handleSearch = (_e, data) => {
38
- _.flow(_.propOr("", "value"), setFilter)(data);
51
+ const filter = _.propOr("", "value")(data);
39
52
  setPage(1);
53
+ history.push(urlTo({ filter }));
40
54
  };
41
55
 
42
- const messages = _.flow(
43
- _.find({ lang: selectedLang }),
44
- _.prop("messages"),
45
- _.orderBy("message_id", "asc"),
46
- _.filter(({ message_id, definition, description }) => {
47
- const deburrFilter = lowerDeburrTrim(filter);
48
- return (
49
- deburrFilter == "" ||
50
- lowerDeburrTrim(message_id).includes(deburrFilter) ||
51
- lowerDeburrTrim(definition).includes(deburrFilter) ||
52
- lowerDeburrTrim(description).includes(deburrFilter)
53
- );
54
- })
55
- )(locales);
56
+ const messages = selectedLang
57
+ ? _.flow(
58
+ _.find({ lang: selectedLang }),
59
+ _.prop("messages"),
60
+ _.orderBy("message_id", "asc"),
61
+ _.filter(({ message_id, definition, description }) => {
62
+ const deburrFilter = lowerDeburrTrim(filter);
63
+ return (
64
+ deburrFilter == "" ||
65
+ lowerDeburrTrim(message_id).includes(deburrFilter) ||
66
+ lowerDeburrTrim(definition).includes(deburrFilter) ||
67
+ lowerDeburrTrim(description).includes(deburrFilter)
68
+ );
69
+ })
70
+ )(locales)
71
+ : [];
56
72
 
57
73
  const totalPages = Math.ceil(messages.length / ITEMS_PER_PAGE);
58
74
  const paginatedMessages = _.flow(
@@ -65,8 +81,9 @@ export function MessagesContent({ locales, mutate }) {
65
81
  <Menu attached="top" secondary pointing tabular>
66
82
  <Menu.Item
67
83
  key={0}
68
- active={selectedManageView}
69
- onClick={() => setSelectedManageView(true)}
84
+ active={!selectedLang}
85
+ as={Link}
86
+ to={urlTo({ lang: null })}
70
87
  >
71
88
  <FormattedMessage id="i18n.messages.locale.manage" />
72
89
  </Menu.Item>
@@ -79,11 +96,9 @@ export function MessagesContent({ locales, mutate }) {
79
96
  _.map(({ lang, name, local_name }) => (
80
97
  <Menu.Item
81
98
  key={lang}
82
- active={lang === selectedLang && !selectedManageView}
83
- onClick={() => {
84
- setSelectedLang(lang);
85
- setSelectedManageView(false);
86
- }}
99
+ active={lang === selectedLang}
100
+ as={Link}
101
+ to={urlTo({ lang })}
87
102
  >
88
103
  <FormattedMessage
89
104
  id={`i18n.messages.locale.${lang}`}
@@ -94,7 +109,7 @@ export function MessagesContent({ locales, mutate }) {
94
109
  )(locales)}
95
110
  </Menu>
96
111
  <Divider hidden />
97
- {!selectedManageView ? (
112
+ {selectedLang ? (
98
113
  <>
99
114
  <SearchInput
100
115
  onChange={handleSearch}
@@ -103,7 +118,7 @@ export function MessagesContent({ locales, mutate }) {
103
118
  })}
104
119
  value={filter}
105
120
  />
106
- <MessagesTable messages={paginatedMessages} locales={locales} />
121
+ <MessagesTable messages={paginatedMessages} loading={loading} />
107
122
  <Pagination
108
123
  totalPages={totalPages}
109
124
  activePage={page}
@@ -111,21 +126,15 @@ export function MessagesContent({ locales, mutate }) {
111
126
  />
112
127
  </>
113
128
  ) : (
114
- <Languages locales={_.keyBy("lang")(locales)} mutate={mutate} />
129
+ <Languages />
115
130
  )}
116
131
  </>
117
132
  );
118
133
  }
119
134
 
120
- MessagesContent.propTypes = {
121
- locales: PropTypes.array,
122
- mutate: PropTypes.func,
123
- };
124
-
125
135
  export default function Messages() {
126
136
  const { formatMessage } = useIntl();
127
-
128
- const { locales, mutate } = useLanguage();
137
+ const { mutate } = useLanguage();
129
138
 
130
139
  return (
131
140
  <Segment>
@@ -145,6 +154,13 @@ export default function Messages() {
145
154
  </Header.Content>
146
155
  </Header>
147
156
  <Segment attached="bottom">
157
+ <Button
158
+ floated="right"
159
+ content={formatMessage({ id: "i18n.actions.refreshMessages" })}
160
+ onClick={() => {
161
+ mutate();
162
+ }}
163
+ />
148
164
  <Button
149
165
  floated="right"
150
166
  primary
@@ -153,7 +169,7 @@ export default function Messages() {
153
169
  as={Link}
154
170
  to={I18N_MESSAGES_NEW}
155
171
  />
156
- <MessagesContent locales={locales} mutate={mutate} />
172
+ <MessagesContent />
157
173
  </Segment>
158
174
  </Segment>
159
175
  );
@@ -5,15 +5,19 @@ import { useIntl, FormattedMessage } from "react-intl";
5
5
  import { useHistory, Link } from "react-router-dom";
6
6
  import { useMessagePost } from "@truedat/core/hooks";
7
7
  import { I18N_MESSAGES } from "@truedat/core/routes";
8
+ import { useLanguage } from "./LangProvider";
8
9
  import MessageForm from "./MessageForm";
9
10
 
10
11
  const NewMessage = () => {
11
12
  const { formatMessage } = useIntl();
12
13
  const { trigger } = useMessagePost();
14
+ const { mutate } = useLanguage();
13
15
  const history = useHistory();
14
16
 
15
17
  const onSubmit = (message) => {
16
- trigger({ message });
18
+ trigger({ message }).then(() => {
19
+ mutate();
20
+ });
17
21
  history.push(I18N_MESSAGES);
18
22
  };
19
23
 
@@ -4,7 +4,11 @@ import { LangProviderWrapper } from "@truedat/core/i18n";
4
4
  import Messages from "../Messages";
5
5
 
6
6
  const renderOpts = {
7
- messages: {},
7
+ messages: {
8
+ en: {
9
+ "i18n.actions.refreshMessages": "Refresh messages",
10
+ },
11
+ },
8
12
  };
9
13
 
10
14
  jest.mock("@truedat/core/hooks", () => ({
@@ -26,6 +26,11 @@ exports[`<Messages /> matches the latest snapshot 1`] = `
26
26
  <div
27
27
  class="ui bottom attached segment"
28
28
  >
29
+ <button
30
+ class="ui right floated button"
31
+ >
32
+ Refresh messages
33
+ </button>
29
34
  <a
30
35
  class="ui primary right floated button"
31
36
  href="/i18n/messages/new"
@@ -41,12 +46,14 @@ exports[`<Messages /> matches the latest snapshot 1`] = `
41
46
  class="ui pointing secondary top attached tabular menu"
42
47
  >
43
48
  <a
44
- class="item"
49
+ class="active item"
50
+ href="/i18n/messages"
45
51
  >
46
52
  i18n.messages.locale.manage
47
53
  </a>
48
54
  <a
49
- class="active item"
55
+ class="item"
56
+ href="/i18n/messages?lang=es"
50
57
  >
51
58
  undefined ( undefined )
52
59
  </a>
@@ -54,32 +61,102 @@ exports[`<Messages /> matches the latest snapshot 1`] = `
54
61
  <div
55
62
  class="ui hidden divider"
56
63
  />
57
- <div
58
- class="ui icon input"
64
+ <form
65
+ class="ui form"
59
66
  >
60
- <input
61
- placeholder="i18n.messages.search.placeholder"
62
- type="text"
63
- value=""
64
- />
65
- <i
66
- aria-hidden="true"
67
- class="search link icon"
68
- />
69
- </div>
70
- <h4
71
- class="ui header"
67
+ <div
68
+ aria-expanded="false"
69
+ class="ui search selection dropdown lang-manager-dropdown"
70
+ name="add-locales"
71
+ role="combobox"
72
+ >
73
+ <input
74
+ aria-autocomplete="list"
75
+ autocomplete="off"
76
+ class="search"
77
+ tabindex="0"
78
+ type="text"
79
+ value=""
80
+ />
81
+ <div
82
+ aria-atomic="true"
83
+ aria-live="polite"
84
+ class="divider default text"
85
+ role="alert"
86
+ >
87
+ Select languaje
88
+ </div>
89
+ <i
90
+ aria-hidden="true"
91
+ class="dropdown icon"
92
+ />
93
+ <div
94
+ aria-multiselectable="false"
95
+ class="menu transition"
96
+ role="listbox"
97
+ >
98
+ <div
99
+ class="message"
100
+ >
101
+ No results found.
102
+ </div>
103
+ </div>
104
+ </div>
105
+ <button
106
+ class="ui disabled button lang-manager-button"
107
+ disabled=""
108
+ tabindex="-1"
109
+ type="submit"
110
+ >
111
+ i18n.messages.locale.add_lang
112
+ </button>
113
+ </form>
114
+ <div
115
+ class="dimmable"
72
116
  >
73
- <i
74
- aria-hidden="true"
75
- class="search icon"
76
- />
77
117
  <div
78
- class="content"
118
+ class="ui inverted dimmer"
79
119
  >
80
- i18n.messages.empty
120
+ <div
121
+ class="content"
122
+ >
123
+ <div
124
+ class="ui loader"
125
+ />
126
+ </div>
81
127
  </div>
82
- </h4>
128
+ <table
129
+ class="ui collapsing striped table"
130
+ >
131
+ <thead
132
+ class=""
133
+ >
134
+ <tr
135
+ class=""
136
+ >
137
+ <td
138
+ class=""
139
+ />
140
+ <td
141
+ class="center aligned"
142
+ >
143
+ i18n.messages.locale.required
144
+ </td>
145
+ <td
146
+ class="center aligned"
147
+ >
148
+ i18n.messages.locale.default
149
+ </td>
150
+ <td
151
+ class=""
152
+ />
153
+ </tr>
154
+ </thead>
155
+ <tbody
156
+ class=""
157
+ />
158
+ </table>
159
+ </div>
83
160
  </div>
84
161
  </div>
85
162
  </div>
@@ -54,12 +54,12 @@ describe("selectors: makeSearchQuerySelector", () => {
54
54
  const state = {
55
55
  conceptQuery: {
56
56
  ...conceptQuery,
57
- sort: [{ _score: "desc" }, { "name.raw": "asc" }],
57
+ sort: [{ _score: "desc" }],
58
58
  },
59
59
  conceptActiveFilters,
60
60
  };
61
61
  expect(searchQuerySelector(state)).toMatchObject({
62
- sort: [{ _score: "desc" }, { "name.raw": "asc" }],
62
+ sort: [{ _score: "desc" }],
63
63
  });
64
64
  });
65
65
  });