@truedat/core 5.20.0 → 5.20.2

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": "5.20.0",
3
+ "version": "5.20.2",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -117,5 +117,5 @@
117
117
  "react-dom": ">= 16.8.6 < 17",
118
118
  "semantic-ui-react": ">= 2.0.3 < 2.2"
119
119
  },
120
- "gitHead": "3981bdf2fff50f0d8c79643c6f423dfdc7f5a57f"
120
+ "gitHead": "4f02a44805ab1746f026b3fb53e8a3b31ec86765"
121
121
  }
package/src/api.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export const API_COMMENTS = "/api/business_concepts/comments";
2
+ export const API_LOCALE = "/api/locales/:id";
2
3
  export const API_LOCALE_MESSAGES = "/api/locales/:lang/messages";
3
4
  export const API_LOCALES = "/api/locales";
5
+ export const API_ALL_LOCALES = "/api/locales/all_locales";
4
6
  export const API_MESSAGE = "/api/messages/:id";
5
7
  export const API_MESSAGES = "/api/messages";
6
8
  export const API_REINDEX_GRANTS = "/api/grants/search/reindex_all";
@@ -38,6 +38,8 @@ describe("<SelectedFilters/>", () => {
38
38
  const messages = {
39
39
  "search.clear_filters": "clean filters",
40
40
  "search.save_filters": "save filters",
41
+ "search.applied_filters": "applied filters",
42
+ "filter.empty": "empty",
41
43
  };
42
44
 
43
45
  const renderOptions = {
@@ -0,0 +1,9 @@
1
+ import useSWR from "swr";
2
+ import { API_ALL_LOCALES } from "../api";
3
+ import { apiJson } from "../services/api";
4
+
5
+ export const useAllLocales = () => {
6
+ const { data, loading, error, mutate } = useSWR(API_ALL_LOCALES, apiJson);
7
+ const all_locales = data?.data?.data;
8
+ return { all_locales, error, loading, mutate };
9
+ };
@@ -1,9 +1,51 @@
1
+ import _ from "lodash/fp";
2
+ import { compile } from "path-to-regexp";
1
3
  import useSWR from "swr";
2
- import { API_LOCALES } from "../api";
3
- import { apiJson } from "../services/api";
4
+ import useSWRMutations from "swr/mutation";
5
+ import { API_LOCALES, API_LOCALE } from "../api";
6
+ import {
7
+ apiJson,
8
+ apiJsonDelete,
9
+ apiJsonPatch,
10
+ apiJsonPost,
11
+ } from "../services/api";
12
+
13
+ const toApiLocalesPath = compile(API_LOCALES);
14
+
15
+ export const useLocales = (includeMessages = true) => {
16
+ const url = toApiLocalesPath() + "?includeMessages=" + includeMessages;
17
+ const { data, error, mutate, isValidating } = useSWR(url, apiJson);
4
18
 
5
- export const useLocales = () => {
6
- const { data, error, mutate } = useSWR(API_LOCALES, apiJson);
7
19
  const locales = data?.data?.data;
8
- return { locales, error, loading: !error && !data, mutate };
20
+ return { locales, error, loading: !error && !data, mutate, isValidating };
21
+ };
22
+
23
+ export const useLocalesUpdate = (id) => {
24
+ const toApiPath = compile(API_LOCALE);
25
+ const url = toApiPath({ id });
26
+ return useSWRMutations(url, (url, { arg }) => {
27
+ const { mutateData, handleDimmer } = arg;
28
+ const payload = { id: arg.id, locale: arg };
29
+ apiJsonPatch(url, payload).then(() => {
30
+ mutateData();
31
+ handleDimmer(false);
32
+ });
33
+ });
34
+ };
35
+
36
+ export const useLocalesCreate = () => {
37
+ const url = API_LOCALES;
38
+
39
+ return useSWRMutations(url, (url, { arg }) => {
40
+ apiJsonPost(url, arg);
41
+ });
42
+ };
43
+
44
+ export const useLocalesDelete = (id) => {
45
+ const toApiPath = compile(API_LOCALE);
46
+ const url = toApiPath({ id });
47
+ return useSWRMutations(url, (url, { arg }) => {
48
+ const payload = { id: arg.id };
49
+ apiJsonDelete(url, payload);
50
+ });
9
51
  };
@@ -1,6 +1,5 @@
1
1
  import { compile } from "path-to-regexp";
2
- import { mutate } from "swr";
3
- import useSWR from "swr";
2
+ import useSWR, { mutate } from "swr";
4
3
  import useSWRMutations from "swr/mutation";
5
4
  import {
6
5
  API_LOCALE_MESSAGES,
@@ -0,0 +1,231 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useState } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
5
+ import {
6
+ Button,
7
+ Dimmer,
8
+ Dropdown,
9
+ Form,
10
+ Icon,
11
+ Input,
12
+ Loader,
13
+ Table,
14
+ TableBody,
15
+ TableCell,
16
+ TableHeader,
17
+ TableRow,
18
+ } from "semantic-ui-react";
19
+ import { ConfirmModal } from "@truedat/core/components";
20
+ import { useAllLocales } from "../../hooks/useAllLocales";
21
+ import {
22
+ useLocalesCreate,
23
+ useLocalesDelete,
24
+ useLocalesUpdate,
25
+ useLocales,
26
+ } from "../../hooks/useLocales";
27
+
28
+ const LanguajeRow = ({ code, local, name, config, mutate, handleDimmer }) => {
29
+ const { formatMessage } = useIntl();
30
+ const { trigger } = useLocalesUpdate(config.id);
31
+ const { trigger: triggerDelete } = useLocalesDelete(config.id);
32
+
33
+ const handleChange = (data) => {
34
+ const { name, checked } = data;
35
+ const newConfig = {
36
+ ...config,
37
+ [name]: !checked,
38
+ };
39
+ handleDimmer(true);
40
+ trigger({ ...newConfig, mutateData: mutate, handleDimmer: handleDimmer });
41
+ };
42
+
43
+ const handleDelete = () => {
44
+ triggerDelete(config).then(() => {
45
+ mutate();
46
+ });
47
+ };
48
+
49
+ return (
50
+ <TableRow>
51
+ <TableCell>
52
+ {_.upperCase(code)} | {local} ( {name} )
53
+ </TableCell>
54
+ <TableCell textAlign="center">
55
+ <Input
56
+ type="checkbox"
57
+ name="is_required"
58
+ checked={config.is_required}
59
+ disabled={config.is_default}
60
+ onChange={(_e, data) => handleChange(data)}
61
+ />
62
+ </TableCell>
63
+ <TableCell textAlign="center">
64
+ <Input
65
+ id={`radio-${code}`}
66
+ type="radio"
67
+ name="is_default"
68
+ checked={config.is_default}
69
+ onChange={(_e, data) => handleChange(data)}
70
+ />
71
+ </TableCell>
72
+ <TableCell>
73
+ <ConfirmModal
74
+ icon="trash"
75
+ trigger={
76
+ <Icon
77
+ className="lang-manager-delete"
78
+ name="trash alternate outline"
79
+ color="red"
80
+ disabled={config.is_default || ["es", "en"].includes(code)}
81
+ />
82
+ }
83
+ header={formatMessage({
84
+ id: "i18n.messages.locale.delete.confirmation.header",
85
+ })}
86
+ content={formatMessage({
87
+ id: "i18n.messages.locale.delete.confirmation.content",
88
+ })}
89
+ onConfirm={() => handleDelete()}
90
+ />
91
+ </TableCell>
92
+ </TableRow>
93
+ );
94
+ };
95
+
96
+ LanguajeRow.propTypes = {
97
+ code: PropTypes.string,
98
+ local: PropTypes.string,
99
+ name: PropTypes.string,
100
+ config: PropTypes.object,
101
+ mutate: PropTypes.func,
102
+ handleDimmer: PropTypes.func,
103
+ };
104
+
105
+ const Languages = () => {
106
+ const includeMessages = false;
107
+ const {
108
+ locales,
109
+ loading: loadingUseLocales,
110
+ mutate,
111
+ isValidating,
112
+ } = useLocales(includeMessages);
113
+ const langs = _.map("lang")(locales);
114
+
115
+ const { formatMessage } = useIntl();
116
+ const { all_locales, loading, error } = useAllLocales();
117
+ const [newLocales, setNewLocales] = useState([]);
118
+ const { trigger } = useLocalesCreate();
119
+ const [dimmerState, setDimmerState] = useState(false);
120
+
121
+ const handleDimmer = (isMutating) => {
122
+ setDimmerState(isMutating);
123
+ };
124
+
125
+ const langsConfig = _.flow(
126
+ _.map((locale) => _.omit("messages")(locale)),
127
+ _.groupBy("lang"),
128
+ _.mapValues(_.first)
129
+ )(locales);
130
+
131
+ const options = _.flow(
132
+ _.filter(({ code }) => {
133
+ return !langs.includes(code);
134
+ }),
135
+ _.map(({ code, name, local }) => {
136
+ return { text: `${local} (${name} | ${code})`, value: code };
137
+ })
138
+ )(all_locales);
139
+
140
+ const handleOnChange = ({ value }) => {
141
+ setNewLocales(value);
142
+ };
143
+
144
+ const handleSubmit = () => {
145
+ setNewLocales([]);
146
+ trigger({ locales: newLocales }).then(() => {
147
+ mutate();
148
+ });
149
+ };
150
+
151
+ return (
152
+ <>
153
+ <Form
154
+ onSubmit={() => {
155
+ handleSubmit();
156
+ }}
157
+ >
158
+ <Dropdown
159
+ className="lang-manager-dropdown"
160
+ placeholder={formatMessage({
161
+ id: "i18n.messages.locale.lang_select",
162
+ defaultMessage: "Select languaje",
163
+ })}
164
+ name="add-locales"
165
+ multiple={true}
166
+ search={true}
167
+ selection={true}
168
+ options={options}
169
+ clearable={true}
170
+ value={newLocales}
171
+ onChange={(_e, data) => {
172
+ handleOnChange(data);
173
+ }}
174
+ />
175
+ <Button
176
+ type="submit"
177
+ className="lang-manager-button"
178
+ disabled={_.isEmpty(newLocales)}
179
+ >
180
+ {formatMessage({
181
+ id: "i18n.messages.locale.add_lang",
182
+ })}
183
+ </Button>
184
+ </Form>
185
+
186
+ <Dimmer.Dimmable dimmed={isValidating || dimmerState}>
187
+ <Dimmer active={isValidating || dimmerState} inverted>
188
+ <Loader />
189
+ </Dimmer>
190
+ <Table collapsing striped>
191
+ <TableHeader>
192
+ <TableRow>
193
+ <TableCell></TableCell>
194
+ <TableCell textAlign="center">
195
+ {formatMessage({
196
+ id: "i18n.messages.locale.required",
197
+ })}
198
+ </TableCell>
199
+ <TableCell textAlign="center">
200
+ {formatMessage({
201
+ id: "i18n.messages.locale.default",
202
+ })}
203
+ </TableCell>
204
+ <TableCell></TableCell>
205
+ </TableRow>
206
+ </TableHeader>
207
+ <TableBody>
208
+ {_.flow(
209
+ _.filter((locale) => _.includes(locale.code)(langs)),
210
+ _.map(({ code, local, name }) => {
211
+ return (
212
+ <LanguajeRow
213
+ key={code}
214
+ code={code}
215
+ local={local}
216
+ name={name}
217
+ config={langsConfig[code]}
218
+ mutate={mutate}
219
+ handleDimmer={handleDimmer}
220
+ />
221
+ );
222
+ })
223
+ )(all_locales)}
224
+ </TableBody>
225
+ </Table>
226
+ </Dimmer.Dimmable>
227
+ </>
228
+ );
229
+ };
230
+
231
+ export default Languages;
@@ -104,15 +104,17 @@ export const MessageForm = ({ onSubmit, isSubmitting }) => {
104
104
  )}
105
105
  />
106
106
 
107
- {locales.map((lang, i) => (
108
- <LangForm
109
- key={i}
110
- control={control}
111
- lang={lang}
112
- errors={errors}
113
- formatMessage={formatMessage}
114
- />
115
- ))}
107
+ {locales
108
+ .filter(({ lang }) => lang === "en" || lang === "es")
109
+ .map((lang, i) => (
110
+ <LangForm
111
+ key={i}
112
+ control={control}
113
+ lang={lang}
114
+ errors={errors}
115
+ formatMessage={formatMessage}
116
+ />
117
+ ))}
116
118
 
117
119
  <div className="actions">
118
120
  <Button
@@ -1,5 +1,6 @@
1
1
  import _ from "lodash/fp";
2
2
  import React, { useState } from "react";
3
+ import PropTypes from "prop-types";
3
4
  import { useIntl, FormattedMessage } from "react-intl";
4
5
  import {
5
6
  Button,
@@ -18,12 +19,18 @@ import { useLocales } from "@truedat/core/hooks";
18
19
  import { I18N_MESSAGES_NEW } from "@truedat/core/routes";
19
20
  import { Pagination } from "@truedat/core/components";
20
21
  import MessagesTable from "./MessagesTable";
22
+ import Languages from "./Languages";
21
23
 
22
24
  const ITEMS_PER_PAGE = 30;
23
25
 
24
26
  export function MessagesContent({ locales, loading }) {
25
27
  const langs = _.map("lang")(locales);
26
- const [selectedLang, setSelectedLang] = useState(_.head(langs));
28
+
29
+ const [selectedLang, setSelectedLang] = useState(
30
+ _.head(_.filter((lang) => lang === "en" || lang === "es")(langs))
31
+ );
32
+
33
+ const [selectedManageView, setSelectedManageView] = useState(false);
27
34
  const [page, setPage] = useState(1);
28
35
  const [filter, setFilter] = useState("");
29
36
  const { formatMessage } = useIntl();
@@ -56,38 +63,64 @@ export function MessagesContent({ locales, loading }) {
56
63
  return (
57
64
  <>
58
65
  <Menu attached="top" secondary pointing tabular>
59
- {langs.map((lang, i) => (
60
- <Menu.Item
61
- key={i}
62
- active={lang === selectedLang}
63
- onClick={() => setSelectedLang(lang)}
64
- >
65
- <FormattedMessage id={`i18n.messages.locale.${lang}`} />
66
- </Menu.Item>
67
- ))}
66
+ <Menu.Item
67
+ key={0}
68
+ active={selectedManageView}
69
+ onClick={() => setSelectedManageView(true)}
70
+ >
71
+ <FormattedMessage id="i18n.messages.locale.manage" />
72
+ </Menu.Item>
73
+ {langs
74
+ .filter((lang) => lang === "en" || lang === "es")
75
+ .map((lang, i) => (
76
+ <Menu.Item
77
+ key={i}
78
+ active={lang === selectedLang && !selectedManageView}
79
+ onClick={() => {
80
+ setSelectedLang(lang);
81
+ setSelectedManageView(false);
82
+ }}
83
+ >
84
+ <FormattedMessage id={`i18n.messages.locale.${lang}`} />
85
+ </Menu.Item>
86
+ ))}
68
87
  </Menu>
69
88
  <Divider hidden />
70
- <SearchInput
71
- onChange={handleSearch}
72
- placeholder={formatMessage({ id: "i18n.messages.search.placeholder" })}
73
- value={filter}
74
- />
75
- <MessagesTable
76
- messages={paginatedMessages}
77
- locales={locales}
78
- loading={loading}
79
- />
80
- <Pagination
81
- totalPages={totalPages}
82
- activePage={page}
83
- selectPage={({ activePage }) => setPage(activePage)}
84
- />
89
+ {!selectedManageView ? (
90
+ <>
91
+ <SearchInput
92
+ onChange={handleSearch}
93
+ placeholder={formatMessage({
94
+ id: "i18n.messages.search.placeholder",
95
+ })}
96
+ value={filter}
97
+ />
98
+ <MessagesTable
99
+ messages={paginatedMessages}
100
+ locales={locales}
101
+ loading={loading}
102
+ />
103
+ <Pagination
104
+ totalPages={totalPages}
105
+ activePage={page}
106
+ selectPage={({ activePage }) => setPage(activePage)}
107
+ />
108
+ </>
109
+ ) : (
110
+ <Languages />
111
+ )}
85
112
  </>
86
113
  );
87
114
  }
88
115
 
116
+ MessagesContent.propTypes = {
117
+ locales: PropTypes.array,
118
+ loading: PropTypes.bool,
119
+ };
120
+
89
121
  export default function Messages() {
90
122
  const { formatMessage } = useIntl();
123
+
91
124
  const { locales, loading } = useLocales();
92
125
 
93
126
  return (
@@ -1,5 +1,4 @@
1
1
  import React from "react";
2
- import userEvent from "@testing-library/user-event";
3
2
  import { render } from "@truedat/test/render";
4
3
  import messages from "@truedat/core/messages";
5
4
  import MessageForm from "../MessageForm";
@@ -1,9 +1,11 @@
1
1
  import React from "react";
2
2
  import { render } from "@truedat/test/render";
3
- import messages from "@truedat/core/messages";
3
+ import en from "@truedat/core/messages/en";
4
4
  import Messages from "../Messages";
5
5
 
6
- const renderOpts = { messages };
6
+ const renderOpts = {
7
+ messages: { en: { ...en, "i18n.messages.locale.manage": "manage" } },
8
+ };
7
9
 
8
10
  jest.mock("@truedat/core/hooks", () => ({
9
11
  useLocales: jest.fn(() => ({
@@ -55,6 +55,11 @@ exports[`<Messages /> matches the latest snapshot 1`] = `
55
55
  <div
56
56
  class="ui pointing secondary top attached tabular menu"
57
57
  >
58
+ <a
59
+ class="item"
60
+ >
61
+ manage
62
+ </a>
58
63
  <a
59
64
  class="active item"
60
65
  >