-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathGenericEmikatClient.js
132 lines (111 loc) · 4.21 KB
/
GenericEmikatClient.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
* ***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
* ***************************************************
*/
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import log from 'loglevel';
import { EMIKATHelpers } from 'csis-helpers-js';
import GenericEmikatTable from './GenericEmikatTable.js'
/**
* A Generic EMIKAT Client that understands the [EMIKAT API](https://service.emikat.at/EmiKat/swagger/index.html)
* and accepts as render prop a JSX Component, e.g. <GenericEmikatTable>
*
* @param {GenericEmikatClientProps} props
* @version 0.1.0
* @author [Pascal Dihé](https://github.com/p-a-s-c-a-l)
* @see [EMIKAT](https://github.com/clarity-h2020/emikat/) GitHub Project and [EMIKAT API](https://service.emikat.at/EmiKat/swagger/index.html)
*
* @component
* @visibleName Generic EMIKAT Client
* @see GenericEmikatTable
*/
const GenericEmikatClient = ({ emikatUrl, emikatCredentials, render: EmikatVisualisationComponent, props}) => {
/**
* 1) Either we pass just `props` and access `props.render` or
* we need to add `render` to the **destructuring assignment** of the argument `props`.
* 2) We rename `render` to `EmikatVisualisationComponent` using ES6 destructuring assignment syntax, because **components** must be capitalized in React.
* 3) Instead of using a function to render dynamic children ("render props"), we use standard JSX composition in props! See https://americanexpress.io/faccs-are-an-antipattern/
*/
// no need to lift up state because it's only used here
// TODO: Consider using a reducer hook as explained here: https://www.robinwieruch.de/react-hooks-fetch-data/
const [emikatData, setEmikatData] = useState({ data: { rows: [], columnnames: [] }, isFetching: false });
/**
* Create Hook to load data from remote API when one of props emikatUrl or emikatCredentials changes
*
*/
useEffect(() => {
let ignore = false;
const fetchData = async () => {
try {
// functional update form, otherwise we would have to declare emikatData as part of the array
// and the effect would be used when *state* changes (not what we want)
setEmikatData((state) => ({ ...state, isFetching: true }));
const response = await EMIKATHelpers.fetchData(emikatUrl, emikatCredentials);
if (!ignore) {
//console.log(JSON.stringify(response));
log.debug(`emikatUrl: ${emikatUrl} | emikatCredentials: ${emikatCredentials}`);
setEmikatData((state) => ({ ...state, data: response.data, isFetching: false }));
} else {
log.warn(`props emikatUrl ${emikatUrl} or emikatCredentials ${emikatCredentials} changed during async call, ignoring`);
}
} catch (error) {
log.error('error caught in fetchData', error);
//setEmikatData((state) => ({...state, data: { rows: [], columnnames: [] }, isFetching: false }));
// hacketyhack ....
setEmikatData(() => {
throw error;
});
}
};
fetchData();
/**
* clean up function which runs when a component unmounts
*/
return function cleanup() {
log.debug('cleanup data fetching');
ignore = true;
};
}, [emikatUrl, emikatCredentials]);
// this is how we pass props to the `render` JSX Component:
return (<EmikatVisualisationComponent data={emikatData.data} isFetching={false} {...props} />);
}
/**
* GenericEmikatClient Prop Types
*
* @typedef {Object} GenericEmikatTableProps
*/
GenericEmikatClient.propTypes = {
/**
* URL of the EMIKAT Endpoint
*/
emikatUrl: PropTypes.string.isRequired,
/**
* The Basic Auth credentials
*/
emikatCredentials: PropTypes.string.isRequired,
/**
* The actual visualisation component to be rendered
*/
render: PropTypes.elementType,
/**
* child props ....
*/
props: PropTypes.object
};
/**
* GenericEmikatClient Default Props
* @typedef {Object} GenericEmikatClientProps
*/
GenericEmikatClient.defaultProps = {
emikatUrl: 'https://service.emikat.at/EmiKatTst/api/',
emikatCredentials: null,
render: GenericEmikatTable,
props: null
};
export default GenericEmikatClient