ソースを参照

feat(connection-stats): convert connection stats display to react

Move all logic related to displaying a table of connection stats to a React
Component. The actual parsing logic was modified as little as possible as the
focus is moving display to React.
j8
Leonard Kim 8年前
コミット
e0d641a787

+ 26
- 227
modules/UI/videolayout/ConnectionIndicator.js ファイルの表示

@@ -1,6 +1,13 @@
1 1
 /* global $, APP, interfaceConfig, JitsiMeetJS */
2 2
 /* jshint -W101 */
3 3
 
4
+/* eslint-disable no-unused-vars */
5
+import React from 'react';
6
+import ReactDOM from 'react-dom';
7
+
8
+import { ConnectionStatsTable } from '../../../react/features/connection-stats';
9
+/* eslint-enable no-unused-vars */
10
+
4 11
 import JitsiPopover from "../util/JitsiPopover";
5 12
 import UIUtil from "../util/UIUtil";
6 13
 
@@ -42,237 +49,31 @@ function ConnectionIndicator(videoContainer, videoId) {
42 49
     this.popover = null;
43 50
     this.id = videoId;
44 51
     this.create();
45
-}
46 52
 
47
-ConnectionIndicator.getIP = function(value) {
48
-    return value.substring(0, value.lastIndexOf(":"));
49
-};
50
-
51
-ConnectionIndicator.getPort = function(value) {
52
-    return value.substring(value.lastIndexOf(":") + 1, value.length);
53
-};
54
-
55
-ConnectionIndicator.getStringFromArray = function (array) {
56
-    var res = "";
57
-    for(var i = 0; i < array.length; i++) {
58
-        res += (i === 0? "" : ", ") + array[i];
59
-    }
60
-    return res;
61
-};
53
+    this.isLocalVideo
54
+        = this.videoContainer.videoSpanId === 'localVideoContainer';
55
+    this.showMore = this.showMore.bind(this);
56
+}
62 57
 
63 58
 /**
64 59
  * Generates the html content.
65 60
  * @returns {string} the html content.
66 61
  */
