@performant-software/semantic-components 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +0 -0
  3. package/build/index.js +2 -0
  4. package/build/index.js.map +1 -0
  5. package/build/main.css +786 -0
  6. package/index.js +1 -0
  7. package/package.json +37 -0
  8. package/src/components/AccordionDataList.css +8 -0
  9. package/src/components/AccordionDataList.js +224 -0
  10. package/src/components/AccordionList.css +27 -0
  11. package/src/components/AccordionList.js +596 -0
  12. package/src/components/AccordionSelector.css +3 -0
  13. package/src/components/AccordionSelector.js +359 -0
  14. package/src/components/ArrowButtons.css +4 -0
  15. package/src/components/ArrowButtons.js +38 -0
  16. package/src/components/AssociatedDropdown.css +44 -0
  17. package/src/components/AssociatedDropdown.js +338 -0
  18. package/src/components/BooleanIcon.css +0 -0
  19. package/src/components/BooleanIcon.js +33 -0
  20. package/src/components/CancelButton.css +0 -0
  21. package/src/components/CancelButton.js +25 -0
  22. package/src/components/ColorButton.css +4 -0
  23. package/src/components/ColorButton.js +34 -0
  24. package/src/components/ColorPickerModal.css +3 -0
  25. package/src/components/ColorPickerModal.js +77 -0
  26. package/src/components/ColumnResize.css +9 -0
  27. package/src/components/ColumnResize.js +20 -0
  28. package/src/components/DataList.css +0 -0
  29. package/src/components/DataList.js +531 -0
  30. package/src/components/DataTable.css +43 -0
  31. package/src/components/DataTable.js +596 -0
  32. package/src/components/DataTableColumnSelector.css +10 -0
  33. package/src/components/DataTableColumnSelector.js +146 -0
  34. package/src/components/DateInput.css +6 -0
  35. package/src/components/DateInput.js +58 -0
  36. package/src/components/DatePicker.css +72 -0
  37. package/src/components/DatePicker.js +81 -0
  38. package/src/components/DescriptorField.css +0 -0
  39. package/src/components/DescriptorField.js +42 -0
  40. package/src/components/DownloadButton.css +0 -0
  41. package/src/components/DownloadButton.js +23 -0
  42. package/src/components/Draggable.css +0 -0
  43. package/src/components/Draggable.js +94 -0
  44. package/src/components/DropdownButton.css +3 -0
  45. package/src/components/DropdownButton.js +65 -0
  46. package/src/components/DropdownMenu.css +0 -0
  47. package/src/components/DropdownMenu.js +68 -0
  48. package/src/components/EditModal.css +8 -0
  49. package/src/components/EditModal.js +99 -0
  50. package/src/components/EditPage.css +7 -0
  51. package/src/components/EditPage.js +249 -0
  52. package/src/components/EmbeddedList.css +7 -0
  53. package/src/components/EmbeddedList.js +278 -0
  54. package/src/components/FileInputButton.css +0 -0
  55. package/src/components/FileInputButton.js +54 -0
  56. package/src/components/FileUpload.css +31 -0
  57. package/src/components/FileUpload.js +188 -0
  58. package/src/components/FileUploadModal.css +0 -0
  59. package/src/components/FileUploadModal.js +408 -0
  60. package/src/components/FuzzyDate.css +8 -0
  61. package/src/components/FuzzyDate.js +575 -0
  62. package/src/components/GoogleMap.css +0 -0
  63. package/src/components/GoogleMap.js +105 -0
  64. package/src/components/GooglePlacesSearch.css +0 -0
  65. package/src/components/GooglePlacesSearch.js +43 -0
  66. package/src/components/HorizontalCards.css +50 -0
  67. package/src/components/HorizontalCards.js +226 -0
  68. package/src/components/ItemCollection.css +3 -0
  69. package/src/components/ItemCollection.js +159 -0
  70. package/src/components/ItemList.css +0 -0
  71. package/src/components/ItemList.js +126 -0
  72. package/src/components/Items.css +19 -0
  73. package/src/components/Items.js +365 -0
  74. package/src/components/ItemsToggle.css +0 -0
  75. package/src/components/ItemsToggle.js +168 -0
  76. package/src/components/KeyboardField.css +4 -0
  77. package/src/components/KeyboardField.js +147 -0
  78. package/src/components/LazyDocument.css +21 -0
  79. package/src/components/LazyDocument.js +113 -0
  80. package/src/components/LazyImage.css +21 -0
  81. package/src/components/LazyImage.js +119 -0
  82. package/src/components/LazyVideo.css +21 -0
  83. package/src/components/LazyVideo.js +131 -0
  84. package/src/components/LinkButton.css +8 -0
  85. package/src/components/LinkButton.js +23 -0
  86. package/src/components/LinkLabel.css +8 -0
  87. package/src/components/LinkLabel.js +29 -0
  88. package/src/components/List.css +8 -0
  89. package/src/components/List.js +761 -0
  90. package/src/components/ListFilters.css +0 -0
  91. package/src/components/ListFilters.js +408 -0
  92. package/src/components/ListLoader.css +8 -0
  93. package/src/components/ListLoader.js +32 -0
  94. package/src/components/ListTable.css +3 -0
  95. package/src/components/ListTable.js +86 -0
  96. package/src/components/LoginModal.css +7 -0
  97. package/src/components/LoginModal.js +102 -0
  98. package/src/components/MasonryGrid.css +48 -0
  99. package/src/components/MasonryGrid.js +202 -0
  100. package/src/components/MediaGallery.css +37 -0
  101. package/src/components/MediaGallery.js +148 -0
  102. package/src/components/MediaGrid.css +72 -0
  103. package/src/components/MediaGrid.js +74 -0
  104. package/src/components/MediaList.css +3 -0
  105. package/src/components/MediaList.js +98 -0
  106. package/src/components/ModalDropdown.css +11 -0
  107. package/src/components/ModalDropdown.js +84 -0
  108. package/src/components/NestedAccordion.css +41 -0
  109. package/src/components/NestedAccordion.js +276 -0
  110. package/src/components/PhotoViewer.css +3 -0
  111. package/src/components/PhotoViewer.js +36 -0
  112. package/src/components/PlayButton.css +3 -0
  113. package/src/components/PlayButton.js +37 -0
  114. package/src/components/RemoteDropdown.css +13 -0
  115. package/src/components/RemoteDropdown.js +368 -0
  116. package/src/components/SaveButton.css +0 -0
  117. package/src/components/SaveButton.js +31 -0
  118. package/src/components/Section.css +0 -0
  119. package/src/components/Section.js +41 -0
  120. package/src/components/Selectize.css +11 -0
  121. package/src/components/Selectize.js +297 -0
  122. package/src/components/SelectizeHeader.css +3 -0
  123. package/src/components/SelectizeHeader.js +40 -0
  124. package/src/components/TabbedModal.css +14 -0
  125. package/src/components/TabbedModal.js +165 -0
  126. package/src/components/TabsMenu.css +0 -0
  127. package/src/components/TabsMenu.js +35 -0
  128. package/src/components/TagsList.css +0 -0
  129. package/src/components/TagsList.js +43 -0
  130. package/src/components/Thumbnail.css +0 -0
  131. package/src/components/Thumbnail.js +47 -0
  132. package/src/components/Toaster.css +9 -0
  133. package/src/components/Toaster.js +73 -0
  134. package/src/components/VideoFrameSelector.css +3 -0
  135. package/src/components/VideoFrameSelector.js +148 -0
  136. package/src/components/VideoPlayer.css +3 -0
  137. package/src/components/VideoPlayer.js +55 -0
  138. package/src/components/VideoPlayerButton.css +17 -0
  139. package/src/components/VideoPlayerButton.js +17 -0
  140. package/src/components/ViewXML.css +0 -0
  141. package/src/components/ViewXML.js +72 -0
  142. package/src/i18n/en.json +204 -0
  143. package/src/i18n/i18n.js +24 -0
  144. package/src/index.js +76 -0
  145. package/types/components/AccordionDataList.js.flow +224 -0
  146. package/types/components/AccordionList.js.flow +596 -0
  147. package/types/components/AccordionSelector.js.flow +359 -0
  148. package/types/components/ArrowButtons.js.flow +38 -0
  149. package/types/components/AssociatedDropdown.js.flow +338 -0
  150. package/types/components/BooleanIcon.js.flow +33 -0
  151. package/types/components/CancelButton.js.flow +25 -0
  152. package/types/components/ColorButton.js.flow +34 -0
  153. package/types/components/ColorPickerModal.js.flow +77 -0
  154. package/types/components/ColumnResize.js.flow +20 -0
  155. package/types/components/DataList.js.flow +531 -0
  156. package/types/components/DataTable.js.flow +596 -0
  157. package/types/components/DataTableColumnSelector.js.flow +146 -0
  158. package/types/components/DataView.js.flow +125 -0
  159. package/types/components/DateInput.js.flow +58 -0
  160. package/types/components/DatePicker.js.flow +81 -0
  161. package/types/components/DescriptorField.js.flow +42 -0
  162. package/types/components/DownloadButton.js.flow +23 -0
  163. package/types/components/Draggable.js.flow +94 -0
  164. package/types/components/DropdownButton.js.flow +65 -0
  165. package/types/components/DropdownMenu.js.flow +68 -0
  166. package/types/components/EditModal.js.flow +99 -0
  167. package/types/components/EditPage.js.flow +249 -0
  168. package/types/components/EmbeddedList.js.flow +278 -0
  169. package/types/components/FileInputButton.js.flow +54 -0
  170. package/types/components/FileUpload.js.flow +188 -0
  171. package/types/components/FileUploadModal.js.flow +408 -0
  172. package/types/components/FuzzyDate.js.flow +575 -0
  173. package/types/components/GoogleMap.js.flow +105 -0
  174. package/types/components/GooglePlacesSearch.js.flow +43 -0
  175. package/types/components/HorizontalCards.js.flow +226 -0
  176. package/types/components/ItemCollection.js.flow +159 -0
  177. package/types/components/ItemList.js.flow +126 -0
  178. package/types/components/Items.js.flow +365 -0
  179. package/types/components/ItemsToggle.js.flow +168 -0
  180. package/types/components/KeyboardField.js.flow +147 -0
  181. package/types/components/LazyDocument.js.flow +113 -0
  182. package/types/components/LazyImage.js.flow +119 -0
  183. package/types/components/LazyVideo.js.flow +131 -0
  184. package/types/components/LinkButton.js.flow +23 -0
  185. package/types/components/LinkLabel.js.flow +29 -0
  186. package/types/components/List.js.flow +761 -0
  187. package/types/components/ListFilters.js.flow +408 -0
  188. package/types/components/ListLoader.js.flow +32 -0
  189. package/types/components/ListTable.js.flow +86 -0
  190. package/types/components/LoginModal.js.flow +102 -0
  191. package/types/components/MasonryGrid.js.flow +202 -0
  192. package/types/components/MediaGallery.js.flow +148 -0
  193. package/types/components/MediaGrid.js.flow +74 -0
  194. package/types/components/MediaList.js.flow +98 -0
  195. package/types/components/MenuBar.js.flow +77 -0
  196. package/types/components/MenuSidebar.js.flow +72 -0
  197. package/types/components/ModalDropdown.js.flow +84 -0
  198. package/types/components/NestedAccordion.js.flow +276 -0
  199. package/types/components/PhotoViewer.js.flow +36 -0
  200. package/types/components/PlayButton.js.flow +37 -0
  201. package/types/components/RemoteDropdown.js.flow +368 -0
  202. package/types/components/SaveButton.js.flow +31 -0
  203. package/types/components/Section.js.flow +41 -0
  204. package/types/components/Selectize.js.flow +297 -0
  205. package/types/components/SelectizeHeader.js.flow +40 -0
  206. package/types/components/TabbedModal.js.flow +165 -0
  207. package/types/components/TabsMenu.js.flow +35 -0
  208. package/types/components/TagsList.js.flow +43 -0
  209. package/types/components/Thumbnail.js.flow +47 -0
  210. package/types/components/Toaster.js.flow +73 -0
  211. package/types/components/VideoFrameSelector.js.flow +148 -0
  212. package/types/components/VideoPlayer.js.flow +55 -0
  213. package/types/components/VideoPlayerButton.js.flow +17 -0
  214. package/types/components/ViewXML.js.flow +72 -0
  215. package/types/hooks/Imageable.js.flow +54 -0
  216. package/types/i18n/i18n.js.flow +24 -0
  217. package/types/index.js.flow +78 -0
  218. package/webpack.config.js +3 -0
