@k-int/stripes-kint-components 1.5.0 → 2.0.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.
Files changed (168) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/es/index.js +80 -25
  3. package/es/lib/ActionList/ActionList.js +92 -33
  4. package/es/lib/ActionList/ActionListFieldArray.js +202 -104
  5. package/es/lib/ActionList/index.js +7 -3
  6. package/es/lib/CustomProperties/Config/CustomPropertiesLookup.js +198 -0
  7. package/es/lib/CustomProperties/Config/CustomPropertiesSettings.js +321 -0
  8. package/es/lib/CustomProperties/Config/CustomPropertiesView.js +166 -0
  9. package/es/lib/CustomProperties/Config/CustomPropertyForm.js +357 -0
  10. package/es/lib/CustomProperties/Config/index.js +41 -0
  11. package/es/lib/EditableRefdataList/EditableRefdataList.js +69 -24
  12. package/es/lib/EditableRefdataList/index.js +7 -3
  13. package/es/lib/EditableSettingsList/EditableSettingsList.js +90 -0
  14. package/es/lib/EditableSettingsList/EditableSettingsListFieldArray.js +90 -0
  15. package/es/lib/EditableSettingsList/EditableSettingsListFieldArray.test.js +181 -0
  16. package/es/lib/{Settings → EditableSettingsList/SettingField}/EditSettingValue.js +72 -9
  17. package/es/lib/EditableSettingsList/SettingField/EditSettingValue.test.js +447 -0
  18. package/es/lib/{Settings → EditableSettingsList/SettingField}/RenderSettingValue.js +45 -7
  19. package/es/lib/EditableSettingsList/SettingField/RenderSettingValue.test.js +495 -0
  20. package/es/lib/EditableSettingsList/SettingField/SettingField.js +187 -0
  21. package/es/lib/EditableSettingsList/SettingField/SettingField.test.js +180 -0
  22. package/es/lib/EditableSettingsList/SettingField/index.js +35 -0
  23. package/es/lib/EditableSettingsList/index.js +35 -0
  24. package/es/lib/FormModal/FormModal.js +126 -0
  25. package/es/lib/FormModal/index.js +19 -0
  26. package/es/lib/NoResultsMessage/NoResultsMessage.js +65 -32
  27. package/es/lib/NoResultsMessage/index.js +7 -3
  28. package/es/lib/QueryTypedown/QueryTypedown.js +48 -9
  29. package/es/lib/QueryTypedown/index.js +6 -2
  30. package/es/lib/RefdataButtons/RefdataButtons.js +143 -0
  31. package/es/lib/RefdataButtons/index.js +19 -0
  32. package/es/lib/SASQLookupComponent/SASQLookupComponent.js +194 -140
  33. package/es/lib/SASQLookupComponent/index.js +6 -2
  34. package/es/lib/SASQRoute/SASQRoute.js +55 -18
  35. package/es/lib/SASQRoute/index.js +6 -2
  36. package/es/lib/SASQViewComponent/SASQViewComponent.js +50 -11
  37. package/es/lib/SASQViewComponent/index.js +6 -2
  38. package/es/lib/SearchField/SearchField.js +48 -13
  39. package/es/lib/SearchField/index.js +6 -2
  40. package/es/lib/SettingPage/SettingPage.js +99 -0
  41. package/es/lib/SettingPage/SettingPagePane.js +83 -0
  42. package/es/lib/SettingPage/index.js +27 -0
  43. package/es/lib/Typedown/Typedown.js +174 -99
  44. package/es/lib/Typedown/index.js +6 -2
  45. package/es/lib/constants/customProperties.js +60 -0
  46. package/es/lib/constants/eventCodes.js +31 -1
  47. package/es/lib/contexts/SettingsContext.js +41 -0
  48. package/es/lib/contexts/index.js +19 -0
  49. package/es/lib/hooks/index.js +44 -10
  50. package/es/lib/hooks/settingsHooks/index.js +27 -0
  51. package/es/lib/hooks/settingsHooks/useSettingSection.js +74 -0
  52. package/es/lib/hooks/settingsHooks/useSettings.js +175 -0
  53. package/es/lib/hooks/typedownHooks/index.js +8 -28
  54. package/es/lib/hooks/typedownHooks/useTypedown.js +129 -12
  55. package/es/lib/hooks/typedownHooks/useTypedownData.js +35 -2
  56. package/es/lib/hooks/typedownHooks/useTypedownToggle.js +39 -6
  57. package/es/lib/hooks/useActiveElement.js +33 -2
  58. package/es/lib/hooks/useCustomProperties.js +112 -0
  59. package/es/lib/hooks/useHelperApp.js +44 -11
  60. package/es/lib/hooks/useKiwtFieldArray.js +37 -4
  61. package/es/lib/hooks/useKiwtSASQuery.js +43 -9
  62. package/es/lib/hooks/useLocalStorageState.js +37 -4
  63. package/es/lib/hooks/useMutateCustomProperties.js +143 -0
  64. package/es/lib/hooks/useMutateRefdataValue.js +42 -9
  65. package/es/lib/hooks/useQIndex.js +42 -9
  66. package/es/lib/hooks/useRefdata.js +43 -16
  67. package/es/lib/hooks/useTemplates.js +36 -3
  68. package/es/lib/utils/buildUrl.js +43 -10
  69. package/es/lib/utils/generateKiwtQuery.js +33 -4
  70. package/es/lib/utils/generateKiwtQueryParams.js +31 -2
  71. package/es/lib/utils/index.js +41 -5
  72. package/es/lib/utils/refdataOptions.js +43 -0
  73. package/es/lib/utils/renderHelpText.js +109 -0
  74. package/es/lib/utils/selectorSafe.js +31 -2
  75. package/es/lib/utils/sortByLabel.js +55 -0
  76. package/es/lib/utils/toCamelCase.js +48 -0
  77. package/jest.config.js +15 -1
  78. package/package.json +19 -10
  79. package/src/index.js +25 -10
  80. package/src/lib/ActionList/ActionList.js +32 -22
  81. package/src/lib/ActionList/ActionListFieldArray.js +56 -10
  82. package/src/lib/ActionList/README.md +5 -1
  83. package/src/lib/ActionList/index.js +1 -1
  84. package/src/lib/CustomProperties/Config/CustomPropertiesLookup.js +111 -0
  85. package/src/lib/CustomProperties/Config/CustomPropertiesSettings.js +237 -0
  86. package/src/lib/CustomProperties/Config/CustomPropertiesView.js +150 -0
  87. package/src/lib/CustomProperties/Config/CustomPropertyForm.js +295 -0
  88. package/src/lib/CustomProperties/Config/index.js +4 -0
  89. package/src/lib/EditableRefdataList/EditableRefdataList.js +10 -5
  90. package/src/lib/EditableRefdataList/index.js +1 -1
  91. package/src/lib/{Settings → EditableSettingsList}/EditableSettingsList.js +0 -0
  92. package/src/lib/{Settings → EditableSettingsList}/EditableSettingsListFieldArray.js +2 -2
  93. package/src/lib/EditableSettingsList/EditableSettingsListFieldArray.test.js +111 -0
  94. package/src/lib/{Settings → EditableSettingsList/SettingField}/EditSettingValue.js +24 -1
  95. package/src/lib/EditableSettingsList/SettingField/EditSettingValue.test.js +379 -0
  96. package/src/lib/{Settings → EditableSettingsList/SettingField}/RenderSettingValue.js +2 -1
  97. package/src/lib/EditableSettingsList/SettingField/RenderSettingValue.test.js +368 -0
  98. package/src/lib/{Settings → EditableSettingsList/SettingField}/SettingField.js +7 -7
  99. package/src/lib/EditableSettingsList/SettingField/SettingField.test.js +80 -0
  100. package/src/lib/EditableSettingsList/SettingField/index.js +3 -0
  101. package/src/lib/EditableSettingsList/index.js +3 -0
  102. package/src/lib/FormModal/FormModal.js +71 -0
  103. package/src/lib/FormModal/index.js +1 -0
  104. package/src/lib/NoResultsMessage/NoResultsMessage.js +2 -2
  105. package/src/lib/NoResultsMessage/index.js +1 -1
  106. package/src/lib/{Settings → RefdataButtons}/RefdataButtons.js +1 -1
  107. package/src/lib/RefdataButtons/index.js +1 -0
  108. package/src/lib/SASQLookupComponent/SASQLookupComponent.js +7 -1
  109. package/src/lib/{Settings → SettingPage}/SettingPage.js +5 -5
  110. package/src/lib/{Settings → SettingPage}/SettingPagePane.js +12 -2
  111. package/src/lib/SettingPage/index.js +2 -0
  112. package/src/lib/Typedown/Typedown.js +52 -9
  113. package/src/lib/constants/customProperties.js +9 -0
  114. package/src/lib/{Settings → contexts}/SettingsContext.js +1 -1
  115. package/src/lib/contexts/index.js +2 -0
  116. package/src/lib/hooks/index.js +3 -0
  117. package/src/lib/hooks/settingsHooks/index.js +2 -0
  118. package/src/lib/{Settings → hooks/settingsHooks}/useSettingSection.js +0 -0
  119. package/src/lib/{Settings → hooks/settingsHooks}/useSettings.js +14 -6
  120. package/src/lib/hooks/typedownHooks/index.js +0 -3
  121. package/src/lib/hooks/typedownHooks/useTypedown.js +93 -11
  122. package/src/lib/hooks/useCustomProperties.js +73 -0
  123. package/src/lib/hooks/useMutateCustomProperties.js +62 -0
  124. package/src/lib/hooks/useRefdata.js +2 -8
  125. package/src/lib/utils/index.js +7 -0
  126. package/src/lib/utils/refdataOptions.js +7 -0
  127. package/src/lib/{Settings/utils → utils}/renderHelpText.js +1 -1
  128. package/src/lib/{Settings/utils → utils}/sortByLabel.js +1 -1
  129. package/src/lib/{Settings/utils → utils}/toCamelCase.js +0 -0
  130. package/test/helpers/index.js +1 -0
  131. package/test/helpers/translationsProperties.js +40 -0
  132. package/test/jest/helpers/KintHarness.js +36 -0
  133. package/test/jest/helpers/index.js +2 -0
  134. package/test/jest/helpers/renderWithKintHarness.js +15 -0
  135. package/test/jest/jest-transformer.js +4 -0
  136. package/test/jest/setupTests.js +1 -0
  137. package/translations/stripes-kint-components/en.json +48 -1
  138. package/yarn-error.log +14118 -0
  139. package/babelOptions.js +0 -30
  140. package/es/lib/Settings/EditableSettingsList.js +0 -57
  141. package/es/lib/Settings/EditableSettingsListFieldArray.js +0 -59
  142. package/es/lib/Settings/RefdataButtons.js +0 -100
  143. package/es/lib/Settings/SettingField.js +0 -144
  144. package/es/lib/Settings/SettingPage.js +0 -64
  145. package/es/lib/Settings/SettingPagePane.js +0 -43
  146. package/es/lib/Settings/SettingsContext.js +0 -18
  147. package/es/lib/Settings/index.js +0 -71
  148. package/es/lib/Settings/useSettingSection.js +0 -41
  149. package/es/lib/Settings/useSettings.js +0 -126
  150. package/es/lib/Settings/utils/index.js +0 -31
  151. package/es/lib/Settings/utils/renderHelpText.js +0 -57
  152. package/es/lib/Settings/utils/sortByLabel.js +0 -26
  153. package/es/lib/Settings/utils/toCamelCase.js +0 -19
  154. package/es/lib/TypeDown/TypeDown.js +0 -209
  155. package/es/lib/TypeDown/index.js +0 -15
  156. package/es/lib/hooks/typedownHooks/useTypedownFooter.js +0 -47
  157. package/es/lib/hooks/typedownHooks/useTypedownList.js +0 -45
  158. package/es/lib/hooks/typedownHooks/useTypedownSearchField.js +0 -47
  159. package/es/lib/utils/getFocusableElements.js +0 -132
  160. package/src/lib/Settings/index.js +0 -8
  161. package/src/lib/Settings/utils/index.js +0 -3
  162. package/src/lib/TypeDown/README.md +0 -1
  163. package/src/lib/TypeDown/TypeDown.js +0 -226
  164. package/src/lib/TypeDown/index.js +0 -1
  165. package/src/lib/hooks/typedownHooks/useTypedownFooter.js +0 -43
  166. package/src/lib/hooks/typedownHooks/useTypedownList.js +0 -36
  167. package/src/lib/hooks/typedownHooks/useTypedownSearchField.js +0 -39
  168. package/src/lib/utils/getFocusableElements.js +0 -99
