invenio-vocabularies 1.2.0__py2.py3-none-any.whl → 6.3.1__py2.py3-none-any.whl

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.

Potentially problematic release.


This version of invenio-vocabularies might be problematic. Click here for more details.

Files changed (239) hide show
  1. invenio_vocabularies/__init__.py +2 -2
  2. invenio_vocabularies/administration/__init__.py +10 -0
  3. invenio_vocabularies/administration/views/__init__.py +10 -0
  4. invenio_vocabularies/administration/views/vocabularies.py +45 -0
  5. invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py +4 -4
  6. invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py +2 -2
  7. invenio_vocabularies/alembic/55a700f897b6_add_names_and_afiliations_pid_column.py +96 -0
  8. invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py +1 -1
  9. invenio_vocabularies/alembic/e1146238edd3_create_awards_table.py +1 -1
  10. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/.eslintrc.yml +11 -0
  11. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/.prettierrc +1 -0
  12. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/index.js +7 -0
  13. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/package.json +25 -0
  14. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/AwardResults.js +95 -0
  15. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/CustomAwardForm.js +139 -0
  16. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FunderDropdown.js +87 -0
  17. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingField.js +223 -0
  18. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingField.test.js +1 -0
  19. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingFieldItem.js +152 -0
  20. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingModal.js +270 -0
  21. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/NoAwardResults.js +37 -0
  22. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/index.js +8 -0
  23. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/index.js +7 -0
  24. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/index.js +7 -0
  25. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/index.js +7 -0
  26. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/i18next-scanner.config.js +63 -0
  27. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/i18next.js +36 -0
  28. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/index.js +1 -0
  29. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/package.json +53 -0
  30. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/scripts/compileCatalog.js +39 -0
  31. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/scripts/initCatalog.js +19 -0
  32. invenio_vocabularies/cli.py +31 -44
  33. invenio_vocabularies/config.py +74 -7
  34. invenio_vocabularies/contrib/affiliations/affiliations.py +22 -6
  35. invenio_vocabularies/contrib/affiliations/api.py +1 -2
  36. invenio_vocabularies/contrib/affiliations/config.py +10 -5
  37. invenio_vocabularies/contrib/affiliations/datastreams.py +186 -0
  38. invenio_vocabularies/contrib/affiliations/facets.py +36 -0
  39. invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json +38 -7
  40. invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v1.0.0.json +22 -1
  41. invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v2.0.0.json +171 -0
  42. invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v1.0.0.json +22 -1
  43. invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v2.0.0.json +171 -0
  44. invenio_vocabularies/contrib/affiliations/mappings/v7/affiliations/affiliation-v1.0.0.json +22 -1
  45. invenio_vocabularies/contrib/affiliations/schema.py +23 -5
  46. invenio_vocabularies/contrib/affiliations/services.py +1 -2
  47. invenio_vocabularies/contrib/awards/awards.py +18 -6
  48. invenio_vocabularies/contrib/awards/config.py +1 -3
  49. invenio_vocabularies/contrib/awards/datastreams.py +246 -3
  50. invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json +41 -0
  51. invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json +53 -1
  52. invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json +53 -1
  53. invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json +53 -1
  54. invenio_vocabularies/contrib/awards/schema.py +27 -35
  55. invenio_vocabularies/contrib/awards/serializer.py +9 -1
  56. invenio_vocabularies/contrib/awards/services.py +1 -2
  57. invenio_vocabularies/contrib/common/__init__.py +9 -0
  58. invenio_vocabularies/contrib/common/openaire/__init__.py +9 -0
  59. invenio_vocabularies/contrib/common/openaire/datastreams.py +84 -0
  60. invenio_vocabularies/contrib/common/ror/__init__.py +9 -0
  61. invenio_vocabularies/contrib/common/ror/datastreams.py +220 -0
  62. invenio_vocabularies/contrib/funders/config.py +12 -5
  63. invenio_vocabularies/contrib/funders/datastreams.py +40 -62
  64. invenio_vocabularies/contrib/funders/facets.py +13 -5
  65. invenio_vocabularies/contrib/funders/funders.py +4 -2
  66. invenio_vocabularies/contrib/funders/jsonschemas/funders/funder-v1.0.0.json +36 -1
  67. invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v1.0.0.json +22 -1
  68. invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v2.0.0.json +156 -0
  69. invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v1.0.0.json +22 -1
  70. invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v2.0.0.json +156 -0
  71. invenio_vocabularies/contrib/funders/mappings/v7/funders/funder-v1.0.0.json +22 -1
  72. invenio_vocabularies/contrib/funders/schema.py +8 -0
  73. invenio_vocabularies/contrib/funders/serializer.py +2 -1
  74. invenio_vocabularies/contrib/names/config.py +5 -3
  75. invenio_vocabularies/contrib/names/datastreams.py +177 -38
  76. invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json +2 -6
  77. invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v1.0.0.json +3 -0
  78. invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v2.0.0.json +150 -0
  79. invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v1.0.0.json +3 -0
  80. invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v2.0.0.json +150 -0
  81. invenio_vocabularies/contrib/names/mappings/v7/names/name-v1.0.0.json +3 -0
  82. invenio_vocabularies/contrib/names/names.py +29 -13
  83. invenio_vocabularies/contrib/names/permissions.py +20 -0
  84. invenio_vocabularies/contrib/names/s3client.py +44 -0
  85. invenio_vocabularies/contrib/names/schema.py +31 -4
  86. invenio_vocabularies/contrib/subjects/config.py +9 -3
  87. invenio_vocabularies/contrib/subjects/datastreams.py +61 -0
  88. invenio_vocabularies/contrib/subjects/euroscivoc/__init__.py +9 -0
  89. invenio_vocabularies/contrib/subjects/euroscivoc/datastreams.py +171 -0
  90. invenio_vocabularies/contrib/subjects/jsonschemas/subjects/subject-v1.0.0.json +31 -0
  91. invenio_vocabularies/contrib/subjects/mappings/os-v1/subjects/subject-v1.0.0.json +35 -0
  92. invenio_vocabularies/contrib/subjects/mappings/os-v2/subjects/subject-v1.0.0.json +35 -0
  93. invenio_vocabularies/contrib/subjects/mappings/v7/subjects/subject-v1.0.0.json +35 -0
  94. invenio_vocabularies/contrib/subjects/mesh/__init__.py +9 -0
  95. invenio_vocabularies/contrib/subjects/mesh/datastreams.py +43 -0
  96. invenio_vocabularies/contrib/subjects/schema.py +47 -5
  97. invenio_vocabularies/contrib/subjects/subjects.py +10 -0
  98. invenio_vocabularies/datastreams/datastreams.py +61 -13
  99. invenio_vocabularies/datastreams/factories.py +1 -2
  100. invenio_vocabularies/datastreams/readers.py +138 -29
  101. invenio_vocabularies/datastreams/tasks.py +37 -0
  102. invenio_vocabularies/datastreams/transformers.py +17 -27
  103. invenio_vocabularies/datastreams/writers.py +116 -14
  104. invenio_vocabularies/datastreams/xml.py +34 -0
  105. invenio_vocabularies/ext.py +59 -5
  106. invenio_vocabularies/factories.py +137 -0
  107. invenio_vocabularies/jobs.py +133 -0
  108. invenio_vocabularies/proxies.py +2 -2
  109. invenio_vocabularies/records/jsonschemas/vocabularies/definitions-v1.0.0.json +7 -0
  110. invenio_vocabularies/records/jsonschemas/vocabularies/vocabulary-v1.0.0.json +1 -4
  111. invenio_vocabularies/records/mappings/os-v1/vocabularies/vocabulary-v1.0.0.json +3 -3
  112. invenio_vocabularies/records/mappings/os-v2/vocabularies/vocabulary-v1.0.0.json +3 -3
  113. invenio_vocabularies/records/mappings/v7/vocabularies/vocabulary-v1.0.0.json +3 -3
  114. invenio_vocabularies/records/models.py +8 -10
  115. invenio_vocabularies/records/pidprovider.py +1 -2
  116. invenio_vocabularies/records/systemfields/relations.py +2 -2
  117. invenio_vocabularies/resources/__init__.py +9 -1
  118. invenio_vocabularies/resources/config.py +105 -0
  119. invenio_vocabularies/resources/resource.py +31 -41
  120. invenio_vocabularies/resources/schema.py +2 -1
  121. invenio_vocabularies/services/__init__.py +5 -2
  122. invenio_vocabularies/services/config.py +179 -0
  123. invenio_vocabularies/services/custom_fields/__init__.py +6 -2
  124. invenio_vocabularies/services/custom_fields/subject.py +82 -0
  125. invenio_vocabularies/services/custom_fields/vocabulary.py +19 -9
  126. invenio_vocabularies/services/facets.py +67 -37
  127. invenio_vocabularies/services/permissions.py +3 -1
  128. invenio_vocabularies/services/results.py +110 -0
  129. invenio_vocabularies/services/schema.py +39 -2
  130. invenio_vocabularies/services/service.py +46 -94
  131. invenio_vocabularies/services/tasks.py +1 -1
  132. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/subjects.html +23 -0
  133. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabularies-list.html +12 -0
  134. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabulary-details.html +71 -0
  135. invenio_vocabularies/translations/af/LC_MESSAGES/messages.mo +0 -0
  136. invenio_vocabularies/translations/af/LC_MESSAGES/messages.po +1 -1
  137. invenio_vocabularies/translations/ar/LC_MESSAGES/messages.mo +0 -0
  138. invenio_vocabularies/translations/ar/LC_MESSAGES/messages.po +9 -8
  139. invenio_vocabularies/translations/bg/LC_MESSAGES/messages.mo +0 -0
  140. invenio_vocabularies/translations/bg/LC_MESSAGES/messages.po +1 -1
  141. invenio_vocabularies/translations/ca/LC_MESSAGES/messages.mo +0 -0
  142. invenio_vocabularies/translations/ca/LC_MESSAGES/messages.po +1 -1
  143. invenio_vocabularies/translations/cs/LC_MESSAGES/messages.mo +0 -0
  144. invenio_vocabularies/translations/cs/LC_MESSAGES/messages.po +1 -1
  145. invenio_vocabularies/translations/da/LC_MESSAGES/messages.mo +0 -0
  146. invenio_vocabularies/translations/da/LC_MESSAGES/messages.po +1 -1
  147. invenio_vocabularies/translations/de/LC_MESSAGES/messages.mo +0 -0
  148. invenio_vocabularies/translations/de/LC_MESSAGES/messages.po +1 -1
  149. invenio_vocabularies/translations/de_AT/LC_MESSAGES/messages.mo +0 -0
  150. invenio_vocabularies/translations/de_AT/LC_MESSAGES/messages.po +139 -0
  151. invenio_vocabularies/translations/de_DE/LC_MESSAGES/messages.mo +0 -0
  152. invenio_vocabularies/translations/de_DE/LC_MESSAGES/messages.po +139 -0
  153. invenio_vocabularies/translations/el/LC_MESSAGES/messages.mo +0 -0
  154. invenio_vocabularies/translations/el/LC_MESSAGES/messages.po +1 -1
  155. invenio_vocabularies/translations/en/LC_MESSAGES/messages.mo +0 -0
  156. invenio_vocabularies/translations/en_AT/LC_MESSAGES/messages.mo +0 -0
  157. invenio_vocabularies/translations/en_AT/LC_MESSAGES/messages.po +139 -0
  158. invenio_vocabularies/translations/en_HU/LC_MESSAGES/messages.mo +0 -0
  159. invenio_vocabularies/translations/en_HU/LC_MESSAGES/messages.po +139 -0
  160. invenio_vocabularies/translations/es/LC_MESSAGES/messages.mo +0 -0
  161. invenio_vocabularies/translations/es/LC_MESSAGES/messages.po +1 -1
  162. invenio_vocabularies/translations/es_CU/LC_MESSAGES/messages.mo +0 -0
  163. invenio_vocabularies/translations/es_CU/LC_MESSAGES/messages.po +139 -0
  164. invenio_vocabularies/translations/es_MX/LC_MESSAGES/messages.mo +0 -0
  165. invenio_vocabularies/translations/es_MX/LC_MESSAGES/messages.po +139 -0
  166. invenio_vocabularies/translations/et/LC_MESSAGES/messages.mo +0 -0
  167. invenio_vocabularies/translations/et/LC_MESSAGES/messages.po +1 -1
  168. invenio_vocabularies/translations/et_EE/LC_MESSAGES/messages.mo +0 -0
  169. invenio_vocabularies/translations/et_EE/LC_MESSAGES/messages.po +1 -1
  170. invenio_vocabularies/translations/fa/LC_MESSAGES/messages.mo +0 -0
  171. invenio_vocabularies/translations/fa/LC_MESSAGES/messages.po +1 -1
  172. invenio_vocabularies/translations/fa_IR/LC_MESSAGES/messages.mo +0 -0
  173. invenio_vocabularies/translations/fa_IR/LC_MESSAGES/messages.po +139 -0
  174. invenio_vocabularies/translations/fr/LC_MESSAGES/messages.mo +0 -0
  175. invenio_vocabularies/translations/fr/LC_MESSAGES/messages.po +1 -1
  176. invenio_vocabularies/translations/fr_CI/LC_MESSAGES/messages.mo +0 -0
  177. invenio_vocabularies/translations/fr_CI/LC_MESSAGES/messages.po +139 -0
  178. invenio_vocabularies/translations/fr_FR/LC_MESSAGES/messages.mo +0 -0
  179. invenio_vocabularies/translations/fr_FR/LC_MESSAGES/messages.po +139 -0
  180. invenio_vocabularies/translations/gl/LC_MESSAGES/messages.mo +0 -0
  181. invenio_vocabularies/translations/gl/LC_MESSAGES/messages.po +1 -1
  182. invenio_vocabularies/translations/hi_IN/LC_MESSAGES/messages.mo +0 -0
  183. invenio_vocabularies/translations/hi_IN/LC_MESSAGES/messages.po +139 -0
  184. invenio_vocabularies/translations/hr/LC_MESSAGES/messages.mo +0 -0
  185. invenio_vocabularies/translations/hr/LC_MESSAGES/messages.po +1 -1
  186. invenio_vocabularies/translations/hu/LC_MESSAGES/messages.mo +0 -0
  187. invenio_vocabularies/translations/hu/LC_MESSAGES/messages.po +4 -4
  188. invenio_vocabularies/translations/hu_HU/LC_MESSAGES/messages.mo +0 -0
  189. invenio_vocabularies/translations/hu_HU/LC_MESSAGES/messages.po +139 -0
  190. invenio_vocabularies/translations/it/LC_MESSAGES/messages.mo +0 -0
  191. invenio_vocabularies/translations/it/LC_MESSAGES/messages.po +4 -3
  192. invenio_vocabularies/translations/ja/LC_MESSAGES/messages.mo +0 -0
  193. invenio_vocabularies/translations/ja/LC_MESSAGES/messages.po +1 -1
  194. invenio_vocabularies/translations/ka/LC_MESSAGES/messages.mo +0 -0
  195. invenio_vocabularies/translations/ka/LC_MESSAGES/messages.po +1 -1
  196. invenio_vocabularies/translations/lt/LC_MESSAGES/messages.mo +0 -0
  197. invenio_vocabularies/translations/lt/LC_MESSAGES/messages.po +1 -1
  198. invenio_vocabularies/translations/messages.pot +95 -48
  199. invenio_vocabularies/translations/ne/LC_MESSAGES/messages.mo +0 -0
  200. invenio_vocabularies/translations/ne/LC_MESSAGES/messages.po +139 -0
  201. invenio_vocabularies/translations/no/LC_MESSAGES/messages.mo +0 -0
  202. invenio_vocabularies/translations/no/LC_MESSAGES/messages.po +1 -1
  203. invenio_vocabularies/translations/pl/LC_MESSAGES/messages.mo +0 -0
  204. invenio_vocabularies/translations/pl/LC_MESSAGES/messages.po +1 -1
  205. invenio_vocabularies/translations/pt/LC_MESSAGES/messages.mo +0 -0
  206. invenio_vocabularies/translations/pt/LC_MESSAGES/messages.po +1 -1
  207. invenio_vocabularies/translations/ro/LC_MESSAGES/messages.mo +0 -0
  208. invenio_vocabularies/translations/ro/LC_MESSAGES/messages.po +1 -1
  209. invenio_vocabularies/translations/ru/LC_MESSAGES/messages.mo +0 -0
  210. invenio_vocabularies/translations/ru/LC_MESSAGES/messages.po +1 -1
  211. invenio_vocabularies/translations/rw/LC_MESSAGES/messages.mo +0 -0
  212. invenio_vocabularies/translations/rw/LC_MESSAGES/messages.po +1 -1
  213. invenio_vocabularies/translations/sk/LC_MESSAGES/messages.mo +0 -0
  214. invenio_vocabularies/translations/sk/LC_MESSAGES/messages.po +1 -1
  215. invenio_vocabularies/translations/sv/LC_MESSAGES/messages.mo +0 -0
  216. invenio_vocabularies/translations/sv/LC_MESSAGES/messages.po +4 -3
  217. invenio_vocabularies/translations/sv_SE/LC_MESSAGES/messages.mo +0 -0
  218. invenio_vocabularies/translations/sv_SE/LC_MESSAGES/messages.po +139 -0
  219. invenio_vocabularies/translations/tr/LC_MESSAGES/messages.mo +0 -0
  220. invenio_vocabularies/translations/tr/LC_MESSAGES/messages.po +1 -1
  221. invenio_vocabularies/translations/uk/LC_MESSAGES/messages.mo +0 -0
  222. invenio_vocabularies/translations/uk/LC_MESSAGES/messages.po +17 -13
  223. invenio_vocabularies/translations/uk_UA/LC_MESSAGES/messages.mo +0 -0
  224. invenio_vocabularies/translations/uk_UA/LC_MESSAGES/messages.po +139 -0
  225. invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
  226. invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.po +1 -1
  227. invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.mo +0 -0
  228. invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.po +1 -1
  229. invenio_vocabularies/views.py +12 -26
  230. invenio_vocabularies/webpack.py +51 -0
  231. invenio_vocabularies-6.3.1.dist-info/METADATA +346 -0
  232. invenio_vocabularies-6.3.1.dist-info/RECORD +306 -0
  233. {invenio_vocabularies-1.2.0.dist-info → invenio_vocabularies-6.3.1.dist-info}/WHEEL +1 -1
  234. {invenio_vocabularies-1.2.0.dist-info → invenio_vocabularies-6.3.1.dist-info}/entry_points.txt +20 -0
  235. invenio_vocabularies-1.2.0.dist-info/METADATA +0 -133
  236. invenio_vocabularies-1.2.0.dist-info/RECORD +0 -220
  237. {invenio_vocabularies-1.2.0.dist-info → invenio_vocabularies-6.3.1.dist-info}/AUTHORS.rst +0 -0
  238. {invenio_vocabularies-1.2.0.dist-info → invenio_vocabularies-6.3.1.dist-info}/LICENSE +0 -0
  239. {invenio_vocabularies-1.2.0.dist-info → invenio_vocabularies-6.3.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,223 @@
1
+ // This file is part of InvenioVocabularies
2
+ // Copyright (C) 2021-2024 CERN.
3
+ // Copyright (C) 2021 Northwestern University.
4
+ //
5
+ // Invenio is free software; you can redistribute it and/or modify it
6
+ // under the terms of the MIT License; see LICENSE file for more details.
7
+
8
+ import React from "react";
9
+ import PropTypes from "prop-types";
10
+ import { FieldArray, getIn } from "formik";
11
+ import { HTML5Backend } from "react-dnd-html5-backend";
12
+ import { DndProvider } from "react-dnd";
13
+ import { Button, Form, Icon, List } from "semantic-ui-react";
14
+ import { FieldLabel } from "react-invenio-forms";
15
+
16
+ import { FundingFieldItem } from "./FundingFieldItem";
17
+ import FundingModal from "./FundingModal";
18
+
19
+ import { i18next } from "@translations/invenio_rdm_records/i18next";
20
+
21
+ import Overridable from "react-overridable";
22
+
23
+ function FundingFieldForm(props) {
24
+ const {
25
+ label,
26
+ labelIcon,
27
+ fieldPath,
28
+ form: { values },
29
+ move: formikArrayMove,
30
+ push: formikArrayPush,
31
+ remove: formikArrayRemove,
32
+ replace: formikArrayReplace,
33
+ required,
34
+ deserializeAward: deserializeAwardFunc,
35
+ deserializeFunder: deserializeFunderFunc,
36
+ computeFundingContents: computeFundingContentsFunc,
37
+ searchConfig,
38
+ } = props;
39
+
40
+ const deserializeAward = deserializeAwardFunc
41
+ ? deserializeAwardFunc
42
+ : (award) => ({
43
+ title: award?.title_l10n,
44
+ number: award.number,
45
+ funder: award.funder ?? "",
46
+ id: award.id,
47
+ ...(award.identifiers && { identifiers: award.identifiers }),
48
+ ...(award.acronym && { acronym: award.acronym }),
49
+ });
50
+
51
+ const deserializeFunder = deserializeFunderFunc
52
+ ? deserializeFunderFunc
53
+ : (funder) => ({
54
+ id: funder.id,
55
+ name: funder.name,
56
+ ...(funder.pid && { pid: funder.pid }),
57
+ ...(funder.country && { country: funder.country }),
58
+ ...(funder.identifiers && { identifiers: funder.identifiers }),
59
+ });
60
+
61
+ const computeFundingContents = computeFundingContentsFunc
62
+ ? computeFundingContentsFunc
63
+ : (funding) => {
64
+ let headerContent,
65
+ descriptionContent = "";
66
+ let awardOrFunder = "award";
67
+ if (funding.award) {
68
+ headerContent = funding.award.title;
69
+ }
70
+
71
+ if (funding.funder) {
72
+ const funderName =
73
+ funding?.funder?.name ?? funding.funder?.title ?? funding?.funder?.id ?? "";
74
+ descriptionContent = funderName;
75
+ if (!headerContent) {
76
+ awardOrFunder = "funder";
77
+ headerContent = funderName;
78
+ descriptionContent = "";
79
+ }
80
+ }
81
+
82
+ return { headerContent, descriptionContent, awardOrFunder };
83
+ };
84
+ return (
85
+ <DndProvider backend={HTML5Backend}>
86
+ <Form.Field required={required}>
87
+ <FieldLabel htmlFor={fieldPath} icon={labelIcon} label={label} />
88
+ <List>
89
+ {getIn(values, fieldPath, []).map((value, index) => {
90
+ const key = `${fieldPath}.${index}`;
91
+ // if award does not exist or has no id, it's a custom one
92
+ const awardType = value?.award?.id ? "standard" : "custom";
93
+ return (
94
+ <FundingFieldItem
95
+ key={key}
96
+ {...{
97
+ index,
98
+ compKey: key,
99
+ fundingItem: value,
100
+ awardType,
101
+ moveFunding: formikArrayMove,
102
+ replaceFunding: formikArrayReplace,
103
+ removeFunding: formikArrayRemove,
104
+ searchConfig: searchConfig,
105
+ computeFundingContents: computeFundingContents,
106
+ deserializeAward: deserializeAward,
107
+ deserializeFunder: deserializeFunder,
108
+ }}
109
+ />
110
+ );
111
+ })}
112
+ </List>
113
+
114
+ <Overridable id="InvenioVocabularies.FundingField.AddAwardFundingModal.Container">
115
+ <FundingModal
116
+ searchConfig={searchConfig}
117
+ trigger={
118
+ <Button
119
+ type="button"
120
+ key="custom"
121
+ icon
122
+ labelPosition="left"
123
+ className="mb-5"
124
+ >
125
+ <Icon name="add" />
126
+ {i18next.t("Add")}
127
+ </Button>
128
+ }
129
+ onAwardChange={(selectedFunding) => {
130
+ formikArrayPush(selectedFunding);
131
+ }}
132
+ mode="standard"
133
+ action="add"
134
+ deserializeAward={deserializeAward}
135
+ deserializeFunder={deserializeFunder}
136
+ computeFundingContents={computeFundingContents}
137
+ />
138
+ </Overridable>
139
+
140
+ <Overridable id="InvenioVocabularies.FundingField.AddCustomFundingModal.Container">
141
+ <FundingModal
142
+ searchConfig={searchConfig}
143
+ trigger={
144
+ <Button type="button" key="custom" icon labelPosition="left">
145
+ <Icon name="add" />
146
+ {i18next.t("Add custom")}
147
+ </Button>
148
+ }
149
+ onAwardChange={(selectedFunding) => {
150
+ formikArrayPush(selectedFunding);
151
+ }}
152
+ mode="custom"
153
+ action="add"
154
+ deserializeAward={deserializeAward}
155
+ deserializeFunder={deserializeFunder}
156
+ computeFundingContents={computeFundingContents}
157
+ />
158
+ </Overridable>
159
+ </Form.Field>
160
+ </DndProvider>
161
+ );
162
+ }
163
+
164
+ FundingFieldForm.propTypes = {
165
+ label: PropTypes.node,
166
+ labelIcon: PropTypes.node,
167
+ fieldPath: PropTypes.string.isRequired,
168
+ form: PropTypes.object,
169
+ move: PropTypes.func,
170
+ push: PropTypes.func,
171
+ remove: PropTypes.func,
172
+ replace: PropTypes.func,
173
+ required: PropTypes.bool,
174
+ deserializeAward: PropTypes.func,
175
+ deserializeFunder: PropTypes.func,
176
+ computeFundingContents: PropTypes.func,
177
+ searchConfig: PropTypes.object,
178
+ };
179
+
180
+ FundingFieldForm.defaultProps = {
181
+ label: undefined,
182
+ labelIcon: undefined,
183
+ form: undefined,
184
+ move: undefined,
185
+ push: undefined,
186
+ remove: undefined,
187
+ replace: undefined,
188
+ required: undefined,
189
+ deserializeAward: undefined,
190
+ deserializeFunder: undefined,
191
+ computeFundingContents: undefined,
192
+ searchConfig: undefined,
193
+ };
194
+
195
+ export function FundingField(props) {
196
+ const { fieldPath } = props;
197
+ return (
198
+ <FieldArray
199
+ name={fieldPath}
200
+ component={(formikProps) => <FundingFieldForm {...formikProps} {...props} />}
201
+ />
202
+ );
203
+ }
204
+
205
+ FundingField.propTypes = {
206
+ fieldPath: PropTypes.string.isRequired,
207
+ label: PropTypes.string,
208
+ labelIcon: PropTypes.string,
209
+ searchConfig: PropTypes.object.isRequired,
210
+ required: PropTypes.bool,
211
+ deserializeAward: PropTypes.func,
212
+ deserializeFunder: PropTypes.func,
213
+ computeFundingContents: PropTypes.func,
214
+ };
215
+
216
+ FundingField.defaultProps = {
217
+ label: "Awards",
218
+ labelIcon: "money bill alternate outline",
219
+ required: false,
220
+ deserializeAward: undefined,
221
+ deserializeFunder: undefined,
222
+ computeFundingContents: undefined,
223
+ };
@@ -0,0 +1,152 @@
1
+ // This file is part of InvenioVocabularies
2
+ // Copyright (C) 2021-2023 CERN.
3
+ // Copyright (C) 2021 Northwestern University.
4
+ // Copyright (C) 2021 Graz University of Technology.
5
+ //
6
+ // Invenio is free software; you can redistribute it and/or modify it
7
+ // under the terms of the MIT License; see LICENSE file for more details.
8
+
9
+ import { i18next } from "@translations/invenio_rdm_records/i18next";
10
+ import React from "react";
11
+ import { useDrag, useDrop } from "react-dnd";
12
+ import { Button, Icon, Label, List, Ref } from "semantic-ui-react";
13
+
14
+ import FundingModal from "./FundingModal";
15
+ import PropTypes from "prop-types";
16
+
17
+ export const FundingFieldItem = ({
18
+ compKey,
19
+ index,
20
+ fundingItem,
21
+ awardType,
22
+ moveFunding,
23
+ replaceFunding,
24
+ removeFunding,
25
+ searchConfig,
26
+ deserializeAward,
27
+ deserializeFunder,
28
+ computeFundingContents,
29
+ }) => {
30
+ const dropRef = React.useRef(null);
31
+ // eslint-disable-next-line no-unused-vars
32
+ const [_, drag, preview] = useDrag({
33
+ item: { index, type: "award" },
34
+ });
35
+ const [{ hidden }, drop] = useDrop({
36
+ accept: "award",
37
+ hover(item, monitor) {
38
+ if (!dropRef.current) {
39
+ return;
40
+ }
41
+ const dragIndex = item.index;
42
+ const hoverIndex = index;
43
+
44
+ // Don't replace items with themselves
45
+ if (dragIndex === hoverIndex) {
46
+ return;
47
+ }
48
+
49
+ if (monitor.isOver({ shallow: true })) {
50
+ moveFunding(dragIndex, hoverIndex);
51
+ item.index = hoverIndex;
52
+ }
53
+ },
54
+ collect: (monitor) => ({
55
+ hidden: monitor.isOver({ shallow: true }),
56
+ }),
57
+ });
58
+
59
+ let { headerContent, descriptionContent, awardOrFunder } =
60
+ computeFundingContents(fundingItem);
61
+
62
+ // Initialize the ref explicitely
63
+ drop(dropRef);
64
+ return (
65
+ <Ref innerRef={dropRef} key={compKey}>
66
+ <List.Item
67
+ key={compKey}
68
+ className={hidden ? "deposit-drag-listitem hidden" : "deposit-drag-listitem"}
69
+ >
70
+ <List.Content floated="right">
71
+ <FundingModal
72
+ searchConfig={searchConfig}
73
+ onAwardChange={(selectedFunding) => {
74
+ replaceFunding(index, selectedFunding);
75
+ }}
76
+ mode={awardType}
77
+ action="edit"
78
+ trigger={
79
+ <Button size="mini" primary type="button">
80
+ {i18next.t("Edit")}
81
+ </Button>
82
+ }
83
+ deserializeAward={deserializeAward}
84
+ deserializeFunder={deserializeFunder}
85
+ computeFundingContents={computeFundingContents}
86
+ initialFunding={fundingItem}
87
+ />
88
+ <Button size="mini" type="button" onClick={() => removeFunding(index)}>
89
+ {i18next.t("Remove")}
90
+ </Button>
91
+ </List.Content>
92
+
93
+ <Ref innerRef={drag}>
94
+ <List.Icon name="bars" className="drag-anchor" />
95
+ </Ref>
96
+ <Ref innerRef={preview}>
97
+ <List.Content>
98
+ <List.Header>
99
+ <>
100
+ <span className="mr-5">{headerContent}</span>
101
+
102
+ {awardOrFunder === "award"
103
+ ? fundingItem?.award?.number && (
104
+ <Label basic size="mini" className="mr-5">
105
+ {fundingItem.award.number}
106
+ </Label>
107
+ )
108
+ : ""}
109
+ {awardOrFunder === "award"
110
+ ? fundingItem?.award?.url && (
111
+ <a
112
+ href={`${fundingItem.award.url}`}
113
+ target="_blank"
114
+ rel="noopener noreferrer"
115
+ aria-label={i18next.t("Open external link")}
116
+ >
117
+ <Icon link name="external alternate" />
118
+ </a>
119
+ )
120
+ : ""}
121
+ </>
122
+ </List.Header>
123
+ <List.Description>
124
+ {descriptionContent ? descriptionContent : <br />}
125
+ </List.Description>
126
+ </List.Content>
127
+ </Ref>
128
+ </List.Item>
129
+ </Ref>
130
+ );
131
+ };
132
+
133
+ FundingFieldItem.propTypes = {
134
+ compKey: PropTypes.any,
135
+ index: PropTypes.number,
136
+ fundingItem: PropTypes.object,
137
+ awardType: PropTypes.string,
138
+ moveFunding: PropTypes.func.isRequired,
139
+ replaceFunding: PropTypes.func.isRequired,
140
+ removeFunding: PropTypes.func.isRequired,
141
+ searchConfig: PropTypes.object.isRequired,
142
+ deserializeAward: PropTypes.func.isRequired,
143
+ deserializeFunder: PropTypes.func.isRequired,
144
+ computeFundingContents: PropTypes.func.isRequired,
145
+ };
146
+
147
+ FundingFieldItem.defaultProps = {
148
+ compKey: undefined,
149
+ index: undefined,
150
+ fundingItem: undefined,
151
+ awardType: undefined,
152
+ };
@@ -0,0 +1,270 @@
1
+ // This file is part of InvenioVocabularies
2
+ // Copyright (C) 2021-2024 CERN.
3
+ // Copyright (C) 2021 Northwestern University.
4
+ //
5
+ // Invenio is free software; you can redistribute it and/or modify it
6
+ // under the terms of the MIT License; see LICENSE file for more details.
7
+
8
+ import { i18next } from "@translations/invenio_rdm_records/i18next";
9
+ import { Formik } from "formik";
10
+ import PropTypes from "prop-types";
11
+ import React, { useState } from "react";
12
+ import {
13
+ EmptyResults,
14
+ Error,
15
+ InvenioSearchApi,
16
+ Pagination,
17
+ ReactSearchKit,
18
+ ResultsLoader,
19
+ SearchBar,
20
+ } from "react-searchkit";
21
+ import { Grid, Modal, Container, Button } from "semantic-ui-react";
22
+ import * as Yup from "yup";
23
+ import { AwardResults } from "./AwardResults";
24
+ import CustomAwardForm from "./CustomAwardForm";
25
+ import { FunderDropdown } from "./FunderDropdown";
26
+ import { NoAwardResults } from "./NoAwardResults";
27
+
28
+ const ModalTypes = {
29
+ STANDARD: "standard",
30
+ CUSTOM: "custom",
31
+ };
32
+
33
+ const ModalActions = {
34
+ ADD: "add",
35
+ EDIT: "edit",
36
+ };
37
+
38
+ const StandardSchema = Yup.object().shape({
39
+ selectedFunding: Yup.object().shape({
40
+ funder: Yup.object().shape({
41
+ id: Yup.string().required(),
42
+ }),
43
+ award: Yup.object().shape({
44
+ id: Yup.string().required(),
45
+ }),
46
+ }),
47
+ });
48
+
49
+ const CustomFundingSchema = Yup.object().shape({
50
+ selectedFunding: Yup.object().shape({
51
+ funder: Yup.object().shape({
52
+ id: Yup.string().required(i18next.t("Funder is required.")),
53
+ }),
54
+ award: Yup.object().shape({
55
+ title: Yup.string().test({
56
+ name: "testTitle",
57
+ message: i18next.t("Title must be set alongside number."),
58
+ test: function testTitle(value) {
59
+ const { number } = this.parent;
60
+
61
+ if (number && !value) {
62
+ return false;
63
+ }
64
+
65
+ return true;
66
+ },
67
+ }),
68
+ number: Yup.string().test({
69
+ name: "testNumber",
70
+ message: i18next.t("Number must be set alongside title."),
71
+ test: function testNumber(value) {
72
+ const { title } = this.parent;
73
+
74
+ if (title && !value) {
75
+ return false;
76
+ }
77
+
78
+ return true;
79
+ },
80
+ }),
81
+ url: Yup.string()
82
+ .url(i18next.t("URL must be valid."))
83
+ .test({
84
+ name: "validateUrlDependencies",
85
+ message: i18next.t("URL must be set alongside title and number."),
86
+ test: function testUrl(value) {
87
+ const { title, number } = this.parent;
88
+
89
+ if (value && value !== "" && !title && !number) {
90
+ return false;
91
+ }
92
+
93
+ return true;
94
+ },
95
+ }),
96
+ }),
97
+ }),
98
+ });
99
+
100
+ function FundingModal({
101
+ action,
102
+ mode: initialMode,
103
+ trigger,
104
+ onAwardChange,
105
+ searchConfig,
106
+ deserializeAward,
107
+ deserializeFunder,
108
+ computeFundingContents,
109
+ ...props
110
+ }) {
111
+ const [open, setOpen] = useState(false);
112
+ const [mode, setMode] = useState(initialMode);
113
+ const openModal = () => setOpen(true);
114
+ const closeModal = () => {
115
+ setMode(initialMode);
116
+ setOpen(false);
117
+ };
118
+ const onSubmit = (values, formikBag) => {
119
+ formikBag.setSubmitting(false);
120
+ formikBag.resetForm();
121
+ setMode(initialMode);
122
+ closeModal();
123
+ onAwardChange(values.selectedFunding);
124
+ };
125
+
126
+ const searchApi = new InvenioSearchApi(searchConfig.searchApi);
127
+ const customObject = mode === ModalTypes.CUSTOM ? props.initialFunding : {};
128
+ const initialFunding = {
129
+ selectedFunding: action === ModalActions.EDIT ? customObject : {},
130
+ };
131
+
132
+ const FundingSchema =
133
+ mode === ModalTypes.CUSTOM ? CustomFundingSchema : StandardSchema;
134
+
135
+ return (
136
+ <Formik
137
+ initialValues={initialFunding}
138
+ onSubmit={onSubmit}
139
+ validationSchema={FundingSchema}
140
+ validateOnChange={false}
141
+ validateOnBlur={false}
142
+ enableReinitialize
143
+ >
144
+ {({ values, resetForm, handleSubmit }) => (
145
+ <Modal
146
+ role="dialog"
147
+ centered={false}
148
+ onOpen={openModal}
149
+ open={open}
150
+ trigger={React.cloneElement(trigger, {
151
+ "aria-expanded": open,
152
+ "aria-haspopup": "dialog",
153
+ })}
154
+ onClose={closeModal}
155
+ closeIcon
156
+ closeOnDimmerClick={false}
157
+ >
158
+ <Modal.Header as="h2" className="pt-10 pb-10">
159
+ {mode === "standard"
160
+ ? i18next.t("Add standard award/grant")
161
+ : i18next.t("Add custom funding")}
162
+ </Modal.Header>
163
+ <Modal.Content>
164
+ {mode === ModalTypes.STANDARD && (
165
+ <ReactSearchKit
166
+ searchApi={searchApi}
167
+ appName="awards"
168
+ urlHandlerApi={{ enabled: false }}
169
+ initialQueryState={searchConfig.initialQueryState}
170
+ >
171
+ <Grid className="m-0">
172
+ <Grid.Row>
173
+ <Grid.Column width={11} floated="left" verticalAlign="middle">
174
+ <SearchBar
175
+ placeholder={i18next.t("Search for awards/grants")}
176
+ autofocus
177
+ actionProps={{
178
+ icon: "search",
179
+ content: null,
180
+ className: "search",
181
+ }}
182
+ />
183
+ </Grid.Column>
184
+ <Grid.Column width={5} floated="right" textAlign="right">
185
+ <FunderDropdown />
186
+ </Grid.Column>
187
+ </Grid.Row>
188
+
189
+ <Grid.Column width={16} className="pb-0">
190
+ <ResultsLoader>
191
+ <EmptyResults />
192
+ <Error />
193
+ <AwardResults
194
+ deserializeAward={deserializeAward}
195
+ deserializeFunder={deserializeFunder}
196
+ computeFundingContents={computeFundingContents}
197
+ />
198
+ </ResultsLoader>
199
+ <Container textAlign="center" className="rel-mb-1">
200
+ <Pagination />
201
+ </Container>
202
+ </Grid.Column>
203
+
204
+ <Grid.Column width={16} textAlign="center" className="pt-0 pb-0">
205
+ <NoAwardResults
206
+ switchToCustom={() => {
207
+ resetForm();
208
+ setMode(ModalTypes.CUSTOM);
209
+ }}
210
+ />
211
+ </Grid.Column>
212
+ </Grid>
213
+ </ReactSearchKit>
214
+ )}
215
+ {mode === ModalTypes.CUSTOM && (
216
+ <CustomAwardForm
217
+ deserializeFunder={deserializeFunder}
218
+ selectedFunding={values.selectedFunding}
219
+ />
220
+ )}
221
+ </Modal.Content>
222
+ <Modal.Actions>
223
+ <Button
224
+ onClick={() => {
225
+ resetForm();
226
+ closeModal();
227
+ }}
228
+ icon="remove"
229
+ content={i18next.t("Cancel")}
230
+ floated="left"
231
+ />
232
+ <Button
233
+ onClick={(event) => handleSubmit(event)}
234
+ primary
235
+ icon="checkmark"
236
+ content={
237
+ action === ModalActions.ADD ? i18next.t("Add") : i18next.t("Change")
238
+ }
239
+ />
240
+ </Modal.Actions>
241
+ </Modal>
242
+ )}
243
+ </Formik>
244
+ );
245
+ }
246
+
247
+ FundingModal.propTypes = {
248
+ mode: PropTypes.oneOf(["standard", "custom"]).isRequired,
249
+ action: PropTypes.oneOf(["add", "edit"]).isRequired,
250
+ trigger: PropTypes.object.isRequired,
251
+ onAwardChange: PropTypes.func.isRequired,
252
+ searchConfig: PropTypes.shape({
253
+ searchApi: PropTypes.shape({
254
+ axios: PropTypes.shape({
255
+ headers: PropTypes.object,
256
+ }),
257
+ }).isRequired,
258
+ initialQueryState: PropTypes.object.isRequired,
259
+ }).isRequired,
260
+ deserializeAward: PropTypes.func.isRequired,
261
+ deserializeFunder: PropTypes.func.isRequired,
262
+ computeFundingContents: PropTypes.func.isRequired,
263
+ initialFunding: PropTypes.object,
264
+ };
265
+
266
+ FundingModal.defaultProps = {
267
+ initialFunding: undefined,
268
+ };
269
+
270
+ export default FundingModal;
@@ -0,0 +1,37 @@
1
+ // This file is part of InvenioVocabularies
2
+ // Copyright (C) 2021-2024 CERN.
3
+ // Copyright (C) 2021 Northwestern University.
4
+ //
5
+ // Invenio is free software; you can redistribute it and/or modify it
6
+ // under the terms of the MIT License; see LICENSE file for more details.
7
+
8
+ import PropTypes from "prop-types";
9
+ import React from "react";
10
+ import { Segment } from "semantic-ui-react";
11
+ import { i18next } from "@translations/invenio_rdm_records/i18next";
12
+
13
+ export function NoAwardResults({ switchToCustom }) {
14
+ return (
15
+ <Segment
16
+ basic
17
+ content={
18
+ <p>
19
+ {i18next.t("Did not find your award/grant? ")}
20
+ <a
21
+ href="/"
22
+ onClick={(e) => {
23
+ e.preventDefault();
24
+ switchToCustom();
25
+ }}
26
+ >
27
+ {i18next.t("Add a custom award/grant.")}
28
+ </a>
29
+ </p>
30
+ }
31
+ />
32
+ );
33
+ }
34
+
35
+ NoAwardResults.propTypes = {
36
+ switchToCustom: PropTypes.func.isRequired,
37
+ };
@@ -0,0 +1,8 @@
1
+ // This file is part of InvenioVocabularies
2
+ // Copyright (C) 2021-2023 CERN.
3
+ // Copyright (C) 2021 Northwestern University.
4
+ //
5
+ // Invenio is free software; you can redistribute it and/or modify it
6
+ // under the terms of the MIT License; see LICENSE file for more details.
7
+
8
+ export { FundingField } from "./FundingField";
@@ -0,0 +1,7 @@
1
+ // This file is part of InvenioVocabularies
2
+ // Copyright (C) 2023 CERN.
3
+ //
4
+ // Invenio is free software; you can redistribute it and/or modify it
5
+ // under the terms of the MIT License; see LICENSE file for more details.
6
+
7
+ export { FundingField } from "./Funding";