@performant-software/semantic-components 1.0.24-beta.2 → 1.0.25-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@performant-software/semantic-components",
3
- "version": "1.0.24-beta.2",
3
+ "version": "1.0.25-beta.0",
4
4
  "description": "A package of shared components based on the Semantic UI Framework.",
5
5
  "license": "MIT",
6
6
  "main": "./build/index.js",
@@ -12,7 +12,7 @@
12
12
  "build": "webpack --mode production && flow-copy-source -v src types"
13
13
  },
14
14
  "dependencies": {
15
- "@performant-software/shared-components": "^1.0.24-beta.2",
15
+ "@performant-software/shared-components": "^1.0.25-beta.0",
16
16
  "@react-google-maps/api": "^2.8.1",
17
17
  "axios": "^0.26.1",
18
18
  "i18next": "^19.4.4",
@@ -633,6 +633,7 @@ DataTable.defaultProps = {
633
633
  buttons: [],
634
634
  count: 0,
635
635
  className: '',
636
+ csvExportButton: undefined,
636
637
  expandableRows: false,
637
638
  expandPanel: undefined,
638
639
  filters: undefined,
@@ -271,7 +271,3 @@ export {
271
271
  SORT_ASCENDING,
272
272
  SORT_DESCENDING
273
273
  };
274
-
275
- export type {
276
- Props
277
- };
@@ -32,7 +32,7 @@ const FacetSlider = forwardRef(({ useRangeSlider, ...props }: Props, ref: HTMLEl
32
32
  *
33
33
  * @type {unknown}
34
34
  */
35
- const visible = useMemo(() => range.min === 0 && range.max === 0, [range.min, range.max]);
35
+ const visible = useMemo(() => range.min !== 0 && range.max !== 0, [range.min, range.max]);
36
36
 
37
37
  /**
38
38
  * Resets the value and valueView when the current refinement is cleared.
@@ -48,11 +48,6 @@ type Props = {
48
48
  */
49
49
  onClose: () => void,
50
50
 
51
- /**
52
- * Callback fired when the upload has completed.
53
- */
54
- onComplete: () => void,
55
-
56
51
  /**
57
52
  * Callback fired when the save button is clicked. See <code>strategy</code> prop.
58
53
  */
@@ -156,10 +151,6 @@ const FileUploadModal: ComponentType<any> = (props: Props) => {
156
151
  const onComplete = useCallback(() => {
157
152
  setUploading(false);
158
153
 
159
- if (props.onComplete) {
160
- props.onComplete();
161
- }
162
-
163
154
  if (props.closeOnComplete) {
164
155
  props.onClose();
165
156
  }
@@ -79,6 +79,16 @@ type Props = {
79
79
  */
80
80
  className?: string,
81
81
 
82
+ /**
83
+ * If provided, a CSV export button will be rendered in the list header.
84
+ */
85
+ csvExportButton?: {
86
+ basic: boolean,
87
+ color: string,
88
+ location: string,
89
+ onClick?: () => void
90
+ },
91
+
82
92
  /**
83
93
  * If provided, a "delete all" button will be rendered in the list header.
84
94
  */
@@ -208,6 +218,7 @@ type State = {
208
218
  };
209
219
 
210
220
  const BUTTON_KEY_ADD = 'add';
221
+ const BUTTON_KEY_CSV_EXPORT = 'csv-export';
211
222
  const BUTTON_KEY_DELETE_ALL = 'delete-all';
212
223
 
213
224
  /**
@@ -229,6 +240,7 @@ const useList = (WrappedComponent: ComponentType<any>) => (
229
240
  },
230
241
  buttons: [],
231
242
  className: '',
243
+ csvExportButton: undefined,
232
244
  filters: undefined,
233
245
  modal: undefined,
234
246
  page: 1,
@@ -269,6 +281,7 @@ const useList = (WrappedComponent: ComponentType<any>) => (
269
281
 
270
282
  const {
271
283
  addButton = {},
284
+ csvExportButton = {},
272
285
  deleteButton = {},
273
286
  modal,
274
287
  selectable
@@ -288,6 +301,13 @@ const useList = (WrappedComponent: ComponentType<any>) => (
288
301
  });
289
302
  }
290
303
 
304
+ // Add the CSV export button to the list if the csvExport prop is passed
305
+ if (csvExportButton.location === location && !selectable) {
306
+ buttons.push({
307
+ render: this.renderCsvExportButton.bind(this)
308
+ });
309
+ }
310
+
291
311
  // Resolve the array of other buttons
292
312
  buttons.push(..._.filter(this.props.buttons, (button) => {
293
313
  let include = false;
@@ -331,6 +351,43 @@ const useList = (WrappedComponent: ComponentType<any>) => (
331
351
  this.setState({ selectedItem: copy, modalEdit: true });
332
352
  }
333
353
 
354
+ /**
355
+ * Generates and downloads a CSV file containing all
356
+ * the data in the table.
357
+ *
358
+ * @param items
359
+ */
360
+ onCsvExportButton() {
361
+ const visibleColumns = _.filter(this.props.columns, (col) => !col.hidden);
362
+
363
+ let csv = `${_.map(visibleColumns, (col) => `"${col.label}"`).join(',')}\n`;
364
+
365
+ _.each(this.props.items, (item) => {
366
+ csv = csv.concat(`${visibleColumns.map((col) => {
367
+ if (col.resolve) {
368
+ return `"${col.resolve(item)}"`;
369
+ }
370
+
371
+ if (item[col.name]) {
372
+ return `"${item[col.name]}"`;
373
+ }
374
+
375
+ return '';
376
+ }).join(',')}\n`);
377
+ });
378
+
379
+ const element = document.createElement('a');
380
+ element.setAttribute('href', `data:text/plain;charset=utf-8,${encodeURIComponent(csv)}`);
381
+ element.setAttribute('download', `${this.props.collectionName || 'table'}.csv`);
382
+
383
+ element.style.display = 'none';
384
+ document.body.appendChild(element);
385
+
386
+ element.click();
387
+
388
+ document.body.removeChild(element);
389
+ }
390
+
334
391
  /**
335
392
  * Deletes the currently selected item and clears the state.
336
393
  *
@@ -533,6 +590,29 @@ const useList = (WrappedComponent: ComponentType<any>) => (
533
590
  );
534
591
  }
535
592
 
593
+ /**
594
+ * Renders the CSV export button.
595
+ *
596
+ * @returns {null|*}
597
+ */
598
+ renderCsvExportButton() {
599
+ if (!this.props.csvExportButton) {
600
+ return null;
601
+ }
602
+
603
+ return (
604
+ <Button
605
+ basic={this.props.csvExportButton.basic}
606
+ color={this.props.csvExportButton.color}
607
+ key={BUTTON_KEY_CSV_EXPORT}
608
+ onClick={this.onCsvExportButton.bind(this)}
609
+ >
610
+ <Icon name='download' />
611
+ { i18n.t('List.buttons.csvExport') }
612
+ </Button>
613
+ );
614
+ }
615
+
536
616
  /**
537
617
  * Renders the delete all button.
538
618
  *
@@ -131,7 +131,3 @@ ListTable.defaultProps = {
131
131
  };
132
132
 
133
133
  export default ListTable;
134
-
135
- export type {
136
- Props
137
- };
package/src/i18n/en.json CHANGED
@@ -233,6 +233,7 @@
233
233
  "List": {
234
234
  "buttons": {
235
235
  "add": "Add",
236
+ "csvExport": "CSV Export",
236
237
  "deleteAll": "Delete all"
237
238
  },
238
239
  "deleteAllContent": "Are you sure you want to remove all records? This action cannot be undone.",
package/src/index.js CHANGED
@@ -109,10 +109,8 @@ export { default as BatchEdit } from './hooks/BatchEdit';
109
109
 
110
110
  // Types
111
111
  export type { EditPageProps } from './components/EditPage';
112
- export type { Props as EmbeddedListProps } from './components/EmbeddedList';
113
112
  export type { FileUploadProps } from './components/FileUploadModal';
114
113
  export type { Props as ListProps } from './components/List';
115
- export type { Props as ListTableProps } from './components/ListTable';
116
114
  export type { BatchEditProps } from './hooks/BatchEdit';
117
115
 
118
116
  // Constants
@@ -633,6 +633,7 @@ DataTable.defaultProps = {
633
633
  buttons: [],
634
634
  count: 0,
635
635
  className: '',
636
+ csvExportButton: undefined,
636
637
  expandableRows: false,
637
638
  expandPanel: undefined,
638
639
  filters: undefined,
@@ -271,7 +271,3 @@ export {
271
271
  SORT_ASCENDING,
272
272
  SORT_DESCENDING
273
273
  };
274
-
275
- export type {
276
- Props
277
- };
@@ -32,7 +32,7 @@ const FacetSlider = forwardRef(({ useRangeSlider, ...props }: Props, ref: HTMLEl
32
32
  *
33
33
  * @type {unknown}
34
34
  */
35
- const visible = useMemo(() => range.min === 0 && range.max === 0, [range.min, range.max]);
35
+ const visible = useMemo(() => range.min !== 0 && range.max !== 0, [range.min, range.max]);
36
36
 
37
37
  /**
38
38
  * Resets the value and valueView when the current refinement is cleared.
@@ -48,11 +48,6 @@ type Props = {
48
48
  */
49
49
  onClose: () => void,
50
50
 
51
- /**
52
- * Callback fired when the upload has completed.
53
- */
54
- onComplete: () => void,
55
-
56
51
  /**
57
52
  * Callback fired when the save button is clicked. See <code>strategy</code> prop.
58
53
  */
@@ -156,10 +151,6 @@ const FileUploadModal: ComponentType<any> = (props: Props) => {
156
151
  const onComplete = useCallback(() => {
157
152
  setUploading(false);
158
153
 
159
- if (props.onComplete) {
160
- props.onComplete();
161
- }
162
-
163
154
  if (props.closeOnComplete) {
164
155
  props.onClose();
165
156
  }
@@ -79,6 +79,16 @@ type Props = {
79
79
  */
80
80
  className?: string,
81
81
 
82
+ /**
83
+ * If provided, a CSV export button will be rendered in the list header.
84
+ */
85
+ csvExportButton?: {
86
+ basic: boolean,
87
+ color: string,
88
+ location: string,
89
+ onClick?: () => void
90
+ },
91
+
82
92
  /**
83
93
  * If provided, a "delete all" button will be rendered in the list header.
84
94
  */
@@ -208,6 +218,7 @@ type State = {
208
218
  };
209
219
 
210
220
  const BUTTON_KEY_ADD = 'add';
221
+ const BUTTON_KEY_CSV_EXPORT = 'csv-export';
211
222
  const BUTTON_KEY_DELETE_ALL = 'delete-all';
212
223
 
213
224
  /**
@@ -229,6 +240,7 @@ const useList = (WrappedComponent: ComponentType<any>) => (
229
240
  },
230
241
  buttons: [],
231
242
  className: '',
243
+ csvExportButton: undefined,
232
244
  filters: undefined,
233
245
  modal: undefined,
234
246
  page: 1,
@@ -269,6 +281,7 @@ const useList = (WrappedComponent: ComponentType<any>) => (
269
281
 
270
282
  const {
271
283
  addButton = {},
284
+ csvExportButton = {},
272
285
  deleteButton = {},
273
286
  modal,
274
287
  selectable
@@ -288,6 +301,13 @@ const useList = (WrappedComponent: ComponentType<any>) => (
288
301
  });
289
302
  }
290
303
 
304
+ // Add the CSV export button to the list if the csvExport prop is passed
305
+ if (csvExportButton.location === location && !selectable) {
306
+ buttons.push({
307
+ render: this.renderCsvExportButton.bind(this)
308
+ });
309
+ }
310
+
291
311
  // Resolve the array of other buttons
292
312
  buttons.push(..._.filter(this.props.buttons, (button) => {
293
313
  let include = false;
@@ -331,6 +351,43 @@ const useList = (WrappedComponent: ComponentType<any>) => (
331
351
  this.setState({ selectedItem: copy, modalEdit: true });
332
352
  }
333
353
 
354
+ /**
355
+ * Generates and downloads a CSV file containing all
356
+ * the data in the table.
357
+ *
358
+ * @param items
359
+ */
360
+ onCsvExportButton() {
361
+ const visibleColumns = _.filter(this.props.columns, (col) => !col.hidden);
362
+
363
+ let csv = `${_.map(visibleColumns, (col) => `"${col.label}"`).join(',')}\n`;
364
+
365
+ _.each(this.props.items, (item) => {
366
+ csv = csv.concat(`${visibleColumns.map((col) => {
367
+ if (col.resolve) {
368
+ return `"${col.resolve(item)}"`;
369
+ }
370
+
371
+ if (item[col.name]) {
372
+ return `"${item[col.name]}"`;
373
+ }
374
+
375
+ return '';
376
+ }).join(',')}\n`);
377
+ });
378
+
379
+ const element = document.createElement('a');
380
+ element.setAttribute('href', `data:text/plain;charset=utf-8,${encodeURIComponent(csv)}`);
381
+ element.setAttribute('download', `${this.props.collectionName || 'table'}.csv`);
382
+
383
+ element.style.display = 'none';
384
+ document.body.appendChild(element);
385
+
386
+ element.click();
387
+
388
+ document.body.removeChild(element);
389
+ }
390
+
334
391
  /**
335
392
  * Deletes the currently selected item and clears the state.
336
393
  *
@@ -533,6 +590,29 @@ const useList = (WrappedComponent: ComponentType<any>) => (
533
590
  );
534
591
  }
535
592
 
593
+ /**
594
+ * Renders the CSV export button.
595
+ *
596
+ * @returns {null|*}
597
+ */
598
+ renderCsvExportButton() {
599
+ if (!this.props.csvExportButton) {
600
+ return null;
601
+ }
602
+
603
+ return (
604
+ <Button
605
+ basic={this.props.csvExportButton.basic}
606
+ color={this.props.csvExportButton.color}
607
+ key={BUTTON_KEY_CSV_EXPORT}
608
+ onClick={this.onCsvExportButton.bind(this)}
609
+ >
610
+ <Icon name='download' />
611
+ { i18n.t('List.buttons.csvExport') }
612
+ </Button>
613
+ );
614
+ }
615
+
536
616
  /**
537
617
  * Renders the delete all button.
538
618
  *
@@ -131,7 +131,3 @@ ListTable.defaultProps = {
131
131
  };
132
132
 
133
133
  export default ListTable;
134
-
135
- export type {
136
- Props
137
- };
@@ -109,10 +109,8 @@ export { default as BatchEdit } from './hooks/BatchEdit';
109
109
 
110
110
  // Types
111
111
  export type { EditPageProps } from './components/EditPage';
112
- export type { Props as EmbeddedListProps } from './components/EmbeddedList';
113
112
  export type { FileUploadProps } from './components/FileUploadModal';
114
113
  export type { Props as ListProps } from './components/List';
115
- export type { Props as ListTableProps } from './components/ListTable';
116
114
  export type { BatchEditProps } from './hooks/BatchEdit';
117
115
 
118
116
  // Constants