@@ -15,8 +15,11 @@ const propTypes = {
15
15
  actionAssigner: PropTypes.func,
16
16
  actionCalls: PropTypes.object,
17
17
  columnMapping: PropTypes.object,
18
+ creatableFields: PropTypes.object,
18
19
  editableFields: PropTypes.object,
19
20
  fields: PropTypes.object,
21
+ fieldComponents: PropTypes.object,
22
+ formatter: PropTypes.object,
20
23
  visibleFields: PropTypes.arrayOf(PropTypes.string)
21
24
  };
22
25
 
@@ -24,9 +27,12 @@ const ActionListFieldArray = ({
24
27
  actionAssigner,
25
28
  actionCalls,
26
29
  columnMapping,
30
+ creatableFields,
27
31
  editableFields,
28
32
  fields,
29
- visibleFields
33
+ fieldComponents,
34
+ visibleFields,
35
+ ...mclProps // Assume anything left over is to directly apply to the MCL
30
36
  }) => {
31
37
  // Grab finalForm functions/values from form hooks
32
38
  const { change } = useForm();
@@ -54,7 +60,7 @@ const ActionListFieldArray = ({
54
60
  };
55
61
 
56
62
  const handleCreate = (index) => {
57
- const rowData = fields.value[index];
63
+ const { actionListActions: _a, ...rowData } = fields.value[index];
58
64
  actionCalls.create(rowData);
59
65
  };
60
66
 
@@ -105,8 +111,13 @@ const ActionListFieldArray = ({
105
111
  key={`cancel[${data.rowIndex}]`}
106
112
  data-type-button="cancel"
107
113
  onClick={() => {
108
- change(fieldName, get(initialValues, fieldName));
109
- toggleEditing(data.id);
114
+ if (!data.id && editing === 'NEW_ROW') {
115
+ fields.remove(data.rowIndex);
116
+ toggleEditing('NEW_ROW');
117
+ } else {
118
+ change(fieldName, get(initialValues, fieldName));
119
+ toggleEditing(data.id);
120
+ }
110
121
  }}
111
122
  >
112
123
  <FormattedMessage id="stripes-kint-components.actionList.cancel" />
@@ -153,7 +164,7 @@ const ActionListFieldArray = ({
153
164
 
154
165
  const formatContent = () => {
155
166
  return (
156
- fields.map(fieldName => {
167
+ fields.map((fieldName, fieldIndex) => {
157
168
  // Fetch the content from the field Values
158
169
  const cd = get(values, fieldName);
159
170
  cd.actionListActions = actionAssigner(cd);
@@ -170,19 +181,30 @@ const ActionListFieldArray = ({
170
181
  */
171
182
  for (const key of visibleFields) {
172
183
  const editFunction = editableFields[key] ?? (() => true);
184
+ const createFunction = creatableFields[key] ?? (() => true);
173
185
  /*
174
- Next check if this is a new row, if so we should edit it in a Field
175
- If it does, then we check if the property has an editableField function,
176
- if it does we run it with the data. If not then we just return the Field
186
+ Next check if this is a new row, if so we should run the createableField function with the data.
187
+ If it is not a new row, then we run the editableField function with the data,
188
+ and it should return true/false
189
+
190
+ For both checks
191
+ true => Field, false => display value
177
192
  */
178
193
  if (
179
- !cd.id ||
194
+ (!cd.id && createFunction(cd)) ||
180
195
  (editFunction(cd))
181
196
  ) {
182
197
  returnObj[key] =
198
+ fieldComponents[key] ?
199
+ fieldComponents[key]({
200
+ name: `${fieldName}.${key}`
201
+ }) :
183
202
  <Field
203
+ autofocus={fieldIndex === 0}
184
204
  component={TextField}
205
+ marginBottom0
185
206
  name={`${fieldName}.${key}`}
207
+ parse={v => v}
186
208
  />;
187
209
  }
188
210
  }
@@ -192,6 +214,28 @@ const ActionListFieldArray = ({
192
214
  );
193
215
  };
194
216
 
217
+ const { formatter, ...restOfMclProps } = mclProps; // Destructure formatter part of mclProps
218
+ const fieldAwareFormatter = () => {
219
+ const returnObj = {};
220
+ // For each visible field, if it's being edited then ignore passed formatters, else use them
221
+ visibleFields.forEach(key => {
222
+ returnObj[key] = cd => {
223
+ // Row is being edited if it has no id, or its id is in the editing string
224
+ const editingRow = cd.id === editing || !cd.id;
225
+ // If not editing, use the passed formatter values
226
+
227
+ let returnValue = cd[key];
228
+
229
+ if (!editingRow && formatter[key]) {
230
+ returnValue = formatter[key](cd);
231
+ }
232
+
233
+ return returnValue;
234
+ };
235
+ });
236
+ return returnObj;
237
+ };
238
+
195
239
  return (
196
240
  <>
197
241
  <Button
@@ -212,10 +256,12 @@ const ActionListFieldArray = ({
212
256
  columnWidths={getColumnWidths()}
213
257
  contentData={formatContent()}
214
258
  formatter={{
215
- actionListActions: renderActionButtons
259
+ actionListActions: renderActionButtons,
260
+ ...fieldAwareFormatter()
216
261
  }}
217
262
  interactive={false}
218
263
  visibleColumns={[...visibleFields, 'actionListActions']}
264
+ {...restOfMclProps}
219
265
  />
220
266
  </>
221
267
  );
@@ -61,5 +61,9 @@ actionAssigner | function | A function which will be passed the entire row objec
61
61
  actionCalls | object<function> | An object with keys matching any "actions" the `actionAssigner` may have assigned (In addition to special case `create`, if relevant), and values which are functions. These functions will be handed the row as a parameter. | {} | ✕ |
62
62
  columnMapping | object | An object which will act on the rendered MultiColumnList headers to map the labels for each `visibleField` | | ✕ |
63
63
  contentData | array | An array of objects to render along with their actions | | ✓ |
64
- editableFields | object<function> | An object with keys from the `visibleFields` array, and values of functions which take the entire row object and return a boolean indicating whether that field is editable or not. | | ✕ |
64
+ creatableFields | object<function> | An object with keys from the `visibleFields` array, and values of functions which take the entire row object and return a boolean indicating whether that field is fillable on create or not. | | ✕ |
65
+ editableFields | object<function> | An object with keys from the `visibleFields` array, and values of functions which take the entire row object and return a boolean indicating whether that field is editable or not. No key for a given field will be interpreted as () => true, so a field is editable by default. | | ✕ |
66
+ fieldComponents | object<function> | An object with keys from the `visibleFields` array, and values of functions which take some `fieldProps` (currently only the name of the field `name`), and returns a Field component to be used in "edit mode" for the visible field specified. | | ✕ |
67
+ formatter | object<function> | A "formatter" object that takes the same shape as an MCL formatter, and is used in the same way whilst a row is NOT being edited. While editing a given row, this formatter entry is ignored. | | ✕ |
65
68
  visibleFields | array<String> | An array of strings corresponding to those fields to be displayed in the rendered MultiColumnList | | ✓ |
69
+ ...mclProps | any | Any other props supplied to ActionList will be applied to the MCL directly. *WARNING* Some MCL props may override important functionality within ActionList | | ✕ |
@@ -1 +1 @@
1
- export { default as ActionList } from './ActionList';
1
+ export { default } from './ActionList';
@@ -0,0 +1,111 @@
1
+ import { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import { FormattedMessage } from 'react-intl';
5
+
6
+ import debounce from 'lodash/debounce';
7
+
8
+ import { Col, MultiColumnList, Row, Spinner, Select } from '@folio/stripes/components';
9
+
10
+ import SearchField from '../../SearchField';
11
+ import { useCustomProperties } from '../../hooks';
12
+
13
+ const DEBOUNCE_TIME = 500;
14
+
15
+ const CustomPropertiesLookup = ({
16
+ contextFilterOptions, // expects an array of the form [{value: "OpenAccess", label: "Open Access"}, {value: false, label: "None"}]
17
+ customPropertiesEndpoint: endpoint,
18
+ labelOverrides,
19
+ mclProps,
20
+ onSelectCustomProperty,
21
+ queryParams
22
+ }) => {
23
+ const [nsValues, setNsValues] = useState({
24
+ sort: 'id'
25
+ });
26
+ const [selectedContext, setSelectedContext] = useState();
27
+
28
+ const { data: custprops, isLoading } = useCustomProperties({
29
+ endpoint,
30
+ nsValues,
31
+ queryParams,
32
+ returnQueryObject: true,
33
+ ctx: selectedContext
34
+ });
35
+
36
+ const handleSearch = debounce((query) => {
37
+ setNsValues({
38
+ ...nsValues,
39
+ query,
40
+ });
41
+ }, DEBOUNCE_TIME);
42
+
43
+ return (
44
+ <>
45
+ <SearchField fullWidth onChange={e => handleSearch(e.target.value)} />
46
+ <Row>
47
+ <Col xs={6}>
48
+ <Select
49
+ dataOptions={contextFilterOptions}
50
+ onChange={(e) => {
51
+ setSelectedContext(e.target.value);
52
+ }}
53
+ value={selectedContext}
54
+ />
55
+ </Col>
56
+ </Row>
57
+ {isLoading ?
58
+ <Spinner /> :
59
+ <MultiColumnList
60
+ columnMapping={{
61
+ 'label': labelOverrides?.label ?? <FormattedMessage id="stripes-kint-components.customProperties.label" />,
62
+ 'primary': labelOverrides?.primary ?? <FormattedMessage id="stripes-kint-components.customProperties.primary" />,
63
+ 'ctx': labelOverrides?.ctx ?? <FormattedMessage id="stripes-kint-components.customProperties.ctx" />,
64
+ 'weight': labelOverrides?.weight ?? <FormattedMessage id="stripes-kint-components.customProperties.weight" />,
65
+ 'type': labelOverrides?.type ?? <FormattedMessage id="stripes-kint-components.customProperties.type" />,
66
+ 'category': labelOverrides?.category ?? <FormattedMessage id="stripes-kint-components.customProperties.category" />
67
+ }}
68
+ contentData={custprops}
69
+ formatter={{
70
+ primary: data => {
71
+ if (data?.primary) {
72
+ return (
73
+ <FormattedMessage id="stripes-kint-components.yes" />
74
+ );
75
+ } else {
76
+ return (
77
+ <FormattedMessage id="stripes-kint-components.no" />
78
+ );
79
+ }
80
+ },
81
+ type: data => (
82
+ <FormattedMessage id={`stripes-kint-components.customProperties.type.${data?.type}`} />
83
+ ),
84
+ category: data => data?.category?.desc
85
+ }}
86
+ onRowClick={onSelectCustomProperty}
87
+ visibleColumns={['label', 'primary', 'ctx', 'weight', 'type', 'category']}
88
+ {...mclProps}
89
+ />
90
+ }
91
+ </>
92
+ );
93
+ };
94
+
95
+ CustomPropertiesLookup.propTypes = {
96
+ contextFilterOptions: PropTypes.arrayOf(PropTypes.shape({
97
+ value: PropTypes.string,
98
+ label: PropTypes.oneOfType([
99
+ PropTypes.element,
100
+ PropTypes.string
101
+ ])
102
+ })),
103
+ customPropertiesEndpoint: PropTypes.string,
104
+ labelOverrides: PropTypes.object,
105
+ mclProps: PropTypes.object,
106
+ onSelectCustomProperty: PropTypes.func,
107
+ queryParams: PropTypes.object,
108
+ refdataEndpoint: PropTypes.string,
109
+ };
110
+
111
+ export default CustomPropertiesLookup;
@@ -0,0 +1,237 @@
1
+ import { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import compose from 'compose-function';
5
+
6
+ import { FormattedMessage, useIntl } from 'react-intl';
7
+
8
+ import { useQueryClient } from 'react-query';
9
+
10
+ import SafeHTMLMessage from '@folio/react-intl-safe-html';
11
+
12
+ import { Button, ConfirmationModal, Pane } from '@folio/stripes/components';
13
+
14
+ import FormModal from '../../FormModal/FormModal';
15
+
16
+ import CustomPropertiesLookup from './CustomPropertiesLookup';
17
+ import CustomPropertiesView from './CustomPropertiesView';
18
+ import CustomPropertiesForm from './CustomPropertyForm';
19
+ import { useMutateCustomProperties, useRefdata } from '../../hooks';
20
+
21
+ const EDITING = 'edit';
22
+ const CREATING = 'create';
23
+ const VIEWING = 'view';
24
+
25
+ // A default option for setting up panes manually
26
+ const CustomPropertiesSettings = ({
27
+ afterQueryCalls,
28
+ contextFilterOptions,
29
+ customPropertiesEndpoint,
30
+ helpPopovers,
31
+ labelOverrides,
32
+ refdataEndpoint,
33
+ }) => {
34
+ const queryClient = useQueryClient();
35
+
36
+ const intl = useIntl();
37
+ const [customProperty, setCustomProperty] = useState();
38
+ const [deleteModal, setDeleteModal] = useState(false);
39
+
40
+ const refdata = useRefdata({
41
+ endpoint: refdataEndpoint,
42
+ });
43
+
44
+ const [mode, setMode] = useState(VIEWING);
45
+
46
+ // Default props that need hooks are hard
47
+ let renderContextFilterOptions = contextFilterOptions;
48
+ if (!contextFilterOptions) {
49
+ /*
50
+ Default is {value: '', label: 'All'}, empty string will map to ALL contexts
51
+ If null context is needed, use
52
+ {value: 'isNull', label: ...}
53
+ */
54
+ renderContextFilterOptions = [
55
+ {
56
+ value: '', // empty string is all custoprop contexts
57
+ label: intl.formatMessage({ id: 'stripes-kint-components.customProperties.all' })
58
+ }
59
+ ];
60
+ }
61
+
62
+ let renderViewPaneTitle = labelOverrides?.viewPaneTitle;
63
+ if (renderViewPaneTitle instanceof Function) {
64
+ renderViewPaneTitle = renderViewPaneTitle(customProperty);
65
+ }
66
+
67
+ // Defaulting is hard
68
+ const afterQueryCallsSafe = {
69
+ put: () => null,
70
+ post: () => null,
71
+ delete: () => null,
72
+ ...afterQueryCalls
73
+ };
74
+
75
+ const {
76
+ post: createCustprop,
77
+ put: editCustProp,
78
+ delete: deleteCustProp
79
+ } = useMutateCustomProperties({
80
+ afterQueryCalls: {
81
+ put: () => {
82
+ setMode(VIEWING);
83
+ queryClient.invalidateQueries(['stripes-kint-components', 'useCustomProperties', 'custprops']);
84
+ afterQueryCallsSafe.put();
85
+ },
86
+ post: () => {
87
+ setMode(VIEWING);
88
+ queryClient.invalidateQueries(['stripes-kint-components', 'useCustomProperties', 'custprops']);
89
+ afterQueryCallsSafe.post();
90
+ },
91
+ delete: () => {
92
+ setMode(VIEWING);
93
+ queryClient.invalidateQueries(['stripes-kint-components', 'useCustomProperties', 'custprops']);
94
+ afterQueryCallsSafe.delete();
95
+ }
96
+ },
97
+ endpoint: customPropertiesEndpoint,
98
+ id: customProperty?.id
99
+ });
100
+
101
+ const handeContextSubmit = (submitData) => {
102
+ return {
103
+ ...submitData,
104
+ ctx: submitData?.ctx?.[0]?.value
105
+ };
106
+ };
107
+
108
+ return (
109
+ <>
110
+ <Pane
111
+ defaultWidth="fill"
112
+ id="settings-customProperties.lookupPane"
113
+ lastMenu={
114
+ <Button
115
+ marginBottom0
116
+ onClick={() => setMode(CREATING)} // TODO do we need to clear form here too?
117
+ >
118
+ <FormattedMessage id="stripes-kint-components.create" />
119
+ </Button>
120
+ }
121
+ paneTitle={labelOverrides.paneTitle ??
122
+ <FormattedMessage id="stripes-kint-components.customProperties" /> // This should be configurable?
123
+ }
124
+ >
125
+ <CustomPropertiesLookup
126
+ contextFilterOptions={renderContextFilterOptions}
127
+ customPropertiesEndpoint={customPropertiesEndpoint}
128
+ labelOverrides={labelOverrides}
129
+ onSelectCustomProperty={(_e, cp) => setCustomProperty(cp)}
130
+ />
131
+ </Pane>
132
+ {customProperty &&
133
+ <Pane
134
+ actionMenu={({ onToggle }) => (
135
+ [
136
+ <Button
137
+ buttonStyle="dropdownItem"
138
+ marginBottom0
139
+ onClick={() => setMode(EDITING)}
140
+ >
141
+ <FormattedMessage id="stripes-kint-components.edit" />
142
+ </Button>,
143
+ <Button
144
+ buttonStyle="dropdownItem"
145
+ marginBottom0
146
+ onClick={() => {
147
+ setDeleteModal(true);
148
+ onToggle();
149
+ }}
150
+ >
151
+ <FormattedMessage id="stripes-kint-components.delete" />
152
+ </Button>
153
+ ]
154
+ )}
155
+ defaultWidth="fill"
156
+ dismissible
157
+ id="settings-customProperties-viewPane"
158
+ onClose={() => setCustomProperty()}
159
+ paneTitle={
160
+ renderViewPaneTitle ?? customProperty?.label ?? customProperty?.name
161
+ }
162
+ >
163
+ <CustomPropertiesView
164
+ customProperty={customProperty}
165
+ labelOverrides={labelOverrides}
166
+ />
167
+ </Pane>
168
+ }
169
+ <FormModal
170
+ initialValues={mode === CREATING ?
171
+ {
172
+ weight: 0,
173
+ primary: true,
174
+ defaultInternal: true
175
+ } :
176
+ customProperty
177
+ }
178
+ modalProps={{
179
+ dismissible: true,
180
+ onClose: () => setMode(VIEWING),
181
+ open: (mode === CREATING || mode === EDITING)
182
+ }}
183
+ onSubmit={mode === CREATING ?
184
+ compose(createCustprop, handeContextSubmit) :
185
+ compose(editCustProp, handeContextSubmit)
186
+ }
187
+ >
188
+ <CustomPropertiesForm
189
+ contextFilterOptions={renderContextFilterOptions}
190
+ helpPopovers={helpPopovers}
191
+ labelOverrides={labelOverrides}
192
+ refdata={refdata.map(rdc => ({ label: rdc.desc, value: rdc.id }))}
193
+ />
194
+ </FormModal>
195
+ <ConfirmationModal
196
+ buttonStyle="danger"
197
+ confirmLabel={
198
+ labelOverrides?.confirmLabel ??
199
+ <FormattedMessage id="stripes-kint-components.customProperties.delete.confirmLabel" />
200
+ }
201
+ heading={
202
+ labelOverrides?.confirmHeading ??
203
+ <FormattedMessage id="stripes-kint-components.customProperties.delete.confirmHeading" />
204
+ }
205
+ id="delete-job-confirmation"
206
+ message={
207
+ labelOverrides?.confirmMessage ??
208
+ <SafeHTMLMessage id="stripes-kint-components.customProperties.delete.confirmMessage" values={{ name: customProperty?.name }} />
209
+ }
210
+ onCancel={() => setDeleteModal(false)}
211
+ onConfirm={() => {
212
+ deleteCustProp();
213
+ setCustomProperty();
214
+ setDeleteModal(false);
215
+ }}
216
+ open={deleteModal}
217
+ />
218
+ </>
219
+ );
220
+ };
221
+
222
+ CustomPropertiesSettings.propTypes = {
223
+ afterQueryCalls: PropTypes.object,
224
+ contextFilterOptions: PropTypes.arrayOf(PropTypes.shape({
225
+ value: PropTypes.string,
226
+ label: PropTypes.oneOfType([
227
+ PropTypes.element,
228
+ PropTypes.string
229
+ ])
230
+ })),
231
+ customPropertiesEndpoint: PropTypes.string,
232
+ helpPopovers: PropTypes.object,
233
+ labelOverrides: PropTypes.object,
234
+ refdataEndpoint: PropTypes.string,
235
+ };
236
+
237
+ export default CustomPropertiesSettings;
@@ -0,0 +1,150 @@
1
+ import PropTypes from 'prop-types';
2
+ import { FormattedMessage } from 'react-intl';
3
+ import { Col, KeyValue, NoValue, Row } from '@folio/stripes/components';
4
+
5
+ import { REFDATA_CLASS_NAME } from '../../constants/customProperties';
6
+
7
+ // A default option for CustProp view pane, with the ability to override labels for fields
8
+ const CustomPropertiesView = ({
9
+ customProperty,
10
+ labelOverrides
11
+ }) => {
12
+ return (
13
+ <>
14
+ <Row>
15
+ <Col xs={6}>
16
+ <KeyValue
17
+ label={
18
+ labelOverrides?.label ??
19
+ <FormattedMessage id="stripes-kint-components.customProperties.label" />
20
+ }
21
+ value={customProperty?.label}
22
+ />
23
+ </Col>
24
+ <Col xs={6}>
25
+ <KeyValue
26
+ label={
27
+ labelOverrides?.name ??
28
+ <FormattedMessage id="stripes-kint-components.customProperties.name" />
29
+ }
30
+ value={customProperty?.name}
31
+ />
32
+ </Col>
33
+ </Row>
34
+ <Row>
35
+ <Col xs={12}>
36
+ <KeyValue
37
+ label={
38
+ labelOverrides?.description ??
39
+ <FormattedMessage id="stripes-kint-components.customProperties.description" />
40
+ }
41
+ value={customProperty?.description}
42
+ />
43
+ </Col>
44
+ </Row>
45
+ <Row>
46
+ <Col xs={6}>
47
+ <KeyValue
48
+ label={
49
+ labelOverrides?.weight ??
50
+ <FormattedMessage id="stripes-kint-components.customProperties.weight" />
51
+ }
52
+ value={customProperty?.weight}
53
+ />
54
+ </Col>
55
+ <Col xs={6}>
56
+ <KeyValue
57
+ label={
58
+ labelOverrides?.primary ??
59
+ <FormattedMessage
60
+ id="stripes-kint-components.customProperties.primary"
61
+ />
62
+ }
63
+ value={
64
+ <FormattedMessage
65
+ id={
66
+ customProperty?.primary
67
+ ? 'stripes-kint-components.yes'
68
+ : 'stripes-kint-components.no'
69
+ }
70
+ />
71
+ }
72
+ />
73
+ </Col>
74
+ </Row>
75
+ <Row>
76
+ <Col xs={6}>
77
+ <KeyValue
78
+ label={
79
+ labelOverrides?.defaultVisibility ??
80
+ <FormattedMessage id="stripes-kint-components.customProperties.defaultVisibility" />
81
+ }
82
+ value={
83
+ <FormattedMessage
84
+ id={
85
+ customProperty?.defaultInternal
86
+ ? 'stripes-kint-components.customProperties.internalTrue'
87
+ : 'stripes-kint-components.customProperties.internalFalse'
88
+ }
89
+ />
90
+ }
91
+ />
92
+ </Col>
93
+ <Col xs={6}>
94
+ <KeyValue
95
+ label={
96
+ labelOverrides?.ctx ??
97
+ <FormattedMessage id="stripes-kint-components.customProperties.ctx" />
98
+ }
99
+ value={customProperty?.ctx ?? <NoValue />}
100
+ />
101
+ </Col>
102
+ </Row>
103
+ <Row>
104
+ <Col xs={6}>
105
+ {customProperty?.type && (
106
+ <KeyValue
107
+ label={
108
+ labelOverrides?.type ??
109
+ <FormattedMessage id="stripes-kint-components.customProperties.type" />
110
+ }
111
+ value={<FormattedMessage id={`stripes-kint-components.customProperties.type.${customProperty?.type}`} />}
112
+ />
113
+ )}
114
+ </Col>
115
+ <Col xs={6}>
116
+ {customProperty?.type === REFDATA_CLASS_NAME && (
117
+ <KeyValue
118
+ label={
119
+ labelOverrides?.category ??
120
+ <FormattedMessage id="stripes-kint-components.customProperties.category" />
121
+ }
122
+ value={customProperty?.category?.desc ?? <NoValue />}
123
+ />
124
+ )}
125
+ </Col>
126
+ </Row>
127
+ </>
128
+ );
129
+ };
130
+
131
+ CustomPropertiesView.propTypes = {
132
+ customProperty: PropTypes.shape({
133
+ id: PropTypes.string,
134
+ label: PropTypes.string,
135
+ name: PropTypes.string,
136
+ description: PropTypes.string,
137
+ weight: PropTypes.number,
138
+ primary: PropTypes.bool,
139
+ defaultInternal: PropTypes.bool,
140
+ ctx: PropTypes.string,
141
+ type: PropTypes.string,
142
+ category: PropTypes.shape({
143
+ desc: PropTypes.string
144
+ })
145
+
146
+ }),
147
+ labelOverrides: PropTypes.object
148
+ };
149
+
150
+ export default CustomPropertiesView;