67 62
 ConnectionIndicator.prototype.generateText = function () {
68
-    var downloadBitrate, uploadBitrate, packetLoss, i;
69
-
70
-    if(!this.bitrate) {
71
-        downloadBitrate = "N/A";
72
-        uploadBitrate = "N/A";
73
-    }
74
-    else {
75
-        downloadBitrate =
76
-            this.bitrate.download? this.bitrate.download + " Kbps" : "N/A";
77
-        uploadBitrate =
78
-            this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A";
79
-    }
80
-
81
-    if(!this.packetLoss) {
82
-        packetLoss = "N/A";
83
-    } else {
84
-
85
-        packetLoss = "<span class='connection-info__download'>&darr;</span>" +
86
-            (this.packetLoss.download !== null ?
87
-                this.packetLoss.download : "N/A") +
88
-            "% <span class='connection-info__upload'>&uarr;</span>" +
89
-            (this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") +
90
-            "%";
91
-    }
92
-
93
-    // GENERATE RESOLUTIONS STRING
94
-    const resolutions = this.resolution || {};
95
-    const resolutionStr = Object.keys(resolutions).map(ssrc => {
96
-        let {width, height} = resolutions[ssrc];
97
-        return `${width}x${height}`;
98
-    }).join(', ') || 'N/A';
99
-
100
-    const framerates = this.framerate || {};
101
-    const frameRateStr = Object.keys(framerates).map(ssrc =>
102
-        framerates[ssrc]
103
-    ).join(', ') || 'N/A';
104
-
105
-    let result = (
106
-        `<table class="connection-info__container" style='width:100%'>
107
-            <tr>
108
-                <td>
109
-                    <span data-i18n='connectionindicator.bitrate'></span>
110
-                </td>
111
-                <td>
112
-                    <span class='connection-info__download'>&darr;</span>${downloadBitrate}
113
-                    <span class='connection-info__upload'>&uarr;</span>${uploadBitrate}
114
-                </td>
115
-            </tr>
116
-            <tr>
117
-                <td>
118
-                    <span data-i18n='connectionindicator.packetloss'></span>
119
-                </td>
120
-                <td>${packetLoss}</td>
121
-            </tr>
122
-            <tr>
123
-                <td>
124
-                    <span data-i18n='connectionindicator.resolution'></span>
125
-                </td>
126
-                <td>
127
-                    ${resolutionStr}
128
-                </td>
129
-            </tr>
130
-            <tr>
131
-                <td>
132
-                    <span data-i18n='connectionindicator.framerate'></span>
133
-                </td>
134
-                <td>
135
-                    ${frameRateStr}
136
-                </td>
137
-            </tr>
138
-        </table>`);
139
-
140
-    if(this.videoContainer.videoSpanId == "localVideoContainer") {
141
-        result += "<a class=\"jitsipopover__showmore link\" " +
142
-            "onclick = \"APP.UI.connectionIndicatorShowMore('" +
143
-            // FIXME: we do not know local id when this text is generated
144
-            //this.id + "')\"  data-i18n='connectionindicator." +
145
-            "local')\"  data-i18n='connectionindicator." +
146
-                (this.showMoreValue ? "less" : "more") + "'></a>";
147
-    }
148
-
149
-    if (this.showMoreValue) {
150
-        var downloadBandwidth, uploadBandwidth, transport;
151
-        if (!this.bandwidth) {
152
-            downloadBandwidth = "N/A";
153
-            uploadBandwidth = "N/A";
154
-        } else {
155
-            downloadBandwidth = this.bandwidth.download?
156
-                this.bandwidth.download + " Kbps" :
157
-                "N/A";
158
-            uploadBandwidth = this.bandwidth.upload?
159
-                this.bandwidth.upload + " Kbps" :
160
-                "N/A";
161
-        }
162
-
163
-        if (!this.transport || this.transport.length === 0) {
164
-            transport = "<tr>" +
165
-                "<td><span " +
166
-                "data-i18n='connectionindicator.address'></span></td>" +
167
-                "<td> N/A</td></tr>";
168
-        } else {
169
-            var data = {
170
-                remoteIP: [],
171
-                localIP:[],
172
-                remotePort:[],
173
-                localPort:[],
174
-                transportType:[]};
175
-            for(i = 0; i < this.transport.length; i++) {
176
-                var ip =  ConnectionIndicator.getIP(this.transport[i].ip);
177
-                var port = ConnectionIndicator.getPort(this.transport[i].ip);
178
-                var localIP =
179
-                    ConnectionIndicator.getIP(this.transport[i].localip);
180
-                var localPort =
181
-                    ConnectionIndicator.getPort(this.transport[i].localip);
182
-                if(data.remoteIP.indexOf(ip) == -1) {
183
-                    data.remoteIP.push(ip);
184
-                }
185
-
186
-                if(data.remotePort.indexOf(port) == -1) {
187
-                    data.remotePort.push(port);
188
-                }
189
-
190
-                if(data.localIP.indexOf(localIP) == -1) {
191
-                    data.localIP.push(localIP);
192
-                }
193
-
194
-                if(data.localPort.indexOf(localPort) == -1) {
195
-                    data.localPort.push(localPort);
196
-                }
197
-
198
-                if(data.transportType.indexOf(this.transport[i].type) == -1) {
199
-                    data.transportType.push(this.transport[i].type);
200
-                }
201
-            }
202
-
203
-            // All of the transports should be either P2P or JVB
204
-            const isP2P = this.transport.length ? this.transport[0].p2p : false;
205
-
206
-            var local_address_key = "connectionindicator.localaddress";
207
-            var remote_address_key = "connectionindicator.remoteaddress";
208
-            var localTransport =
209
-                "<tr><td><span data-i18n='" +
210
-                local_address_key +"' data-i18n-options='" +
211
-                    JSON.stringify({count: data.localIP.length})
212
-                        + "'></span></td><td> " +
213
-                ConnectionIndicator.getStringFromArray(data.localIP) +
214
-                "</td></tr>";
215
-            transport =
216
-                "<tr><td><span data-i18n='" +
217
-                remote_address_key + "' data-i18n-options='" +
218
-                    JSON.stringify({count: data.remoteIP.length})
219
-                        + "'></span></td><td> " +
220
-                ConnectionIndicator.getStringFromArray(data.remoteIP);
221
-
222
-            // Append (p2p) to indicate the P2P type of transport
223
-            if (isP2P) {
224
-                transport
225
-                    += "<span data-i18n='connectionindicator.peer_to_peer'>";
226
-            }
227
-            transport += "</td></tr>";
228
-
229
-            var key_remote = "connectionindicator.remoteport",
230
-                key_local = "connectionindicator.localport";
231
-
232
-            transport += "<tr>" +
233
-                "<td>" +
234
-                "<span data-i18n='" + key_remote +
235
-                "' data-i18n-options='" +
236
-                    JSON.stringify({count: this.transport.length})
237
-                        + "'></span></td><td>";
238
-            localTransport += "<tr>" +
239
-                "<td>" +
240
-                "<span data-i18n='" + key_local +
241
-                "' data-i18n-options='" +
242
-                    JSON.stringify({count: this.transport.length})
243
-                        + "'></span></td><td>";
244
-
245
-            transport +=
246
-                ConnectionIndicator.getStringFromArray(data.remotePort);
247
-            localTransport +=
248
-                ConnectionIndicator.getStringFromArray(data.localPort);
249
-            transport += "</td></tr>";
250
-            transport += localTransport + "</td></tr>";
251
-            transport +="<tr>" +
252
-                "<td><span data-i18n='connectionindicator.transport' "
253
-                    + " data-i18n-options='" +
254
-                    JSON.stringify({count: data.transportType.length})
255
-                + "'></span></td>" +
256
-                "<td>"
257
-                    + ConnectionIndicator.getStringFromArray(data.transportType);
258
-                + "</td></tr>";
259
-
260
-        }
261
-
262
-        result += "<table class='connection-info__container' style='width:100%'>" +
263
-            "<tr>" +
264
-            "<td>" +
265
-            "<span data-i18n='connectionindicator.bandwidth'></span>" +
266
-            "</td><td>" +
267
-            "<span class='connection-info__download'>&darr;</span>" +
268
-            downloadBandwidth +
269
-            " <span class='connection-info__upload'>&uarr;</span>" +
270
-            uploadBandwidth + "</td></tr>";
271
-
272
-        result += transport + "</table>";
273
-    }
274
-
275
-    return result;
63
+    /* jshint ignore:start */
64
+    return (
65
+        <ConnectionStatsTable
66
+            bandwidth = { this.bandwidth }
67
+            bitrate = { this.bitrate }
68
+            isLocalVideo = { this.isLocalVideo }
69
+            framerate = { this.framerate }
70
+            onShowMore = { this.showMore }
71
+            packetLoss = { this.packetLoss}
72
+            resolution = { this.resolution }
73
+            shouldShowMore = { this.showMoreValue }
74
+            transport = { this.transport } />
75
+    );
76
+    /* jshint ignore:end */
276 77
 };
277 78
 
278 79
 /**
@@ -443,9 +244,7 @@ ConnectionIndicator.prototype.updatePopoverData = function (force) {
443 244
     // generate content, translate it and add it to document only if
444 245
     // popover is visible or we force to do so.
445 246
     if(this.popover.popoverShown || force) {
446
-        this.popover.updateContent(
447
-            `<div class="connection-info">${this.generateText()}</div>`
448
-        );
247
+        this.popover.updateContent(this.generateText());
449 248
     }
450 249
 };
451 250
 

+ 499
- 0
react/features/connection-stats/components/ConnectionStatsTable.js ファイルの表示

@@ -0,0 +1,499 @@
1
+import React, { Component } from 'react';
2
+
3
+import { translate } from '../../base/i18n';
4
+
5
+/**
6
+ * React {@code Component} for displaying connection statistics.
7
+ *
8
+ * @extends Component
9
+ */
10
+class ConnectionStatsTable extends Component {
11
+    /**
12
+     * {@code ConnectionStatsTable} component's property types.
13
+     *
14
+     * @static
15
+     */
16
+    static propTypes = {
17
+        /**
18
+         * Statistics related to bandwidth.
19
+         * {{
20
+         *     download: Number,
21
+         *     upload: Number
22
+         * }}
23
+         */
24
+        bandwidth: React.PropTypes.object,
25
+
26
+        /**
27
+         * Statistics related to bitrate.
28
+         * {{
29
+         *     download: Number,
30
+         *     upload: Number
31
+         * }}
32
+         */
33
+        bitrate: React.PropTypes.object,
34
+
35
+        /**
36
+         * Statistics related to framerates for each ssrc.
37
+         * {{
38
+         *     [ ssrc ]: Number
39
+         * }}
40
+         */
41
+        framerate: React.PropTypes.object,
42
+
43
+        /**
44
+         * Whether or not the statitics are for local video.
45
+         */
46
+        isLocalVideo: React.PropTypes.bool,
47
+
48
+        /**
49
+         * Callback to invoke when the show additional stats link is clicked.
50
+         */
51
+        onShowMore: React.PropTypes.func,
52
+
53
+        /**
54
+         * Statistics related to packet loss.
55
+         * {{
56
+         *     download: Number,
57
+         *     upload: Number
58
+         * }}
59
+         */
60
+        packetLoss: React.PropTypes.object,
61
+
62
+        /**
63
+         * Statistics related to display resolutions for each ssrc.
64
+         * {{
65
+         *     [ ssrc ]: {
66
+         *         height: Number,
67
+         *         width: Number
68
+         *     }
69
+         * }}
70
+         */
71
+        resolution: React.PropTypes.object,
72
+
73
+        /**
74
+         * Whether or not additional stats about bandwidth and transport should
75
+         * be displayed. Will not display even if true for remote participants.
76
+         */
77
+        shouldShowMore: React.PropTypes.bool,
78
+
79
+        /**
80
+         * Invoked to obtain translated strings.
81
+         */
82
+        t: React.PropTypes.func,
83
+
84
+        /**
85
+         * Statistics related to transports.
86
+         */
87
+        transport: React.PropTypes.array
88
+    };
89
+
90
+    /**
91
+     * Implements React's {@link Component#render()}.
92
+     *
93
+     * @inheritdoc
94
+     * @returns {ReactElement}
95
+     */
96
+    render() {
97
+        const { isLocalVideo } = this.props;
98
+
99
+        return (
100
+            <div className = 'connection-info'>
101
+                { this._renderStatistics() }
102
+                { isLocalVideo ? this._renderShowMoreLink() : null }
103
+                { isLocalVideo && this.props.shouldShowMore
104
+                    ? this._renderAdditionalStats() : null }
105
+            </div>
106
+        );
107
+    }
108
+
109
+    /**
110
+     * Creates a table as ReactElement that will display additional statistics
111
+     * related to bandwidth and transport.
112
+     *
113
+     * @private
114
+     * @returns {ReactElement}
115
+     */
116
+    _renderAdditionalStats() {
117
+        return (
118
+            <table className = 'connection-info__container'>
119
+                <tbody>
120
+                    { this._renderBandwidth() }
121
+                    { this._renderTransport() }
122
+                </tbody>
123
+            </table>
124
+        );
125
+    }
126
+
127
+    /**
128
+     * Creates a table row as a ReactElement for displaying bandwidth related
129
+     * statistics.
130
+     *
131
+     * @private
132
+     * @returns {ReactElement}
133
+     */
134
+    _renderBandwidth() {
135
+        const { download, upload } = this.props.bandwidth || {};
136
+
137
+        return (
138
+            <tr>
139
+                <td>
140
+                    { this.props.t('connectionindicator.bandwidth') }
141
+                </td>
142
+                <td>
143
+                    <span className = 'connection-info__download'>
144
+                        &darr;
145
+                    </span>
146
+                    { download ? `${download} Kbps` : 'N/A' }
147
+                    <span className = 'connection-info__upload'>
148
+                        &uarr;
149
+                    </span>
150
+                    { upload ? `${upload} Kbps` : 'N/A' }
151
+                </td>
152
+            </tr>
153
+        );
154
+    }
155
+
156
+    /**
157
+     * Creates a a table row as a ReactElement for displaying bitrate related
158
+     * statistics.
159
+     *
160
+     * @private
161
+     * @returns {ReactElement}
162
+     */
163
+    _renderBitrate() {
164
+        const { download, upload } = this.props.bitrate || {};
165
+
166
+        return (
167
+            <tr>
168
+                <td>
169
+                    <span>
170
+                        { this.props.t('connectionindicator.bitrate') }
171
+                    </span>
172
+                </td>
173
+                <td>
174
+                    <span className = 'connection-info__download'>
175
+                        &darr;
176
+                    </span>
177
+                    { download ? `${download} Kbps` : 'N/A' }
178
+                    <span className = 'connection-info__upload'>
179
+                        &uarr;
180
+                    </span>
181
+                    { upload ? `${upload} Kbps` : 'N/A' }
182
+                </td>
183
+            </tr>
184
+        );
185
+    }
186
+
187
+    /**
188
+     * Creates a table row as a ReactElement for displaying frame rate related
189
+     * statistics.
190
+     *
191
+     * @private
192
+     * @returns {ReactElement}
193
+     */
194
+    _renderFrameRate() {
195
+        const { framerate, t } = this.props;
196
+        const frameRateString = Object.keys(framerate || {})
197
+            .map(ssrc => framerate[ssrc])
198
+            .join(', ') || 'N/A';
199
+
200
+        return (
201
+            <tr>
202
+                <td>
203
+                    <span>{ t('connectionindicator.framerate') }</span>
204
+                </td>
205
+                <td>{ frameRateString }</td>
206
+            </tr>
207
+        );
208
+    }
209
+
210
+    /**
211
+     * Creates a tables row as a ReactElement for displaying packet loss related
212
+     * statistics.
213
+     *
214
+     * @private
215
+     * @returns {ReactElement}
216
+     */
217
+    _renderPacketLoss() {
218
+        const { packetLoss, t } = this.props;
219
+        let packetLossTableData;
220
+
221
+        if (packetLoss) {
222
+            const { download, upload } = packetLoss;
223
+
224
+            // eslint-disable-next-line no-extra-parens
225
+            packetLossTableData = (
226
+                <td>
227
+                    <span className = 'connection-info__download'>
228
+                        &darr;
229
+                    </span>
230
+                    { download === null ? 'N/A' : `${download}%` }
231
+                    <span className = 'connection-info__upload'>
232
+                        &uarr;
233
+                    </span>
234
+                    { upload === null ? 'N/A' : `${upload}%` }
235
+                </td>
236
+            );
237
+        } else {
238
+            packetLossTableData = <td>N/A</td>;
239
+        }
240
+
241
+        return (
242
+            <tr>
243
+                <td>
244
+                    <span>
245
+                        { t('connectionindicator.packetloss') }
246
+                    </span>
247
+                </td>
248
+                { packetLossTableData }
249
+            </tr>
250
+        );
251
+    }
252
+
253
+    /**
254
+     * Creates a table row as a ReactElement for displaying resolution related
255
+     * statistics.
256
+     *
257
+     * @private
258
+     * @returns {ReactElement}
259
+     */
260
+    _renderResolution() {
261
+        const { resolution, t } = this.props;
262
+        const resolutionString = Object.keys(resolution || {})
263
+            .map(ssrc => {
264
+                const { width, height } = resolution[ssrc];
265
+
266
+                return `${width}x${height}`;
267
+            })
268
+            .join(', ') || 'N/A';
269
+
270
+        return (
271
+            <tr>
272
+                <td>
273
+                    <span>{ t('connectionindicator.resolution') }</span>
274
+                </td>
275
+                <td>{ resolutionString }</td>
276
+            </tr>
277
+        );
278
+    }
279
+
280
+    /**
281
+     * Creates a ReactElement for display a link to toggle showing additional
282
+     * statistics.
283
+     *
284
+     * @private
285
+     * @returns {ReactElement}
286
+     */
287
+    _renderShowMoreLink() {
288
+        const translationKey
289
+            = this.props.shouldShowMore
290
+            ? 'connectionindicator.less'
291
+            : 'connectionindicator.more';
292
+
293
+        return (
294
+            <a
295
+                className = 'jitsipopover__showmore link'
296
+                onClick = { this.props.onShowMore } >
297
+                { this.props.t(translationKey) }
298
+            </a>
299
+        );
300
+    }
301
+
302
+    /**
303
+     * Creates a table as a ReactElement for displaying connection statistics.
304
+     *
305
+     * @private
306
+     * @returns {ReactElement}
307
+     */
308
+    _renderStatistics() {
309
+        return (
310
+            <table className = 'connection-info__container'>
311
+                <tbody>
312
+                    { this._renderBitrate() }
313
+                    { this._renderPacketLoss() }
314
+                    { this._renderResolution() }
315
+                    { this._renderFrameRate() }
316
+                </tbody>
317
+            </table>
318
+        );
319
+    }
320
+
321
+    /**
322
+     * Creates table rows as ReactElements for displaying transport related
323
+     * statistics.
324
+     *
325
+     * @private
326
+     * @returns {ReactElement[]}
327
+     */
328
+    _renderTransport() {
329
+        const { t, transport } = this.props;
330
+
331
+        if (!transport || transport.length === 0) {
332
+            // eslint-disable-next-line no-extra-parens
333
+            const NA = (
334
+                <tr key = 'address'>
335
+                    <td>
336
+                        <span>{ t('connectionindicator.address') }</span>
337
+                    </td>
338
+                    <td>
339
+                        N/A
340
+                    </td>
341
+                </tr>
342
+            );
343
+
344
+            return [ NA ];
345
+        }
346
+
347
+        const data = {
348
+            localIP: [],
349
+            localPort: [],
350
+            remoteIP: [],
351
+            remotePort: [],
352
+            transportType: []
353
+        };
354
+
355
+        for (let i = 0; i < transport.length; i++) {
356
+            const ip = getIP(transport[i].ip);
357
+            const localIP = getIP(transport[i].localip);
358
+            const localPort = getPort(transport[i].localip);
359
+            const port = getPort(transport[i].ip);
360
+
361
+            if (!data.remoteIP.includes(ip)) {
362
+                data.remoteIP.push(ip);
363
+            }
364
+
365
+            if (!data.localIP.includes(localIP)) {
366
+                data.localIP.push(localIP);
367
+            }
368
+
369
+            if (!data.localPort.includes(localPort)) {
370
+                data.localPort.push(localPort);
371
+            }
372
+
373
+            if (!data.remotePort.includes(port)) {
374
+                data.remotePort.push(port);
375
+            }
376
+
377
+            if (!data.transportType.includes(transport[i].type)) {
378
+                data.transportType.push(transport[i].type);
379
+            }
380
+        }
381
+
382
+        // All of the transports should be either P2P or JVB
383
+        const isP2P = transport.length ? transport[0].p2p : false;
384
+
385
+        // First show remote statistics, then local, and then transport type.
386
+        const tableRowConfigurations = [
387
+            {
388
+                additionalData: isP2P
389
+                    ? <span>{ t('connectionindicator.peer_to_peer') }</span>
390
+                    : null,
391
+                data: data.remoteIP,
392
+                key: 'remoteaddress',
393
+                label: t('connectionindicator.remoteaddress',
394
+                    { count: data.remoteIP.length })
395
+            },
396
+            {
397
+                data: data.remotePort,
398
+                key: 'remoteport',
399
+                label: t('connectionindicator.remoteport',
400
+                        { count: transport.length })
401
+            },
402
+            {
403
+                data: data.localIP,
404
+                key: 'localaddress',
405
+                label: t('connectionindicator.localaddress',
406
+                    { count: data.localIP.length })
407
+            },
408
+            {
409
+                data: data.localPort,
410
+                key: 'localport',
411
+                label: t('connectionindicator.localport',
412
+                    { count: transport.length })
413
+            },
414
+            {
415
+                data: data.transportType,
416
+                key: 'transport',
417
+                label: t('connectionindicator.transport',
418
+                    { count: data.transportType.length })
419
+            }
420
+        ];
421
+
422
+        return tableRowConfigurations.map(this._renderTransportTableRow);
423
+    }
424
+
425
+    /**
426
+     * Creates a table row as a ReactElement for displaying a transport related
427
+     * statistic.
428
+     *
429
+     * @param {Object} config - Describes the contents of the row.
430
+     * @param {ReactElement} config.additionalData - Extra data to display next
431
+     * to the passed in config.data.
432
+     * @param {Array} config.data - The transport statistics to display.
433
+     * @param {string} config.key - The ReactElement's key. Must be unique for
434
+     * iterating over multiple child rows.
435
+     * @param {string} config.label - The text to display describing the data.
436
+     * @private
437
+     * @returns {ReactElement}
438
+     */
439
+    _renderTransportTableRow(config) {
440
+        const { additionalData, data, key, label } = config;
441
+
442
+        return (
443
+            <tr key = { key }>
444
+                <td>
445
+                    <span>
446
+                        { label }
447
+                    </span>
448
+                </td>
449
+                <td>
450
+                    { getStringFromArray(data) }
451
+                    { additionalData || null }
452
+                </td>
453
+            </tr>
454
+        );
455
+    }
456
+}
457
+
458
+/**
459
+ * Utility for getting the IP from a transport statistics object's
460
+ * representation of an IP.
461
+ *
462
+ * @param {string} value - The transport's IP to parse.
463
+ * @private
464
+ * @returns {string}
465
+ */
466
+function getIP(value) {
467
+    return value.substring(0, value.lastIndexOf(':'));
468
+}
469
+
470
+/**
471
+ * Utility for getting the port from a transport statistics object's
472
+ * representation of an IP.
473
+ *
474
+ * @param {string} value - The transport's IP to parse.
475
+ * @private
476
+ * @returns {string}
477
+ */
478
+function getPort(value) {
479
+    return value.substring(value.lastIndexOf(':') + 1, value.length);
480
+}
481
+
482
+/**
483
+ * Utility for concatenating values in an array into a comma separated string.
484
+ *
485
+ * @param {Array} array - Transport statistics to concatenate.
486
+ * @private
487
+ * @returns {string}
488
+ */
489
+function getStringFromArray(array) {
490
+    let res = '';
491
+
492
+    for (let i = 0; i < array.length; i++) {
493
+        res += (i === 0 ? '' : ', ') + array[i];
494
+    }
495
+
496
+    return res;
497
+}
498
+
499
+export default translate(ConnectionStatsTable);

+ 1
- 0
react/features/connection-stats/components/index.js ファイルの表示

@@ -0,0 +1 @@
1
+export { default as ConnectionStatsTable } from './ConnectionStatsTable';

+ 1
- 0
react/features/connection-stats/index.js ファイルの表示

@@ -0,0 +1 @@
1
+export * from './components';

読み込み中…
キャンセル
保存