@@ -0,0 +1,531 @@
1
+ // @flow
2
+
3
+ import { Object as ObjectUtils, Timer } from '@performant-software/shared-components';
4
+ import React, { Component, type ComponentType } from 'react';
5
+ import _ from 'underscore';
6
+ import { Input, Message } from 'semantic-ui-react';
7
+ import i18n from '../i18n/i18n';
8
+ import Toaster from './Toaster';
9
+
10
+ type Props = {
11
+ collectionName: string,
12
+ defaultPerPage?: number,
13
+ defaultSearch?: string,
14
+ defaultSort?: string,
15
+ defaultSortDirection?: string,
16
+ filters?: {
17
+ component: ComponentType<any>,
18
+ defaults?: any,
19
+ props?: any,
20
+ onChange?: (filter: any) => Promise<any>
21
+ },
22
+ onDelete: (item: any) => Promise<any>,
23
+ onDeleteAll?: () => Promise<any>,
24
+ onLoad: (params: any) => Promise<any>,
25
+ onSave: (item: any) => Promise<any>,
26
+ perPageOptions?: Array<number>,
27
+ polling?: number,
28
+ resolveErrors?: (error: any) => Array<string>,
29
+ saved?: boolean,
30
+ searchable: boolean,
31
+ session?: {
32
+ key: string,
33
+ storage: typeof sessionStorage
34
+ }
35
+ };
36
+
37
+ type State = {
38
+ count: number,
39
+ error: ?any,
40
+ filters: any,
41
+ items: Array<any>,
42
+ loading: boolean,
43
+ page: number,
44
+ pages: number,
45
+ perPage: number,
46
+ saved: boolean,
47
+ search: ?string,
48
+ sortColumn: ?string,
49
+ sortDirection: ?string
50
+ };
51
+
52
+ const SESSION_KEY = 'DataList';
53
+ const SESSION_DEFAULT = '{}';
54
+
55
+ const SORT_ASCENDING = 'ascending';
56
+ const SORT_DESCENDING = 'descending';
57
+
58
+ /**
59
+ * Returns a function to wrap the passed component as a DataList. The DataList component is intended to be used to load
60
+ * records from an API and display them using the wrapped component. This HOC will handle calling the API, pagination,
61
+ * storing search, filters, and sorting.
62
+ *
63
+ * @param WrappedComponent
64
+ */
65
+ const useDataList = (WrappedComponent: ComponentType<any>) => (
66
+ class extends Component<Props, State> {
67
+ // Default props
68
+ static defaultProps = {
69
+ filters: {},
70
+ searchable: true
71
+ };
72
+
73
+ // Polling
74
+ pollingInterval: any;
75
+
76
+ /**
77
+ * Constructs a new DataList component.
78
+ *
79
+ * @param props
80
+ */
81
+ constructor(props: Props) {
82
+ super(props);
83
+
84
+ this.state = this.initializeState(props);
85
+ }
86
+
87
+ /**
88
+ * Sets up the polling interval.
89
+ */
90
+ componentDidMount() {
91
+ if (this.props.polling) {
92
+ this.pollingInterval = setInterval(this.fetchData.bind(this), this.props.polling);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Sets the saved prop on the state (if changed) and fetches the data. This can provide as a way to manually toggle
98
+ * a save event outside of the DataList context.
99
+ *
100
+ * @param prevProps
101
+ */
102
+ componentDidUpdate(prevProps: Props) {
103
+ if (prevProps.saved !== this.props.saved && this.props.saved) {
104
+ this.setState({ saved: this.props.saved }, this.fetchData.bind(this));
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Tears down the polling interval.
110
+ */
111
+ componentWillUnmount() {
112
+ if (this.pollingInterval) {
113
+ clearInterval(this.pollingInterval);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Resets the page number and reloads the data.
119
+ *
120
+ * @returns {void|any|Promise<State>}
121
+ */
122
+ afterDelete() {
123
+ if (this.state.items.length === 1) {
124
+ return this.setState((state) => ({
125
+ page: (state.page - 1) > 1 ? state.page - 1 : 1
126
+ }), this.fetchData.bind(this));
127
+ }
128
+
129
+ return this.fetchData();
130
+ }
131
+
132
+ /**
133
+ * Resets the page number and reloads the data.
134
+ */
135
+ afterDeleteAll() {
136
+ this.setState({ page: 1 }, this.fetchData.bind(this));
137
+ }
138
+
139
+ /**
140
+ * Calls the onLoad prop to populate the array of items in the state.
141
+ */
142
+ fetchData() {
143
+ // Store the session information before fetching the data.
144
+ this.setSession();
145
+
146
+ // Set the loading indicator and fetch the data.
147
+ this.setState({ loading: true }, () => {
148
+ const {
149
+ page,
150
+ perPage,
151
+ search,
152
+ sortColumn,
153
+ sortDirection
154
+ } = this.state;
155
+
156
+ const params = {
157
+ ...this.state.filters,
158
+ page,
159
+ search,
160
+ per_page: perPage,
161
+ sort_by: sortColumn,
162
+ sort_direction: sortDirection
163
+ };
164
+
165
+ this.props
166
+ .onLoad(params)
167
+ .then(({ data }) => {
168
+ const items = data[this.props.collectionName];
169
+ const { pages, count } = data.list;
170
+
171
+ this.setState({
172
+ count,
173
+ items,
174
+ page,
175
+ pages,
176
+ loading: false
177
+ });
178
+ });
179
+ });
180
+ }
181
+
182
+ /**
183
+ * Returns the session storage key for the current list.
184
+ *
185
+ * @returns {string|null}
186
+ */
187
+ getSessionKey() {
188
+ if (!this.props.session) {
189
+ return null;
190
+ }
191
+
192
+ return `${SESSION_KEY}.${this.props.session.key}`;
193
+ }
194
+
195
+ /**
196
+ * Initializes the state based on the passed props.
197
+ *
198
+ * @param props
199
+
200
+ * @returns {{search: string, sortColumn: string, sortDirection: string, pages: number, perPage: (number|*),
201
+ * saved: boolean, count: number, filters: (*|{}), page: number, error: null, loading: boolean, items: *[]}}
202
+ */
203
+ initializeState(props: Props) {
204
+ const session = this.restoreSession();
205
+
206
+ const filters = session.filters || (props.filters && props.filters.defaults) || {};
207
+ const page = session.page || 1;
208
+ const perPage = session.perPage || props.defaultPerPage || _.first(props.perPageOptions);
209
+ const search = session.search || props.defaultSearch || null;
210
+ const sortColumn = session.sortColumn || props.defaultSort || null;
211
+ const sortDirection = session.sortDirection || props.defaultSortDirection || null;
212
+
213
+ return {
214
+ count: 0,
215
+ error: null,
216
+ filters,
217
+ items: [],
218
+ loading: false,
219
+ page,
220
+ pages: 1,
221
+ perPage,
222
+ saved: props.saved || false,
223
+ search,
224
+ sortColumn,
225
+ sortDirection
226
+ };
227
+ }
228
+
229
+ /**
230
+ * Returns true if any filters have been set.
231
+ *
232
+ * @returns {boolean}
233
+ */
234
+ isFilterActive() {
235
+ let isActive = false;
236
+
237
+ _.each(_.values(this.state.filters), (value) => {
238
+ if (!ObjectUtils.isEmpty(value)) {
239
+ isActive = true;
240
+ }
241
+ });
242
+
243
+ return isActive;
244
+ }
245
+
246
+ /**
247
+ * Calls the onDelete prop.
248
+ *
249
+ * @param selectedItem
250
+ *
251
+ * @returns {Q.Promise<any> | Promise<R> | Promise<any> | void | *}
252
+ */
253
+ onDelete(selectedItem: any) {
254
+ return this.props
255
+ .onDelete(selectedItem)
256
+ .then(this.afterDelete.bind(this))
257
+ .catch(this.onError.bind(this));
258
+ }
259
+
260
+ /**
261
+ * Calls the onDeleteAll prop.
262
+ *
263
+ * @returns {Q.Promise<any> | Promise<R> | Promise<any> | void | *}
264
+ */
265
+ onDeleteAll() {
266
+ if (!this.props.onDeleteAll) {
267
+ return Promise.resolve();
268
+ }
269
+
270
+ return this.props
271
+ .onDeleteAll()
272
+ .then(this.afterDeleteAll.bind(this));
273
+ }
274
+
275
+ /**
276
+ * Sets the error on the state if the component is configured to display errors.
277
+ *
278
+ * @param error
279
+ *
280
+ * @returns {*|void|Promise<State>}
281
+ */
282
+ onError(error: any) {
283
+ return this.props.resolveErrors && this.setState({ error });
284
+ }
285
+
286
+ /**
287
+ * Updates the state with the passed filters.
288
+ *
289
+ * @param filters
290
+ *
291
+ * @returns {Promise<R>}
292
+ */
293
+ onFilterChange(filters: any) {
294
+ return new Promise<void>((resolve) => {
295
+ // Call the custom onChange prop
296
+ if (this.props.filters && this.props.filters.onChange) {
297
+ this.props.filters.onChange(filters);
298
+ }
299
+
300
+ // Set the filters and re-fetch the data
301
+ this.setState({ filters, page: 1 }, () => {
302
+ this.fetchData();
303
+ resolve();
304
+ });
305
+ });
306
+ }
307
+
308
+ /**
309
+ * Sets the new active page and reloads the data.
310
+ *
311
+ * @param e
312
+ * @param activePage
313
+ */
314
+ onPageChange(e: Event, { activePage }: { activePage: number }) {
315
+ this.setState({ page: activePage }, this.fetchData.bind(this));
316
+ }
317
+
318
+ /**
319
+ * Sets the perPage value and reloads the data.
320
+ *
321
+ * @param e
322
+ * @param value
323
+ */
324
+ onPerPageChange(e: Event, { value }: { value: number }) {
325
+ this.setState({ perPage: value }, this.fetchData.bind(this));
326
+ }
327
+
328
+ /**
329
+ * Calls the onSave prop and reloads the data.
330
+ *
331
+ * @param item
332
+ *
333
+ * @returns {Q.Promise<any> | Promise<R> | Promise<any> | void | *}
334
+ */
335
+ onSave(item: any) {
336
+ return Promise.resolve(this.props.onSave(item))
337
+ .then(() => this.setState({ saved: true }, this.fetchData.bind(this)));
338
+ }
339
+
340
+ /**
341
+ * Resets the page and reloads the data.
342
+ */
343
+ onSearch() {
344
+ this.setState({ page: 1 }, this.fetchData.bind(this));
345
+ }
346
+
347
+ /**
348
+ * Updates the search value on the state.
349
+ *
350
+ * @param e
351
+ * @param value
352
+ */
353
+ onSearchChange(e: Event, { value }: { value: any }) {
354
+ this.setState({ search: value });
355
+ }
356
+
357
+ /**
358
+ * Updates the sortColumn and sortDirection props on the state.
359
+ *
360
+ * @param sortColumn
361
+ * @param direction
362
+ * @param page
363
+ */
364
+ onSort(sortColumn: string, direction?: string, page?: number = 1) {
365
+ let sortDirection = direction;
366
+
367
+ if (!sortDirection) {
368
+ sortDirection = this.state.sortColumn === sortColumn && this.state.sortDirection === SORT_ASCENDING
369
+ ? SORT_DESCENDING : SORT_ASCENDING;
370
+ }
371
+
372
+ this.setState({ sortColumn, sortDirection, page }, this.fetchData.bind(this));
373
+ }
374
+
375
+ /**
376
+ * When no columns are sortable, load data as is
377
+ *
378
+ */
379
+ onInit(page?: number = 1) {
380
+ this.setState({ sortColumn: '', sortDirection: '', page }, this.fetchData.bind(this));
381
+ }
382
+
383
+ /**
384
+ * Renders the DataList component.
385
+ *
386
+ * @returns {*}
387
+ */
388
+ render() {
389
+ const { filters = {} } = this.props;
390
+ const { component, defaults, props } = filters;
391
+
392
+ return (
393
+ <>
394
+ <WrappedComponent
395
+ {...this.props}
396
+ count={this.state.count}
397
+ filters={{
398
+ active: this.isFilterActive(),
399
+ component,
400
+ onChange: this.onFilterChange.bind(this),
401
+ props: {
402
+ ...props,
403
+ defaults,
404
+ item: this.state.filters
405
+ }
406
+ }}
407
+ items={this.state.items}
408
+ loading={this.state.loading}
409
+ page={this.state.page}
410
+ pages={this.state.pages}
411
+ perPage={this.state.perPage}
412
+ onDelete={this.onDelete.bind(this)}
413
+ onDeleteAll={this.onDeleteAll.bind(this)}
414
+ onPageChange={this.onPageChange.bind(this)}
415
+ onPerPageChange={this.onPerPageChange.bind(this)}
416
+ onSave={this.onSave.bind(this)}
417
+ onSort={this.onSort.bind(this)}
418
+ onInit={this.onInit.bind(this)}
419
+ renderSearch={this.renderSearch.bind(this)}
420
+ sortColumn={this.state.sortColumn}
421
+ sortDirection={this.state.sortDirection}
422
+ />
423
+ { this.state.saved && (
424
+ <Toaster
425
+ onDismiss={() => this.setState({ saved: false })}
426
+ type={Toaster.MessageTypes.positive}
427
+ >
428
+ <Message.Header
429
+ content={i18n.t('Common.messages.save.header')}
430
+ />
431
+ <Message.Content
432
+ content={i18n.t('Common.messages.save.content')}
433
+ />
434
+ </Toaster>
435
+ )}
436
+ { this.state.error && (
437
+ <Toaster
438
+ onDismiss={() => this.setState({ error: false })}
439
+ timeout={0}
440
+ type={Toaster.MessageTypes.negative}
441
+ >
442
+ <Message.Header
443
+ content={i18n.t('Common.messages.error.header')}
444
+ />
445
+ <Message.List
446
+ items={this.props.resolveErrors && this.props.resolveErrors(this.state.error)}
447
+ />
448
+ </Toaster>
449
+ )}
450
+ </>
451
+ );
452
+ }
453
+
454
+ /**
455
+ * Renders the search input component.
456
+ *
457
+ * @returns {null|*}
458
+ */
459
+ renderSearch() {
460
+ if (!this.props.searchable) {
461
+ return null;
462
+ }
463
+
464
+ return (
465
+ <Input
466
+ type='text'
467
+ icon='search'
468
+ input={{
469
+ 'aria-label': 'search'
470
+ }}
471
+ loading={this.state.loading}
472
+ onKeyDown={Timer.clearSearchTimer.bind(this)}
473
+ onKeyUp={Timer.setSearchTimer.bind(this, this.onSearch.bind(this))}
474
+ onChange={this.onSearchChange.bind(this)}
475
+ size='small'
476
+ value={this.state.search}
477
+ />
478
+ );
479
+ }
480
+
481
+ /**
482
+ * Restores the DataList session object.
483
+ */
484
+ restoreSession() {
485
+ const key = this.getSessionKey();
486
+
487
+ if (!key) {
488
+ return {};
489
+ }
490
+
491
+ const session = sessionStorage.getItem(key) || SESSION_DEFAULT;
492
+ return JSON.parse(session);
493
+ }
494
+
495
+ /**
496
+ * Sets the DataList session object.
497
+ */
498
+ setSession() {
499
+ const key = this.getSessionKey();
500
+
501
+ if (!key) {
502
+ return;
503
+ }
504
+
505
+ const {
506
+ filters,
507
+ page,
508
+ perPage,
509
+ search,
510
+ sortColumn,
511
+ sortDirection
512
+ } = this.state;
513
+
514
+ sessionStorage.setItem(key, JSON.stringify({
515
+ filters,
516
+ page,
517
+ perPage,
518
+ search,
519
+ sortColumn,
520
+ sortDirection
521
+ }));
522
+ }
523
+ }
524
+ );
525
+
526
+ export default useDataList;
527
+
528
+ export {
529
+ SORT_ASCENDING,
530
+ SORT_DESCENDING
531
+ };
@@ -0,0 +1,43 @@
1
+ .data-table .ui.table .actions-cell {
2
+ white-space: nowrap;
3
+ width: 1px;
4
+ }
5
+
6
+ .data-table .empty-button {
7
+ display: inline;
8
+ margin-left: 5px;
9
+ margin-right: 4px;
10
+ }
11
+
12
+ .data-table .empty-container {
13
+ font-size: 1.1em;
14
+ padding: 15px;
15
+ }
16
+
17
+ .data-table .expandable {
18
+ cursor: pointer;
19
+ }
20
+
21
+ .data-table .expanded-panel {
22
+ display: table-row;
23
+ }
24
+
25
+ .data-table .footer {
26
+ margin-top: 10px;
27
+ }
28
+
29
+ .data-table .header {
30
+ margin-bottom: 10px;
31
+ }
32
+
33
+ .data-table .hidden {
34
+ display: none;
35
+ }
36
+
37
+ .data-table.ui.celled.table tr th {
38
+ position: relative;
39
+ }
40
+
41
+ .data-table.ui.celled.table tr td.actions-cell {
42
+ white-space: nowrap;
43
+ }