-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
Copy pathWidgetMixin.js
150 lines (148 loc) · 4.78 KB
/
WidgetMixin.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* Mixin that all pre-built and custom widgets extend from.
* Manages loading state, error handling, data updates and user options
*/
import axios from 'axios';
import { Progress } from 'rsup-progress';
import ErrorHandler from '@/utils/ErrorHandler';
import { serviceEndpoints } from '@/utils/defaults';
const WidgetMixin = {
props: {
options: {
type: Object,
default: {},
},
},
data: () => ({
progress: new Progress({ color: 'var(--progress-bar)' }),
overrideProxyChoice: false,
overrideUpdateInterval: null,
disableLoader: false, // Prevent ever showing the loader
updater: null, // Stores interval
defaultTimeout: 50000,
}),
/* When component mounted, fetch initial data */
mounted() {
this.fetchData();
if (this.updateInterval) {
this.continuousUpdates();
this.disableLoader = true;
}
},
beforeDestroy() {
if (this.updater) {
clearInterval(this.updater);
}
},
computed: {
proxyReqEndpoint() {
const baseUrl = process.env.VUE_APP_DOMAIN || window.location.origin;
return `${baseUrl}${serviceEndpoints.corsProxy}`;
},
useProxy() {
return this.options.useProxy || this.overrideProxyChoice;
},
/* Returns either a number in ms to continuously update widget data. Or 0 for no updates */
updateInterval() {
const usersInterval = this.options.updateInterval;
if (usersInterval === null && this.overrideUpdateInterval) {
return this.overrideUpdateInterval * 1000;
}
if (!usersInterval) return 0;
// If set to `true`, then default to 30 seconds
if (typeof usersInterval === 'boolean') return 30 * 1000;
// If set to a number, and within valid range, return user choice
if (typeof usersInterval === 'number'
&& usersInterval >= 2
&& usersInterval <= 7200) {
return usersInterval * 1000;
}
return 0;
},
},
methods: {
/* Re-fetches external data, called by parent. Usually overridden by widget */
update() {
this.startLoading();
this.fetchData();
},
/* If continuous updates enabled, create interval */
continuousUpdates() {
this.updater = setInterval(() => { this.update(); }, this.updateInterval);
},
/* Called when an error occurs. Logs to handler, and passes to parent component */
error(msg, stackTrace, quite = false) {
ErrorHandler(msg, stackTrace);
if (!this.options.ignoreErrors && !quite) {
this.$emit('error', msg);
}
},
/* When a data request update starts, show loader */
startLoading() {
if (!this.disableLoader) {
this.$emit('loading', true);
this.progress.start();
}
},
/* When a data request finishes, hide loader */
finishLoading() {
this.$emit('loading', false);
setTimeout(() => { this.progress.end(); }, 500);
},
/* Overridden by child component. Will make network request, then end loader */
fetchData() {
this.finishLoading();
},
/* Used as v-tooltip, pass text content in, and will show on hover */
tooltip(content, html = false) {
return {
content, html, trigger: 'hover focus', delay: 250,
};
},
/* Makes data request, returns promise */
makeRequest(endpoint, options, protocol, body) {
// Request Options
const method = protocol || 'GET';
const url = this.useProxy ? this.proxyReqEndpoint : endpoint;
const data = JSON.stringify(body || {});
const CustomHeaders = options || null;
const headers = this.useProxy
? { 'Target-URL': endpoint, CustomHeaders: JSON.stringify(CustomHeaders) } : CustomHeaders;
const timeout = this.options.timeout || this.defaultTimeout;
const requestConfig = {
method, url, headers, data, timeout,
};
// Make request
return new Promise((resolve, reject) => {
axios.request(requestConfig)
.then((response) => {
if (response.data.success === false) {
this.error('Proxy returned error from target server', response.data.message);
}
resolve(response.data);
})
.catch((dataFetchError) => {
this.error('Unable to fetch data', dataFetchError);
reject(dataFetchError);
})
.finally(() => {
this.finishLoading();
});
});
},
/* Check if a value is an environment variable, return its value if so. */
parseAsEnvVar(str) {
if (typeof str !== 'string') return str;
if (str.includes('VUE_APP_')) {
const envVar = process.env[str];
if (!envVar) {
this.error(`Environment variable ${str} not found`);
} else {
return envVar;
}
}
return str;
},
},
};
export default WidgetMixin;