28 Commits

Author SHA1 Message Date
Irtiza-h30
5a49a0301e get radius profile query 2020-08-05 12:02:08 -04:00
Sean Macfarlane
afc222bb4a fixed root path bug 2020-08-04 01:46:25 -04:00
Sean Macfarlane
c595424269 update version 2020-08-03 17:17:25 -04:00
Sean Macfarlane
69fbceefff Merge pull request #40 from Telecominfraproject/hotfix/docker
Hotfix/docker: made API URL Dynamic
2020-08-03 14:53:18 -04:00
Sean Macfarlane
f9c66adf00 update versiom 2020-08-03 14:51:02 -04:00
Sean Macfarlane
56c0329bdb Merge branch 'master' into hotfix/docker 2020-08-03 14:33:57 -04:00
Sean Macfarlane
06cb3feac3 fixed jq 2020-08-03 14:32:56 -04:00
Sean Macfarlane
a159705cae fixed client history 2020-08-03 13:21:13 -04:00
Sean Macfarlane
02c20ffd6e fixed Alarms error handling 2020-08-03 12:08:08 -04:00
Sean Macfarlane
dc8374300e make API url dynamic 2020-08-03 12:03:56 -04:00
Sean Macfarlane
c001ce21ba update version 2020-08-02 13:20:03 -04:00
Sean Macfarlane
04bbc5fbed Merge pull request #35 from Telecominfraproject/feature/TW-843-polling
Feature/TW-843-polling: Line charts with polling new data after an interval
2020-08-01 13:12:48 -04:00
Sean Macfarlane
902de8bcb0 renamed Capacity to Occupany 2020-08-01 13:12:12 -04:00
Sean Macfarlane
6c6635017a cleanup 2020-08-01 12:58:43 -04:00
Sean Macfarlane
8891b5b3f9 cleanup 2020-08-01 12:51:18 -04:00
Sean Macfarlane
8d2e5bb8a5 Merge pull request #38 from Telecominfraproject/feature/TW-957
feature/TW-957: Blocked List Page
2020-07-30 11:47:20 -04:00
Sean Macfarlane
f29f31558a update version 2020-07-30 11:28:54 -04:00
Sean Macfarlane
6e0cf15616 Merge branch 'master' into feature/TW-957 2020-07-30 11:01:14 -04:00
Alidev123
49d5771fca Merge branch 'master' of https://github.com/Telecominfraproject/wlan-cloud-ui into feature/TW-843-polling 2020-07-30 10:41:23 -04:00
Alidev123
3794869adb fixed Line Charts polling 2020-07-30 10:41:09 -04:00
Sean Macfarlane
3d105340af Merge pull request #39 from Telecominfraproject/hotfix/TW-968
hotfix/TW-968: seconds to hh:mm:ss format
2020-07-29 17:12:48 -04:00
Sean Macfarlane
c8ee2138ad added days 2020-07-29 17:12:12 -04:00
Irtiza-h30
2e9dd99f3a seconds to hh:mm:ss format 2020-07-29 16:36:26 -04:00
Alidev123
0d58a8bb6a fixed line charts polling 2020-07-29 15:12:01 -04:00
Alidev123
19c0bb4393 Merge branch 'master' of https://github.com/Telecominfraproject/wlan-cloud-ui into feature/TW-843-polling 2020-07-27 09:50:38 -04:00
Alidev123
2a521ce036 fixed line charts re-rendering issue 2020-07-27 09:48:55 -04:00
Alidev123
85e1ee16ee fixed line chart component 2020-07-24 15:23:49 -04:00
Alidev123
195518a137 updated linecharts with polling new data after every 5 min 2020-07-24 12:18:26 -04:00
14 changed files with 198 additions and 100 deletions

View File

@@ -24,7 +24,11 @@ RUN npm run build
# production environment
FROM nginx:stable-alpine
RUN apk add --no-cache jq
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY docker_entrypoint.sh generate_config_js.sh /
RUN chmod +x docker_entrypoint.sh generate_config_js.sh
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT ["/docker_entrypoint.sh"]

1
app/config.js Normal file
View File

@@ -0,0 +1 @@
window.REACT_APP_API = undefined;

View File

@@ -31,6 +31,7 @@ const Alarms = () => {
const { customerId } = useContext(UserContext);
const { loading, error, data, refetch, fetchMore } = useQuery(GET_ALL_ALARMS, {
variables: { customerId },
errorPolicy: 'all',
});
const handleOnReload = () => {
@@ -73,9 +74,10 @@ const Alarms = () => {
return <Loading />;
}
if (error) {
if (error && !data?.getAllAlarms?.items) {
return <Alert message="Error" description="Failed to load alarms." type="error" showIcon />;
}
return (
<AlarmsPage
data={data.getAllAlarms.items}

View File

@@ -1,4 +1,4 @@
import React, { useContext, useMemo, useState } from 'react';
import React, { useContext, useEffect, useMemo, useState, useRef } from 'react';
import { Alert } from 'antd';
import moment from 'moment';
import { useQuery } from '@apollo/react-hooks';
@@ -36,104 +36,164 @@ const USER_FRIENDLY_RADIOS = {
is5GHz: '5GHz',
};
const lineChartConfig = [
{ key: 'inservicesAPs', title: 'Inservice APs (24 hours)' },
{ key: 'clientDevices', title: 'Client Devices (24 hours)' },
{
key: 'traffic',
title: 'Traffic (24 hours)',
options: { formatter: trafficLabelFormatter, tooltipFormatter: trafficTooltipFormatter },
},
];
const Dashboard = () => {
const initialGraphTime = useRef({
toTime: moment()
.valueOf()
.toString(),
fromTime: moment()
.subtract(24, 'hours')
.valueOf()
.toString(),
});
const { customerId } = useContext(UserContext);
const { loading, error, data } = useQuery(GET_ALL_STATUS, {
variables: { customerId, statusDataTypes: ['CUSTOMER_DASHBOARD'] },
});
const [toTime] = useState(
moment()
.valueOf()
.toString()
);
const [fromTime] = useState(
moment()
.subtract(24, 'hours')
.valueOf()
.toString()
);
const {
loading: metricsLoading,
error: metricsError,
data: metricsData,
// refetch: metricsRefetch,
} = useQuery(FILTER_SYSTEM_EVENTS, {
variables: {
customerId,
fromTime,
toTime,
equipmentIds: [0],
dataTypes: ['StatusChangedEvent'],
limit: 1000,
const [lineChartData, setLineChartData] = useState({
inservicesAPs: {
key: 'Inservice APs',
value: [],
},
clientDevices: {
is2dot4GHz: {
key: USER_FRIENDLY_RADIOS.is2dot4GHz,
value: [],
},
is5GHz: {
key: USER_FRIENDLY_RADIOS.is5GHz,
value: [],
},
},
traffic: {
trafficBytesDownstream: {
key: 'Down Stream',
value: [],
},
trafficBytesUpstream: {
key: 'Up Stream',
value: [],
},
},
});
const formatLineChartData = (list = []) => {
const lineChartData = {
inservicesAPs: {
title: 'Inservice APs (24 hours)',
data: { key: 'Inservice APs', value: [] },
const { loading: metricsLoading, error: metricsError, data: metricsData, fetchMore } = useQuery(
FILTER_SYSTEM_EVENTS,
{
variables: {
customerId,
fromTime: initialGraphTime.current.fromTime,
toTime: initialGraphTime.current.toTime,
equipmentIds: [0],
dataTypes: ['StatusChangedEvent'],
limit: 3000, // TODO: make get all in GraphQL
},
clientDevices: { title: 'Client Devices (24 hours)' },
traffic: {
title: 'Traffic (24 hours)',
formatter: trafficLabelFormatter,
tooltipFormatter: trafficTooltipFormatter,
data: {
trafficBytesDownstream: { key: 'Down Stream', value: [] },
trafficBytesUpstream: { key: 'Up Stream', value: [] },
},
},
};
const clientDevicesData = {};
}
);
list.forEach(
({
eventTimestamp,
details: {
payload: {
const formatLineChartData = (list = []) => {
if (list.length) {
setLineChartData(prev => {
const inservicesAPs = [];
const clientDevices2dot4GHz = [];
const clientDevices5GHz = [];
const trafficBytesDownstreamData = [];
const trafficBytesUpstreamData = [];
list.forEach(
({
eventTimestamp,
details: {
equipmentInServiceCount,
associatedClientsCountPerRadio: radios,
trafficBytesDownstream,
trafficBytesUpstream,
payload: {
details: {
equipmentInServiceCount,
associatedClientsCountPerRadio: radios,
trafficBytesDownstream,
trafficBytesUpstream,
},
},
},
}) => {
inservicesAPs.push([eventTimestamp, equipmentInServiceCount]);
let total5GHz = 0;
total5GHz += (radios?.is5GHz || 0) + (radios?.is5GHzL || 0) + (radios?.is5GHzU || 0); // combine all 5GHz radios
clientDevices2dot4GHz.push([eventTimestamp, radios.is2dot4GHz || 0]);
clientDevices5GHz.push([eventTimestamp, total5GHz]);
trafficBytesDownstreamData.push([eventTimestamp, trafficBytesDownstream]);
trafficBytesUpstreamData.push([eventTimestamp, trafficBytesUpstream]);
}
);
return {
inservicesAPs: {
...prev.inservicesAPs,
value: [...prev.inservicesAPs.value, ...inservicesAPs],
},
clientDevices: {
is2dot4GHz: {
...prev.clientDevices.is2dot4GHz,
value: [...prev.clientDevices.is2dot4GHz.value, ...clientDevices2dot4GHz],
},
is5GHz: {
...prev.clientDevices.is5GHz,
value: [...prev.clientDevices.is5GHz.value, ...clientDevices5GHz],
},
},
},
}) => {
lineChartData.inservicesAPs.data.value.push([eventTimestamp, equipmentInServiceCount]);
Object.keys(radios).forEach(key => {
if (!clientDevicesData[key]) {
clientDevicesData[key] = {
key: USER_FRIENDLY_RADIOS[key] || key,
value: [],
};
}
clientDevicesData[key].value.push([eventTimestamp, radios[key]]);
});
lineChartData.traffic.data.trafficBytesDownstream.value.push([
eventTimestamp,
trafficBytesDownstream,
]);
lineChartData.traffic.data.trafficBytesUpstream.value.push([
eventTimestamp,
trafficBytesUpstream,
]);
}
);
return {
...lineChartData,
clientDevices: { ...lineChartData.clientDevices, data: { ...clientDevicesData } },
};
traffic: {
trafficBytesDownstream: {
...prev.traffic.trafficBytesDownstream,
value: [...prev.traffic.trafficBytesDownstream.value, ...trafficBytesDownstreamData],
},
trafficBytesUpstream: {
...prev.traffic.trafficBytesUpstream,
value: [...prev.traffic.trafficBytesUpstream.value, ...trafficBytesUpstreamData],
},
},
};
});
}
};
const lineChartsData = useMemo(
() => formatLineChartData(metricsData?.filterSystemEvents?.items),
[metricsData]
);
useEffect(() => {
const interval = setInterval(() => {
const toTime = moment()
.valueOf()
.toString();
const fromTime = moment()
.subtract(5, 'minutes')
.valueOf()
.toString();
fetchMore({
variables: {
fromTime,
toTime,
},
updateQuery: (_, { fetchMoreResult }) => {
formatLineChartData(fetchMoreResult?.filterSystemEvents?.items);
},
});
}, 300000);
return () => clearInterval(interval);
}, []);
useEffect(() => {
formatLineChartData(metricsData?.filterSystemEvents?.items);
}, [metricsData]);
const statsArr = useMemo(() => {
const status = data?.getAllStatus?.items[0]?.detailsJSON || {};
@@ -205,7 +265,8 @@ const Dashboard = () => {
<DashboardPage
statsCardDetails={statsArr}
pieChartDetails={pieChartsData}
lineChartDetails={lineChartsData}
lineChartData={lineChartData}
lineChartConfig={lineChartConfig}
lineChartLoading={metricsLoading}
lineChartError={metricsError}
/>

View File

@@ -1,11 +1,14 @@
import React, { useEffect, useContext } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { useLazyQuery } from '@apollo/react-hooks';
import { Alert } from 'antd';
import { floor, padStart } from 'lodash';
import { NetworkTable, Loading } from '@tip-wlan/wlan-cloud-ui-library';
import UserContext from 'contexts/UserContext';
import { FILTER_EQUIPMENT } from 'graphql/queries';
import styles from './index.module.scss';
const renderTableCell = tabCell => {
@@ -22,6 +25,13 @@ const renderTableCell = tabCell => {
return tabCell;
};
const durationToString = duration =>
`${floor(duration.asDays())}d ${floor(duration.hours())}h ${padStart(
duration.minutes(),
2,
0
)}m ${padStart(duration.seconds(), 2, 0)}s`;
const accessPointsTableColumns = [
{
title: 'NAME',
@@ -61,7 +71,7 @@ const accessPointsTableColumns = [
{
title: 'UP TIME',
dataIndex: ['status', 'osPerformance', 'details', 'uptimeInSeconds'],
render: renderTableCell,
render: upTimeInSeconds => durationToString(moment.duration(upTimeInSeconds, 'seconds')),
},
{
title: 'PROFILE',
@@ -74,7 +84,7 @@ const accessPointsTableColumns = [
render: renderTableCell,
},
{
title: 'CAPACITY',
title: 'OCCUPANCY',
dataIndex: ['status', 'radioUtilization', 'details', 'capacityDetails'],
render: renderTableCell,
},

View File

@@ -12,7 +12,7 @@ import UserContext from 'contexts/UserContext';
import { GET_CLIENT_SESSION, FILTER_SERVICE_METRICS } from 'graphql/queries';
const toTime = moment();
const fromTime = moment().subtract(1, 'hour');
const fromTime = moment().subtract(4, 'hours');
const ClientDeviceDetails = () => {
const { id } = useParams();
@@ -33,7 +33,7 @@ const ClientDeviceDetails = () => {
toTime: toTime.valueOf().toString(),
clientMacs: [id],
dataTypes: ['Client'],
limit: 100,
limit: 1000,
},
});
@@ -73,7 +73,7 @@ const ClientDeviceDetails = () => {
metricsData={
metricsData && metricsData.filterServiceMetrics && metricsData.filterServiceMetrics.items
}
historyDate={toTime}
historyDate={{ toTime, fromTime }}
/>
);
};

View File

@@ -77,9 +77,15 @@ const ProfileDetails = () => {
const { loading, error, data } = useQuery(GET_PROFILE, {
variables: { id },
});
const { data: ssidProfiles } = useQuery(GET_ALL_PROFILES, {
variables: { customerId, type: 'ssid' },
});
const { data: radiusProfiles } = useQuery(GET_ALL_PROFILES, {
variables: { customerId, type: 'radius' },
});
const [updateProfile] = useMutation(UPDATE_PROFILE);
const [deleteProfile] = useMutation(DELETE_PROFILE);
@@ -170,6 +176,7 @@ const ProfileDetails = () => {
ssidProfiles={
(ssidProfiles && ssidProfiles.getAllProfiles && ssidProfiles.getAllProfiles.items) || []
}
radiusProfiles={radiusProfiles?.getAllProfiles?.items}
fileUpload={handleFileUpload}
/>
);

View File

@@ -181,6 +181,7 @@ export const FILTER_SERVICE_METRICS = gql`
rssi
rxBytes
txBytes
detailsJSON
}
context {
lastPage

View File

@@ -9,6 +9,7 @@
<!-- Allow installing the app to the homescreen -->
<meta name="mobile-web-app-capable" content="yes" />
<script type="text/javascript" src="/config.js"></script>
</head>
<body>

View File

@@ -18,9 +18,7 @@ import { getItem, setItem, removeItem } from 'utils/localStorage';
import history from 'utils/history';
const API_URI =
process.env.NODE_ENV === 'development'
? 'http://localhost:4000/'
: 'https://wlan-graphql.zone3.lab.connectus.ai/';
process.env.NODE_ENV === 'development' ? 'http://localhost:4000/' : window.REACT_APP_API;
const MOUNT_NODE = document.getElementById('root');
const cache = new InMemoryCache();

3
docker_entrypoint.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/sh -eu
./generate_config_js.sh >/usr/share/nginx/html/config.js
nginx -g "daemon off;"

10
generate_config_js.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/sh -eu
if [ -z "${API:-}" ]; then
API_URL_JSON=undefined
else
API_URL_JSON=$(jq -n --arg api "$API" '$api')
fi
cat <<EOF
window.REACT_APP_API = $API_URL_JSON;
EOF

8
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "wlan-cloud-ui",
"version": "0.2.3",
"version": "0.2.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1874,9 +1874,9 @@
}
},
"@tip-wlan/wlan-cloud-ui-library": {
"version": "0.2.3",
"resolved": "https://tip.jfrog.io/artifactory/api/npm/tip-wlan-cloud-npm-repo/@tip-wlan/wlan-cloud-ui-library/-/@tip-wlan/wlan-cloud-ui-library-0.2.3.tgz",
"integrity": "sha1-m/aF8DLiaeGF8UDtECAabipk2P0="
"version": "0.2.7",
"resolved": "https://tip.jfrog.io/artifactory/api/npm/tip-wlan-cloud-npm-repo/@tip-wlan/wlan-cloud-ui-library/-/@tip-wlan/wlan-cloud-ui-library-0.2.7.tgz",
"integrity": "sha1-GGCapOJxcgD36ml6ZU2j1AlzXio="
},
"@types/anymatch": {
"version": "1.3.1",

View File

@@ -1,6 +1,6 @@
{
"name": "wlan-cloud-ui",
"version": "0.2.3",
"version": "0.2.7",
"author": "ConnectUs",
"description": "React Portal",
"engines": {
@@ -20,7 +20,7 @@
"@ant-design/icons": "^4.2.1",
"@apollo/react-hoc": "^3.1.4",
"@apollo/react-hooks": "^3.1.3",
"@tip-wlan/wlan-cloud-ui-library": "^0.2.3",
"@tip-wlan/wlan-cloud-ui-library": "^0.2.7",
"antd": "^4.3.1",
"apollo-cache-inmemory": "^1.6.6",
"apollo-client": "^2.6.10",