7 Commits

Author SHA1 Message Date
chris-cosentino
6cd1458f17 added wrapper for missed components 2020-12-08 11:09:03 -05:00
chris-cosentino
2b80c7cb82 created high order query component handling errors 2020-12-07 17:50:28 -05:00
chris-cosentino
92b522e14b checked error on all pages 2020-11-18 10:35:47 -05:00
chris-cosentino
917b949fea Merge branch 'hotfix/WIFI-905' of https://github.com/Telecominfraproject/wlan-cloud-ui into hotfix/WIFI-905 2020-11-17 19:16:25 -05:00
chris-cosentino
439ff1afbe hotfix/WIFI-905: App doesnt show error page briefly when user session expires 2020-11-17 19:13:25 -05:00
Toan Do
acf36fb42b deleted error 401 verification 2020-10-19 10:52:57 -04:00
Toan Do
273ca85fde prevents error message when Auth Token expires 2020-10-16 17:08:18 -04:00
14 changed files with 1351 additions and 1374 deletions

View File

@@ -1,10 +1,11 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client'; import { useMutation, gql } from '@apollo/client';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import { Accounts as AccountsPage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { Accounts as AccountsPage } from '@tip-wlan/wlan-cloud-ui-library';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { withQuery } from 'containers/QueryWrapper';
const GET_ALL_USERS = gql` const GET_ALL_USERS = gql`
query GetAllUsers($customerId: ID!, $context: JSONObject) { query GetAllUsers($customerId: ID!, $context: JSONObject) {
@@ -65,120 +66,117 @@ const DELETE_USER = gql`
} }
`; `;
const Accounts = () => { const Accounts = withQuery(
const { customerId } = useContext(UserContext); ({ data, fetchMore, refetch }) => {
const { customerId } = useContext(UserContext);
const { data, loading, error, refetch, fetchMore } = useQuery(GET_ALL_USERS, { const [createUser] = useMutation(CREATE_USER);
variables: { customerId }, const [updateUser] = useMutation(UPDATE_USER);
}); const [deleteUser] = useMutation(DELETE_USER);
const [createUser] = useMutation(CREATE_USER);
const [updateUser] = useMutation(UPDATE_USER);
const [deleteUser] = useMutation(DELETE_USER);
const handleLoadMore = () => { const handleLoadMore = () => {
if (!data.getAllUsers.context.lastPage) { if (!data.getAllUsers.context.lastPage) {
fetchMore({ fetchMore({
variables: { context: data.getAllUsers.context }, variables: { context: data.getAllUsers.context },
updateQuery: (previousResult, { fetchMoreResult }) => { updateQuery: (previousResult, { fetchMoreResult }) => {
const previousEntry = previousResult.getAllUsers; const previousEntry = previousResult.getAllUsers;
const newItems = fetchMoreResult.getAllUsers.items; const newItems = fetchMoreResult.getAllUsers.items;
return { return {
getAllUsers: { getAllUsers: {
context: fetchMoreResult.getAllUsers.context, context: fetchMoreResult.getAllUsers.context,
items: [...previousEntry.items, ...newItems], items: [...previousEntry.items, ...newItems],
__typename: previousEntry.__typename, __typename: previousEntry.__typename,
}, },
}; };
},
});
}
};
const handleCreateUser = (email, password, role) => {
createUser({
variables: {
username: email,
password,
role,
customerId,
}, },
});
}
};
const handleCreateUser = (email, password, role) => {
createUser({
variables: {
username: email,
password,
role,
customerId,
},
})
.then(() => {
refetch();
notification.success({
message: 'Success',
description: 'Account successfully created.',
});
}) })
.catch(() => .then(() => {
notification.error({ refetch();
message: 'Error', notification.success({
description: 'Account could not be created.', message: 'Success',
description: 'Account successfully created.',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Account could not be created.',
})
);
};
const handleEditUser = (id, email, password, role, lastModifiedTimestamp) => { const handleEditUser = (id, email, password, role, lastModifiedTimestamp) => {
updateUser({ updateUser({
variables: { variables: {
id, id,
username: email, username: email,
password, password,
role, role,
customerId, customerId,
lastModifiedTimestamp, lastModifiedTimestamp,
}, },
})
.then(() => {
refetch();
notification.success({
message: 'Success',
description: 'Account successfully updated.',
});
}) })
.catch(() => .then(() => {
notification.error({ refetch();
message: 'Error', notification.success({
description: 'Account could not be updated.', message: 'Success',
description: 'Account successfully updated.',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Account could not be updated.',
})
);
};
const handleDeleteUser = id => { const handleDeleteUser = id => {
deleteUser({ variables: { id } }) deleteUser({ variables: { id } })
.then(() => { .then(() => {
refetch(); refetch();
notification.success({ notification.success({
message: 'Success', message: 'Success',
description: 'Account successfully deleted.', description: 'Account successfully deleted.',
}); });
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Account could not be deleted.',
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Account could not be deleted.',
})
);
};
if (loading) { return (
return <Loading />; <AccountsPage
data={data.getAllUsers.items}
onLoadMore={handleLoadMore}
onCreateUser={handleCreateUser}
onEditUser={handleEditUser}
onDeleteUser={handleDeleteUser}
isLastPage={data.getAllUsers.context.lastPage}
/>
);
},
GET_ALL_USERS,
() => {
const { customerId } = useContext(UserContext);
return { customerId };
} }
);
if (error) {
return <Alert message="Error" description="Failed to load Users." type="error" showIcon />;
}
return (
<AccountsPage
data={data.getAllUsers.items}
onLoadMore={handleLoadMore}
onCreateUser={handleCreateUser}
onEditUser={handleEditUser}
onDeleteUser={handleDeleteUser}
isLastPage={data.getAllUsers.context.lastPage}
/>
);
};
export default Accounts; export default Accounts;

View File

@@ -1,7 +1,8 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useQuery, gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import { Alarms as AlarmsPage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { Alarms as AlarmsPage } from '@tip-wlan/wlan-cloud-ui-library';
import { withQuery } from 'containers/QueryWrapper';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
@@ -23,65 +24,58 @@ const GET_ALL_ALARMS = gql`
} }
`; `;
const Alarms = () => { const Alarms = withQuery(
const { customerId } = useContext(UserContext); ({ data, refetch, fetchMore }) => {
const { loading, error, data, refetch, fetchMore } = useQuery(GET_ALL_ALARMS, { const handleOnReload = () => {
variables: { customerId }, refetch()
errorPolicy: 'all', .then(() => {
}); notification.success({
message: 'Success',
const handleOnReload = () => { description: 'Alarms reloaded.',
refetch() });
.then(() => {
notification.success({
message: 'Success',
description: 'Alarms reloaded.',
});
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Alarms could not be reloaded.',
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Alarms could not be reloaded.',
})
);
};
const handleLoadMore = () => { const handleLoadMore = () => {
if (!data.getAllAlarms.context.lastPage) { if (!data.getAllAlarms.context.lastPage) {
fetchMore({ fetchMore({
variables: { context: data.getAllAlarms.context }, variables: { context: data.getAllAlarms.context },
updateQuery: (previousResult, { fetchMoreResult }) => { updateQuery: (previousResult, { fetchMoreResult }) => {
const previousEntry = previousResult.getAllAlarms; const previousEntry = previousResult.getAllAlarms;
const newItems = fetchMoreResult.getAllAlarms.items; const newItems = fetchMoreResult.getAllAlarms.items;
return { return {
getAllAlarms: { getAllAlarms: {
context: fetchMoreResult.getAllAlarms.context, context: fetchMoreResult.getAllAlarms.context,
items: [...previousEntry.items, ...newItems], items: [...previousEntry.items, ...newItems],
__typename: previousEntry.__typename, __typename: previousEntry.__typename,
}, },
}; };
}, },
}); });
} }
}; };
if (loading) { return (
return <Loading />; <AlarmsPage
data={data.getAllAlarms.items}
onReload={handleOnReload}
onLoadMore={handleLoadMore}
isLastPage={data.getAllAlarms.context.lastPage}
/>
);
},
GET_ALL_ALARMS,
() => {
const { customerId } = useContext(UserContext);
return { customerId, errorPolicy: 'all' };
} }
);
if (error && !data?.getAllAlarms?.items) {
return <Alert message="Error" description="Failed to load alarms." type="error" showIcon />;
}
return (
<AlarmsPage
data={data.getAllAlarms.items}
onReload={handleOnReload}
onLoadMore={handleLoadMore}
isLastPage={data.getAllAlarms.context.lastPage}
/>
);
};
export default Alarms; export default Alarms;

View File

@@ -1,10 +1,10 @@
import React, { useContext, useEffect, useMemo, useState, useRef } from 'react'; import React, { useContext, useEffect, useMemo, useState, useRef } from 'react';
import { Alert } from 'antd';
import moment from 'moment'; import moment from 'moment';
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { Dashboard as DashboardPage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { Dashboard as DashboardPage } from '@tip-wlan/wlan-cloud-ui-library';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { FILTER_SYSTEM_EVENTS, GET_ALL_STATUS } from 'graphql/queries'; import { FILTER_SYSTEM_EVENTS, GET_ALL_STATUS } from 'graphql/queries';
import { withQuery } from 'containers/QueryWrapper';
function formatBytes(bytes, decimals = 2) { function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes'; if (bytes === 0) return '0 Bytes';
@@ -46,242 +46,242 @@ const lineChartConfig = [
}, },
]; ];
const Dashboard = () => { const Dashboard = withQuery(
const initialGraphTime = useRef({ ({ data }) => {
toTime: moment() const { customerId } = useContext(UserContext);
.valueOf() const initialGraphTime = useRef({
.toString(), toTime: moment()
fromTime: moment() .valueOf()
.subtract(24, 'hours') .toString(),
.valueOf() fromTime: moment()
.toString(), .subtract(24, 'hours')
}); .valueOf()
const { customerId } = useContext(UserContext); .toString(),
const { loading, error, data } = useQuery(GET_ALL_STATUS, { });
variables: { customerId, statusDataTypes: ['CUSTOMER_DASHBOARD'] },
});
const [lineChartData, setLineChartData] = useState({ const [lineChartData, setLineChartData] = useState({
inservicesAPs: { inservicesAPs: {
key: 'Inservice APs', key: 'Inservice APs',
value: [],
},
clientDevices: {
is2dot4GHz: {
key: USER_FRIENDLY_RADIOS.is2dot4GHz,
value: [], value: [],
}, },
is5GHz: { clientDevices: {
key: USER_FRIENDLY_RADIOS.is5GHz, is2dot4GHz: {
value: [], key: USER_FRIENDLY_RADIOS.is2dot4GHz,
value: [],
},
is5GHz: {
key: USER_FRIENDLY_RADIOS.is5GHz,
value: [],
},
}, },
}, traffic: {
traffic: { trafficBytesDownstream: {
trafficBytesDownstream: { key: 'Down Stream',
key: 'Down Stream', value: [],
value: [], },
trafficBytesUpstream: {
key: 'Up Stream',
value: [],
},
}, },
trafficBytesUpstream: { });
key: 'Up Stream',
value: [],
},
},
});
const { loading: metricsLoading, error: metricsError, data: metricsData, fetchMore } = useQuery( const { loading: metricsLoading, error: metricsError, data: metricsData, fetchMore } = useQuery(
FILTER_SYSTEM_EVENTS, FILTER_SYSTEM_EVENTS,
{ {
variables: { variables: {
customerId, customerId,
fromTime: initialGraphTime.current.fromTime, fromTime: initialGraphTime.current.fromTime,
toTime: initialGraphTime.current.toTime, toTime: initialGraphTime.current.toTime,
equipmentIds: [0], equipmentIds: [0],
dataTypes: ['StatusChangedEvent'], dataTypes: ['StatusChangedEvent'],
limit: 3000, // TODO: make get all in GraphQL limit: 3000, // TODO: make get all in GraphQL
}, },
} }
); );
const formatLineChartData = (list = []) => { const formatLineChartData = (list = []) => {
if (list.length) { if (list.length) {
setLineChartData(prev => { setLineChartData(prev => {
const inservicesAPs = []; const inservicesAPs = [];
const clientDevices2dot4GHz = []; const clientDevices2dot4GHz = [];
const clientDevices5GHz = []; const clientDevices5GHz = [];
const trafficBytesDownstreamData = []; const trafficBytesDownstreamData = [];
const trafficBytesUpstreamData = []; const trafficBytesUpstreamData = [];
let totalDown = 0; let totalDown = 0;
let totalUp = 0; let totalUp = 0;
list.forEach( list.forEach(
({ ({
eventTimestamp, eventTimestamp,
details: { details: {
payload: { payload: {
details: { details: {
equipmentInServiceCount, equipmentInServiceCount,
associatedClientsCountPerRadio: radios, associatedClientsCountPerRadio: radios,
trafficBytesDownstream, trafficBytesDownstream,
trafficBytesUpstream, 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 || 0]);
trafficBytesDownstreamData.push([eventTimestamp, trafficBytesDownstream || 0]);
trafficBytesUpstreamData.push([eventTimestamp, trafficBytesUpstream || 0]);
totalDown += trafficBytesDownstream || 0;
totalUp += trafficBytesUpstream || 0;
}
);
return {
inservicesAPs: {
...prev.inservicesAPs,
value: [...prev.inservicesAPs.value, ...inservicesAPs],
}, },
}) => { clientDevices: {
inservicesAPs.push([eventTimestamp, equipmentInServiceCount]); is2dot4GHz: {
...prev.clientDevices.is2dot4GHz,
let total5GHz = 0; value: [...prev.clientDevices.is2dot4GHz.value, ...clientDevices2dot4GHz],
total5GHz += (radios?.is5GHz || 0) + (radios?.is5GHzL || 0) + (radios?.is5GHzU || 0); // combine all 5GHz radios },
is5GHz: {
clientDevices2dot4GHz.push([eventTimestamp, radios.is2dot4GHz || 0]); ...prev.clientDevices.is5GHz,
clientDevices5GHz.push([eventTimestamp, total5GHz || 0]); value: [...prev.clientDevices.is5GHz.value, ...clientDevices5GHz],
},
trafficBytesDownstreamData.push([eventTimestamp, trafficBytesDownstream || 0]);
trafficBytesUpstreamData.push([eventTimestamp, trafficBytesUpstream || 0]);
totalDown += trafficBytesDownstream || 0;
totalUp += trafficBytesUpstream || 0;
}
);
return {
inservicesAPs: {
...prev.inservicesAPs,
value: [...prev.inservicesAPs.value, ...inservicesAPs],
},
clientDevices: {
is2dot4GHz: {
...prev.clientDevices.is2dot4GHz,
value: [...prev.clientDevices.is2dot4GHz.value, ...clientDevices2dot4GHz],
}, },
is5GHz: { traffic: {
...prev.clientDevices.is5GHz, trafficBytesDownstream: {
value: [...prev.clientDevices.is5GHz.value, ...clientDevices5GHz], ...prev.traffic.trafficBytesDownstream,
value: [
...prev.traffic.trafficBytesDownstream.value,
...trafficBytesDownstreamData,
],
},
trafficBytesUpstream: {
...prev.traffic.trafficBytesUpstream,
value: [...prev.traffic.trafficBytesUpstream.value, ...trafficBytesUpstreamData],
},
}, },
}, totalDownstreamTraffic: totalDown,
traffic: { totalUpstreamTraffic: totalUp,
trafficBytesDownstream: { };
...prev.traffic.trafficBytesDownstream, });
value: [...prev.traffic.trafficBytesDownstream.value, ...trafficBytesDownstreamData], }
},
trafficBytesUpstream: {
...prev.traffic.trafficBytesUpstream,
value: [...prev.traffic.trafficBytesUpstream.value, ...trafficBytesUpstreamData],
},
},
totalDownstreamTraffic: totalDown,
totalUpstreamTraffic: totalUp,
};
});
}
};
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 statsData = useMemo(() => {
const status = data?.getAllStatus?.items[0]?.detailsJSON || {};
const {
associatedClientsCountPerRadio,
totalProvisionedEquipment,
equipmentInServiceCount,
equipmentWithClientsCount,
} = status;
const clientRadios = {};
let totalAssociated = 0;
if (associatedClientsCountPerRadio) {
Object.keys(associatedClientsCountPerRadio).forEach(i => {
if (i.includes('5GHz')) {
if (!clientRadios['5GHz']) {
clientRadios['5GHz'] = 0;
}
clientRadios['5GHz'] += associatedClientsCountPerRadio[i];
} else {
const key = USER_FRIENDLY_RADIOS[i] || i;
clientRadios[key] = associatedClientsCountPerRadio[i];
}
totalAssociated += associatedClientsCountPerRadio[i];
});
}
return {
totalProvisionedEquipment,
equipmentInServiceCount,
equipmentWithClientsCount,
totalAssociated,
clientRadios,
}; };
}, [data]);
const pieChartsData = useMemo(() => { useEffect(() => {
const { clientCountPerOui, equipmentCountPerOui } = data?.getAllStatus?.items[0]?.details || {}; 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 [ return () => clearInterval(interval);
{ title: 'AP Vendors', ...equipmentCountPerOui }, }, []);
{ title: 'Client Vendors', ...clientCountPerOui },
];
}, [data]);
if (loading) { useEffect(() => {
return <Loading />; formatLineChartData(metricsData?.filterSystemEvents?.items);
}, [metricsData]);
const statsData = useMemo(() => {
const status = data?.getAllStatus?.items[0]?.detailsJSON || {};
const {
associatedClientsCountPerRadio,
totalProvisionedEquipment,
equipmentInServiceCount,
equipmentWithClientsCount,
} = status;
const clientRadios = {};
let totalAssociated = 0;
if (associatedClientsCountPerRadio) {
Object.keys(associatedClientsCountPerRadio).forEach(i => {
if (i.includes('5GHz')) {
if (!clientRadios['5GHz']) {
clientRadios['5GHz'] = 0;
}
clientRadios['5GHz'] += associatedClientsCountPerRadio[i];
} else {
const key = USER_FRIENDLY_RADIOS[i] || i;
clientRadios[key] = associatedClientsCountPerRadio[i];
}
totalAssociated += associatedClientsCountPerRadio[i];
});
}
return {
totalProvisionedEquipment,
equipmentInServiceCount,
equipmentWithClientsCount,
totalAssociated,
clientRadios,
};
}, [data]);
const pieChartsData = useMemo(() => {
const { clientCountPerOui, equipmentCountPerOui } =
data?.getAllStatus?.items[0]?.details || {};
return [
{ title: 'AP Vendors', ...equipmentCountPerOui },
{ title: 'Client Vendors', ...clientCountPerOui },
];
}, [data]);
return (
<DashboardPage
statsCardDetails={[
{
title: 'Access Point',
'Total Provisioned': statsData?.totalProvisionedEquipment,
'In Service': statsData?.equipmentInServiceCount,
'With Clients': statsData?.equipmentWithClientsCount,
},
{
title: 'Client Devices',
'Total Associated': statsData?.totalAssociated,
...statsData?.clientRadios,
},
{
title: 'Usage Information (24 hours)',
'Total Traffic (US)': formatBytes(lineChartData?.totalUpstreamTraffic),
'Total Traffic (DS)': formatBytes(lineChartData?.totalDownstreamTraffic),
},
]}
pieChartDetails={pieChartsData}
lineChartData={lineChartData}
lineChartConfig={lineChartConfig}
lineChartLoading={metricsLoading}
lineChartError={metricsError}
/>
);
},
GET_ALL_STATUS,
() => {
const { customerId } = useContext(UserContext);
return { customerId, statusDataTypes: ['CUSTOMER_DASHBOARD'] };
} }
);
if (error) {
return <Alert message="Error" description="Failed to load Dashboard" type="error" showIcon />;
}
return (
<DashboardPage
statsCardDetails={[
{
title: 'Access Point',
'Total Provisioned': statsData?.totalProvisionedEquipment,
'In Service': statsData?.equipmentInServiceCount,
'With Clients': statsData?.equipmentWithClientsCount,
},
{
title: 'Client Devices',
'Total Associated': statsData?.totalAssociated,
...statsData?.clientRadios,
},
{
title: 'Usage Information (24 hours)',
'Total Traffic (US)': formatBytes(lineChartData?.totalUpstreamTraffic),
'Total Traffic (DS)': formatBytes(lineChartData?.totalDownstreamTraffic),
},
]}
pieChartDetails={pieChartsData}
lineChartData={lineChartData}
lineChartConfig={lineChartConfig}
lineChartLoading={metricsLoading}
lineChartError={metricsError}
/>
);
};
export default Dashboard; export default Dashboard;

View File

@@ -1,7 +1,8 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useMutation, useQuery, gql } from '@apollo/client'; import { useMutation, gql } from '@apollo/client';
import { notification, Alert } from 'antd'; import { notification } from 'antd';
import { EditAccount as EditAccountPage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { EditAccount as EditAccountPage } from '@tip-wlan/wlan-cloud-ui-library';
import { withQuery } from 'containers/QueryWrapper';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
@@ -43,47 +44,45 @@ const UPDATE_USER = gql`
} }
`; `;
const EditAccount = () => { const EditAccount = withQuery(
const { id, email } = useContext(UserContext); ({ data }) => {
const { loading, error, data } = useQuery(GET_USER, { variables: { id } }); const { id, email } = useContext(UserContext);
const [updateUser] = useMutation(UPDATE_USER); const [updateUser] = useMutation(UPDATE_USER);
const handleSubmit = newPassword => { const handleSubmit = newPassword => {
const { role, customerId, lastModifiedTimestamp } = data.getUser; const { role, customerId, lastModifiedTimestamp } = data.getUser;
updateUser({ updateUser({
variables: { variables: {
id, id,
username: email, username: email,
password: newPassword, password: newPassword,
role, role,
customerId, customerId,
lastModifiedTimestamp, lastModifiedTimestamp,
}, },
})
.then(() => {
notification.success({
message: 'Success',
description: 'Password successfully updated.',
});
}) })
.catch(() => .then(() => {
notification.error({ notification.success({
message: 'Error', message: 'Success',
description: 'Password could not be updated.', description: 'Password successfully updated.',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Password could not be updated.',
})
);
};
if (loading) { return <EditAccountPage onSubmit={handleSubmit} email={email} />;
return <Loading />; },
GET_USER,
() => {
const { id } = useContext(UserContext);
return { id };
} }
);
if (error) {
return <Alert message="Error" description="Failed to load User." type="error" showIcon />;
}
return <EditAccountPage onSubmit={handleSubmit} email={email} />;
};
export default EditAccount; export default EditAccount;

View File

@@ -2,12 +2,9 @@ import React, { useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useQuery, useMutation, gql } from '@apollo/client'; import { useQuery, useMutation, gql } from '@apollo/client';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import moment from 'moment'; import moment from 'moment';
import { import { AccessPointDetails as AccessPointDetailsPage } from '@tip-wlan/wlan-cloud-ui-library';
AccessPointDetails as AccessPointDetailsPage,
Loading,
} from '@tip-wlan/wlan-cloud-ui-library';
import { FILTER_SERVICE_METRICS, GET_ALL_FIRMWARE, GET_ALL_PROFILES } from 'graphql/queries'; import { FILTER_SERVICE_METRICS, GET_ALL_FIRMWARE, GET_ALL_PROFILES } from 'graphql/queries';
import { import {
@@ -17,6 +14,7 @@ import {
} from 'graphql/mutations'; } from 'graphql/mutations';
import { updateQueryGetAllProfiles } from 'graphql/functions'; import { updateQueryGetAllProfiles } from 'graphql/functions';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { withQuery } from 'containers/QueryWrapper';
const GET_EQUIPMENT = gql` const GET_EQUIPMENT = gql`
query GetEquipment($id: ID!) { query GetEquipment($id: ID!) {
@@ -126,236 +124,222 @@ const UPDATE_EQUIPMENT = gql`
const toTime = moment(); const toTime = moment();
const fromTime = moment().subtract(1, 'hour'); const fromTime = moment().subtract(1, 'hour');
const AccessPointDetails = ({ locations }) => { const AccessPointDetails = withQuery(
const { id } = useParams(); ({ data, refetch, locations }) => {
const { customerId } = useContext(UserContext); const { id } = useParams();
const { customerId } = useContext(UserContext);
const { loading, error, data, refetch } = useQuery(GET_EQUIPMENT, { const { data: dataFirmware, error: errorFirmware, loading: loadingFirmware } = useQuery(
variables: { GET_ALL_FIRMWARE,
id, {
}, skip: !data?.getEquipment?.model,
}); variables: { modelId: data?.getEquipment?.model },
}
);
const { data: dataFirmware, error: errorFirmware, loading: loadingFirmware } = useQuery( const {
GET_ALL_FIRMWARE, data: dataProfiles,
{ error: errorProfiles,
skip: !data?.getEquipment?.model, loading: loadingProfiles,
variables: { modelId: data?.getEquipment?.model }, fetchMore,
} } = useQuery(
); GET_ALL_PROFILES(`
const {
data: dataProfiles,
error: errorProfiles,
loading: loadingProfiles,
fetchMore,
} = useQuery(
GET_ALL_PROFILES(`
childProfiles { childProfiles {
id id
name name
details details
}`), }`),
{ {
variables: { customerId, type: 'equipment_ap' }, variables: { customerId, type: 'equipment_ap' },
} }
); );
const { const {
loading: metricsLoading, loading: metricsLoading,
error: metricsError, error: metricsError,
data: metricsData, data: metricsData,
refetch: metricsRefetch, refetch: metricsRefetch,
} = useQuery(FILTER_SERVICE_METRICS, { } = useQuery(FILTER_SERVICE_METRICS, {
variables: {
customerId,
fromTime: fromTime.valueOf().toString(),
toTime: toTime.valueOf().toString(),
equipmentIds: [id],
dataTypes: ['ApNode'],
limit: 100,
},
});
const [updateEquipment] = useMutation(UPDATE_EQUIPMENT);
const [updateEquipmentFirmware] = useMutation(UPDATE_EQUIPMENT_FIRMWARE);
const [requestEquipmentSwitchBank] = useMutation(REQUEST_EQUIPMENT_SWITCH_BANK);
const [requestEquipmentReboot] = useMutation(REQUEST_EQUIPMENT_REBOOT);
const refetchData = () => {
refetch();
metricsRefetch();
};
const handleUpdateEquipment = (
equipmentId,
equipmentType,
inventoryId,
custId,
profileId,
locationId,
name,
latitude,
longitude,
serial,
lastModifiedTimestamp,
details
) => {
updateEquipment({
variables: { variables: {
id: equipmentId, customerId,
equipmentType, fromTime: fromTime.valueOf().toString(),
inventoryId, toTime: toTime.valueOf().toString(),
customerId: custId, equipmentIds: [id],
profileId, dataTypes: ['ApNode'],
locationId, limit: 100,
name,
latitude,
longitude,
serial,
lastModifiedTimestamp,
details,
}, },
}) });
.then(() => {
notification.success({ const [updateEquipment] = useMutation(UPDATE_EQUIPMENT);
message: 'Success', const [updateEquipmentFirmware] = useMutation(UPDATE_EQUIPMENT_FIRMWARE);
description: 'Equipment settings successfully updated.', const [requestEquipmentSwitchBank] = useMutation(REQUEST_EQUIPMENT_SWITCH_BANK);
}); const [requestEquipmentReboot] = useMutation(REQUEST_EQUIPMENT_REBOOT);
const refetchData = () => {
refetch();
metricsRefetch();
};
const handleUpdateEquipment = (
equipmentId,
equipmentType,
inventoryId,
custId,
profileId,
locationId,
name,
latitude,
longitude,
serial,
lastModifiedTimestamp,
details
) => {
updateEquipment({
variables: {
id: equipmentId,
equipmentType,
inventoryId,
customerId: custId,
profileId,
locationId,
name,
latitude,
longitude,
serial,
lastModifiedTimestamp,
details,
},
}) })
.then(() => {
.catch(() =>
notification.error({
message: 'Error',
description: 'Equipment settings could not be updated.',
})
);
};
const handleUpdateEquipmentFirmware = (equipmentId, firmwareVersionId) =>
updateEquipmentFirmware({ variables: { equipmentId, firmwareVersionId } })
.then(firmwareResp => {
if (firmwareResp?.data?.updateEquipmentFirmware?.success === true) {
notification.success({ notification.success({
message: 'Success', message: 'Success',
description: 'Equipment Firmware Upgrade in progress', description: 'Equipment settings successfully updated.',
}); });
} else { })
.catch(() =>
notification.error({
message: 'Error',
description: 'Equipment settings could not be updated.',
})
);
};
const handleUpdateEquipmentFirmware = (equipmentId, firmwareVersionId) =>
updateEquipmentFirmware({ variables: { equipmentId, firmwareVersionId } })
.then(firmwareResp => {
if (firmwareResp?.data?.updateEquipmentFirmware?.success === true) {
notification.success({
message: 'Success',
description: 'Equipment Firmware Upgrade in progress',
});
} else {
notification.error({
message: 'Error',
description: 'Equipment Firmware Upgrade could not be updated.',
});
}
})
.catch(() =>
notification.error({ notification.error({
message: 'Error', message: 'Error',
description: 'Equipment Firmware Upgrade could not be updated.', description: 'Equipment Firmware Upgrade could not be updated.',
}); })
} );
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Equipment Firmware Upgrade could not be updated.',
})
);
const handleRequestEquipmentSwitchBank = equipmentId => const handleRequestEquipmentSwitchBank = equipmentId =>
requestEquipmentSwitchBank({ variables: { equipmentId } }) requestEquipmentSwitchBank({ variables: { equipmentId } })
.then(firmwareResp => { .then(firmwareResp => {
if (firmwareResp?.data?.requestEquipmentSwitchBank?.success === true) { if (firmwareResp?.data?.requestEquipmentSwitchBank?.success === true) {
notification.success({ notification.success({
message: 'Success', message: 'Success',
description: 'Equipment Firmware in progress', description: 'Equipment Firmware in progress',
}); });
} else { } else {
notification.error({
message: 'Error',
description: 'Equipment Firmware could not be updated.',
});
}
})
.catch(() =>
notification.error({ notification.error({
message: 'Error', message: 'Error',
description: 'Equipment Firmware could not be updated.', description: 'Equipment Firmware could not be updated.',
}); })
} );
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Equipment Firmware could not be updated.',
})
);
const handleRequestEquipmentReboot = equipmentId => const handleRequestEquipmentReboot = equipmentId =>
requestEquipmentReboot({ variables: { equipmentId } }) requestEquipmentReboot({ variables: { equipmentId } })
.then(firmwareResp => { .then(firmwareResp => {
if (firmwareResp?.data?.requestEquipmentReboot?.success === true) { if (firmwareResp?.data?.requestEquipmentReboot?.success === true) {
notification.success({ notification.success({
message: 'Success', message: 'Success',
description: 'Equipment Firmware in progress', description: 'Equipment Firmware in progress',
}); });
} else { } else {
notification.error({
message: 'Error',
description: 'Equipment Firmware could not be updated.',
});
}
})
.catch(() =>
notification.error({ notification.error({
message: 'Error', message: 'Error',
description: 'Equipment Firmware could not be updated.', description: 'Equipment Firmware could not be updated.',
}); })
} );
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Equipment Firmware could not be updated.',
})
);
const handleFetchProfiles = e => { const handleFetchProfiles = e => {
if (dataProfiles.getAllProfiles.context.lastPage) { if (dataProfiles.getAllProfiles.context.lastPage) {
return false; return false;
} }
e.persist(); e.persist();
const { target } = e; const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) { if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMore({ fetchMore({
variables: { context: { ...dataProfiles.getAllProfiles.context } }, variables: { context: { ...dataProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles, updateQuery: updateQueryGetAllProfiles,
}); });
} }
return true; return true;
}; };
if (loading) {
return <Loading />;
}
if (error) {
return ( return (
<Alert <AccessPointDetailsPage
message="Error" handleRefresh={refetchData}
description="Failed to load Access Point data." onUpdateEquipment={handleUpdateEquipment}
type="error" data={data?.getEquipment}
showIcon profiles={dataProfiles?.getAllProfiles?.items}
osData={{
loading: metricsLoading,
error: metricsError,
data: metricsData && metricsData.filterServiceMetrics.items,
}}
firmware={dataFirmware?.getAllFirmware}
locations={locations}
onUpdateEquipmentFirmware={handleUpdateEquipmentFirmware}
onRequestEquipmentSwitchBank={handleRequestEquipmentSwitchBank}
onRequestEquipmentReboot={handleRequestEquipmentReboot}
loadingProfiles={loadingProfiles}
errorProfiles={errorProfiles}
loadingFirmware={loadingFirmware}
errorFirmware={errorFirmware}
onFetchMoreProfiles={handleFetchProfiles}
isLastProfilesPage={dataProfiles?.getAllProfiles?.context?.lastPage}
/> />
); );
},
GET_EQUIPMENT,
() => {
const { id } = useParams();
return { id };
} }
);
return (
<AccessPointDetailsPage
handleRefresh={refetchData}
onUpdateEquipment={handleUpdateEquipment}
data={data?.getEquipment}
profiles={dataProfiles?.getAllProfiles?.items}
osData={{
loading: metricsLoading,
error: metricsError,
data: metricsData && metricsData.filterServiceMetrics.items,
}}
firmware={dataFirmware?.getAllFirmware}
locations={locations}
onUpdateEquipmentFirmware={handleUpdateEquipmentFirmware}
onRequestEquipmentSwitchBank={handleRequestEquipmentSwitchBank}
onRequestEquipmentReboot={handleRequestEquipmentReboot}
loadingProfiles={loadingProfiles}
errorProfiles={errorProfiles}
loadingFirmware={loadingFirmware}
errorFirmware={errorFirmware}
onFetchMoreProfiles={handleFetchProfiles}
isLastProfilesPage={dataProfiles?.getAllProfiles?.context?.lastPage}
/>
);
};
AccessPointDetails.propTypes = { AccessPointDetails.propTypes = {
locations: PropTypes.instanceOf(Array).isRequired, locations: PropTypes.instanceOf(Array).isRequired,

View File

@@ -1,7 +1,7 @@
import React, { useContext, useMemo } from 'react'; import React, { useContext, useMemo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Alert, notification } from 'antd'; import { Alert, notification } from 'antd';
import { useParams } from 'react-router-dom'; import { useParams, Redirect } from 'react-router-dom';
import { useQuery, useMutation } from '@apollo/client'; import { useQuery, useMutation } from '@apollo/client';
import { BulkEditAccessPoints, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { BulkEditAccessPoints, Loading } from '@tip-wlan/wlan-cloud-ui-library';
@@ -348,6 +348,12 @@ const BulkEditAPs = ({ locations, checkedLocations }) => {
} }
if (filterEquipmentError) { if (filterEquipmentError) {
if (
filterEquipmentError.message === '403: Forbidden' ||
filterEquipmentError.message === '401: Unauthorized'
) {
return <Redirect to="/login" />;
}
return ( return (
<Alert message="Error" description="Failed to load equipments data." type="error" showIcon /> <Alert message="Error" description="Failed to load equipments data." type="error" showIcon />
); );

View File

@@ -2,80 +2,73 @@ import React, { useContext } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import moment from 'moment'; import moment from 'moment';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import { import { ClientDeviceDetails as ClientDevicesDetailsPage } from '@tip-wlan/wlan-cloud-ui-library';
Loading,
ClientDeviceDetails as ClientDevicesDetailsPage,
} from '@tip-wlan/wlan-cloud-ui-library';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { GET_CLIENT_SESSION, FILTER_SERVICE_METRICS } from 'graphql/queries'; import { GET_CLIENT_SESSION, FILTER_SERVICE_METRICS } from 'graphql/queries';
import { withQuery } from 'containers/QueryWrapper';
const toTime = moment(); const toTime = moment();
const fromTime = moment().subtract(4, 'hours'); const fromTime = moment().subtract(4, 'hours');
const ClientDeviceDetails = () => { const ClientDeviceDetails = withQuery(
const { id } = useParams(); ({ data, refetch }) => {
const { customerId } = useContext(UserContext); const { id } = useParams();
const { loading, error, data, refetch } = useQuery(GET_CLIENT_SESSION, { const { customerId } = useContext(UserContext);
variables: { customerId, macAddress: id },
errorPolicy: 'all',
});
const {
loading: metricsLoading,
error: metricsError,
data: metricsData,
refetch: metricsRefetch,
} = useQuery(FILTER_SERVICE_METRICS, {
variables: {
customerId,
fromTime: fromTime.valueOf().toString(),
toTime: toTime.valueOf().toString(),
clientMacs: [id],
dataTypes: ['Client'],
limit: 1000,
},
});
const handleOnRefresh = () => { const {
metricsRefetch(); loading: metricsLoading,
refetch() error: metricsError,
.then(() => { data: metricsData,
notification.success({ refetch: metricsRefetch,
message: 'Success', } = useQuery(FILTER_SERVICE_METRICS, {
description: 'Successfully reloaded.', variables: {
}); customerId,
}) fromTime: fromTime.valueOf().toString(),
.catch(() => toTime: toTime.valueOf().toString(),
notification.error({ clientMacs: [id],
message: 'Error', dataTypes: ['Client'],
description: 'Could not be reloaded.', limit: 1000,
},
});
const handleOnRefresh = () => {
metricsRefetch();
refetch()
.then(() => {
notification.success({
message: 'Success',
description: 'Successfully reloaded.',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Could not be reloaded.',
})
);
};
if (loading) {
return <Loading />;
}
if (error && !data?.getClientSession) {
return ( return (
<Alert message="Error" description="Failed to load Client Device." type="error" showIcon /> <ClientDevicesDetailsPage
data={data.getClientSession[0]}
onRefresh={handleOnRefresh}
metricsLoading={metricsLoading}
metricsError={metricsError}
metricsData={
metricsData && metricsData.filterServiceMetrics && metricsData.filterServiceMetrics.items
}
historyDate={{ toTime, fromTime }}
/>
); );
},
GET_CLIENT_SESSION,
() => {
const { id } = useParams();
const { customerId } = useContext(UserContext);
return { customerId, macAddress: id, errorPolicy: 'all' };
} }
);
return (
<ClientDevicesDetailsPage
data={data.getClientSession[0]}
onRefresh={handleOnRefresh}
metricsLoading={metricsLoading}
metricsError={metricsError}
metricsData={
metricsData && metricsData.filterServiceMetrics && metricsData.filterServiceMetrics.items
}
historyDate={{ toTime, fromTime }}
/>
);
};
export default ClientDeviceDetails; export default ClientDeviceDetails;

View File

@@ -1,15 +1,16 @@
import React, { useMemo, useContext, useState } from 'react'; import React, { useMemo, useContext, useState } from 'react';
import { Switch, Route, useRouteMatch, Redirect } from 'react-router-dom'; import { Switch, Route, useRouteMatch, Redirect } from 'react-router-dom';
import { useQuery, useMutation, useLazyQuery } from '@apollo/client'; import { useQuery, useMutation, useLazyQuery } from '@apollo/client';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import { Network as NetworkPage, PopoverMenu, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { Network as NetworkPage, PopoverMenu } from '@tip-wlan/wlan-cloud-ui-library';
import AccessPointDetails from 'containers/Network/containers/AccessPointDetails'; import AccessPointDetails from 'containers/Network/containers/AccessPointDetails';
import AccessPoints from 'containers/Network/containers/AccessPoints'; import AccessPoints from 'containers/Network/containers/AccessPoints';
import ClientDevices from 'containers/Network/containers/ClientDevices'; import ClientDevices from 'containers/Network/containers/ClientDevices';
import ClientDeviceDetails from 'containers/Network/containers/ClientDeviceDetails'; import ClientDeviceDetails from 'containers/Network/containers/ClientDeviceDetails';
import BulkEditAccessPoints from 'containers/Network/containers/BulkEditAccessPoints'; import BulkEditAccessPoints from 'containers/Network/containers/BulkEditAccessPoints';
import { withQuery } from 'containers/QueryWrapper';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { import {
@@ -26,301 +27,300 @@ import {
} from 'graphql/mutations'; } from 'graphql/mutations';
import { updateQueryGetAllProfiles } from 'graphql/functions'; import { updateQueryGetAllProfiles } from 'graphql/functions';
const Network = () => { const Network = withQuery(
const { path } = useRouteMatch(); ({ data, refetch }) => {
const { customerId } = useContext(UserContext); const { path } = useRouteMatch();
const { loading, error, refetch, data } = useQuery(GET_ALL_LOCATIONS, { const { customerId } = useContext(UserContext);
variables: { customerId },
});
const { loading: loadingProfile, error: errorProfile, data: apProfiles, fetchMore } = useQuery(
GET_ALL_PROFILES(),
{
variables: { customerId, type: 'equipment_ap' },
}
);
const [getLocation, { data: selectedLocation }] = useLazyQuery(GET_LOCATION); const { loading: loadingProfile, error: errorProfile, data: apProfiles, fetchMore } = useQuery(
const [createLocation] = useMutation(CREATE_LOCATION); GET_ALL_PROFILES(),
const [updateLocation] = useMutation(UPDATE_LOCATION);
const [deleteLocation] = useMutation(DELETE_LOCATION);
const [checkedLocations, setCheckedLocations] = useState([]);
const [deleteModal, setDeleteModal] = useState(false);
const [editModal, setEditModal] = useState(false);
const [addModal, setAddModal] = useState(false);
const [apModal, setApModal] = useState(false);
const [createEquipment] = useMutation(CREATE_EQUIPMENT, {
refetchQueries: [
{ {
query: FILTER_EQUIPMENT, variables: { customerId, type: 'equipment_ap' },
variables: { customerId, locationIds: checkedLocations, equipmentType: 'AP' },
},
],
});
const handleGetSingleLocation = id => {
getLocation({
variables: { id },
});
};
const formatLocationListForTree = (list = []) => {
const checkedTreeLocations = ['0'];
list.forEach(ele => {
checkedTreeLocations.push(ele.id);
});
setCheckedLocations(checkedTreeLocations);
function unflatten(array, p, t) {
let tree = typeof t !== 'undefined' ? t : [];
const parent = typeof p !== 'undefined' ? p : { id: '0' };
let children = _.filter(array, child => child.parentId === parent.id);
children = children.map(c => ({
title: (
<PopoverMenu
locationId={c.id}
locationType={c.locationType}
setAddModal={setAddModal}
setEditModal={setEditModal}
setDeleteModal={setDeleteModal}
setApModal={setApModal}
>
{c.name}
</PopoverMenu>
),
value: `${c.id}`,
key: c.id,
...c,
}));
if (!_.isEmpty(children)) {
if (parent.id === '0') {
tree = children;
} else {
parent.children = children;
}
_.each(children, child => unflatten(array, child));
} }
return tree; );
}
return [
{
title: (
<PopoverMenu locationId="0" locationType="NETWORK" setAddModal={setAddModal}>
Network
</PopoverMenu>
),
id: '0',
key: '0',
value: '0',
children: unflatten(list),
},
];
};
const handleAddLocation = ({ location }) => { const [getLocation, { data: selectedLocation }] = useLazyQuery(GET_LOCATION);
setAddModal(false); const [createLocation] = useMutation(CREATE_LOCATION);
let id; const [updateLocation] = useMutation(UPDATE_LOCATION);
let locationType; const [deleteLocation] = useMutation(DELETE_LOCATION);
const [checkedLocations, setCheckedLocations] = useState([]);
const [deleteModal, setDeleteModal] = useState(false);
const [editModal, setEditModal] = useState(false);
const [addModal, setAddModal] = useState(false);
const [apModal, setApModal] = useState(false);
// adding location from root makes selecetedLocation null so we check for that const [createEquipment] = useMutation(CREATE_EQUIPMENT, {
if (selectedLocation && selectedLocation.getLocation) { refetchQueries: [
id = selectedLocation.getLocation.id; {
locationType = 'SITE'; query: FILTER_EQUIPMENT,
} else { variables: { customerId, locationIds: checkedLocations, equipmentType: 'AP' },
id = '0'; },
locationType = 'COUNTRY'; ],
} });
createLocation({ const handleGetSingleLocation = id => {
variables: { getLocation({
locationType, variables: { id },
customerId,
parentId: id,
name: location,
},
})
.then(() => {
notification.success({
message: 'Success',
description: 'Location successfully added.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Location could not be added.',
})
);
};
const handleEditLocation = ({ name }) => {
setEditModal(false);
const { id, parentId, locationType, lastModifiedTimestamp } = selectedLocation.getLocation;
updateLocation({
variables: {
customerId,
id,
parentId,
name,
locationType,
lastModifiedTimestamp,
},
})
.then(() => {
notification.success({
message: 'Success',
description: 'Location successfully edited.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Location could not be edited.',
})
);
};
const handleDeleteLocation = () => {
setDeleteModal(false);
const { id } = selectedLocation.getLocation;
deleteLocation({ variables: { id } })
.then(() => {
notification.success({
message: 'Success',
description: 'Location successfully deleted.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Location could not be deleted.',
})
);
};
const handleCreateEquipment = ({ inventoryId, name, profileId }) => {
setApModal(false);
const { id: locationId } = selectedLocation.getLocation;
createEquipment({ variables: { customerId, inventoryId, locationId, name, profileId } })
.then(() => {
notification.success({
message: 'Success',
description: 'Equipment successfully created.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Equipment could not be created.',
})
);
};
const onSelect = (selectedKeys, info) => {
const { id } = info.node;
handleGetSingleLocation(id);
};
const onCheck = checkedKeys => {
setCheckedLocations(checkedKeys.checked);
};
const handleFetchProfiles = e => {
if (apProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMore({
variables: { context: { ...apProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
}); });
} };
return true; const formatLocationListForTree = (list = []) => {
}; const checkedTreeLocations = ['0'];
list.forEach(ele => {
checkedTreeLocations.push(ele.id);
});
setCheckedLocations(checkedTreeLocations);
const locationsTree = useMemo(() => formatLocationListForTree(data && data.getAllLocations), [ function unflatten(array, p, t) {
data, let tree = typeof t !== 'undefined' ? t : [];
]); const parent = typeof p !== 'undefined' ? p : { id: '0' };
let children = _.filter(array, child => child.parentId === parent.id);
children = children.map(c => ({
title: (
<PopoverMenu
locationId={c.id}
locationType={c.locationType}
setAddModal={setAddModal}
setEditModal={setEditModal}
setDeleteModal={setDeleteModal}
setApModal={setApModal}
>
{c.name}
</PopoverMenu>
),
value: `${c.id}`,
key: c.id,
...c,
}));
if (!_.isEmpty(children)) {
if (parent.id === '0') {
tree = children;
} else {
parent.children = children;
}
_.each(children, child => unflatten(array, child));
}
return tree;
}
return [
{
title: (
<PopoverMenu locationId="0" locationType="NETWORK" setAddModal={setAddModal}>
Network
</PopoverMenu>
),
id: '0',
key: '0',
value: '0',
children: unflatten(list),
},
];
};
if (loading) { const handleAddLocation = ({ location }) => {
return <Loading />; setAddModal(false);
let id;
let locationType;
// adding location from root makes selecetedLocation null so we check for that
if (selectedLocation && selectedLocation.getLocation) {
id = selectedLocation.getLocation.id;
locationType = 'SITE';
} else {
id = '0';
locationType = 'COUNTRY';
}
createLocation({
variables: {
locationType,
customerId,
parentId: id,
name: location,
},
})
.then(() => {
notification.success({
message: 'Success',
description: 'Location successfully added.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Location could not be added.',
})
);
};
const handleEditLocation = ({ name }) => {
setEditModal(false);
const { id, parentId, locationType, lastModifiedTimestamp } = selectedLocation.getLocation;
updateLocation({
variables: {
customerId,
id,
parentId,
name,
locationType,
lastModifiedTimestamp,
},
})
.then(() => {
notification.success({
message: 'Success',
description: 'Location successfully edited.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Location could not be edited.',
})
);
};
const handleDeleteLocation = () => {
setDeleteModal(false);
const { id } = selectedLocation.getLocation;
deleteLocation({ variables: { id } })
.then(() => {
notification.success({
message: 'Success',
description: 'Location successfully deleted.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Location could not be deleted.',
})
);
};
const handleCreateEquipment = ({ inventoryId, name, profileId }) => {
setApModal(false);
const { id: locationId } = selectedLocation.getLocation;
createEquipment({ variables: { customerId, inventoryId, locationId, name, profileId } })
.then(() => {
notification.success({
message: 'Success',
description: 'Equipment successfully created.',
});
refetch();
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Equipment could not be created.',
})
);
};
const onSelect = (selectedKeys, info) => {
const { id } = info.node;
handleGetSingleLocation(id);
};
const onCheck = checkedKeys => {
setCheckedLocations(checkedKeys.checked);
};
const handleFetchProfiles = e => {
if (apProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMore({
variables: { context: { ...apProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
});
}
return true;
};
const locationsTree = useMemo(() => formatLocationListForTree(data && data.getAllLocations), [
data,
]);
return (
<NetworkPage
onSelect={onSelect}
onCheck={onCheck}
checkedLocations={checkedLocations}
locations={locationsTree}
selectedLocation={selectedLocation && selectedLocation.getLocation}
addModal={addModal}
editModal={editModal}
deleteModal={deleteModal}
apModal={apModal}
setAddModal={setAddModal}
setEditModal={setEditModal}
setDeleteModal={setDeleteModal}
setApModal={setApModal}
onAddLocation={handleAddLocation}
onEditLocation={handleEditLocation}
onDeleteLocation={handleDeleteLocation}
onCreateEquipment={handleCreateEquipment}
profiles={
(apProfiles && apProfiles.getAllProfiles && apProfiles.getAllProfiles.items) || []
}
loadingProfile={loadingProfile}
errorProfile={errorProfile}
onFetchMoreProfiles={handleFetchProfiles}
isLastProfilesPage={apProfiles?.getAllProfiles?.context?.lastPage}
>
<Switch>
<Route
exact
path={`${path}/access-points/bulk-edit/:id`}
render={props => (
<BulkEditAccessPoints
locations={locationsTree}
checkedLocations={checkedLocations}
{...props}
/>
)}
/>
<Route
exact
path={`${path}/access-points`}
render={props => <AccessPoints checkedLocations={checkedLocations} {...props} />}
/>
<Route
exact
path={`${path}/access-points/:id/:tab`}
render={props => <AccessPointDetails locations={locationsTree} {...props} />}
/>
<Route
exact
path={`${path}/client-devices`}
render={props => <ClientDevices checkedLocations={checkedLocations} {...props} />}
/>
<Route exact path={`${path}/client-devices/:id`} component={ClientDeviceDetails} />
<Redirect from={`${path}/access-points/:id`} to={`${path}/access-points/:id/general`} />
<Redirect from={path} to={`${path}/access-points`} />
</Switch>
</NetworkPage>
);
},
GET_ALL_LOCATIONS,
() => {
const { customerId } = useContext(UserContext);
return { customerId };
} }
);
if (error) {
return <Alert message="Error" description="Failed to load locations." type="error" showIcon />;
}
return (
<NetworkPage
onSelect={onSelect}
onCheck={onCheck}
checkedLocations={checkedLocations}
locations={locationsTree}
selectedLocation={selectedLocation && selectedLocation.getLocation}
addModal={addModal}
editModal={editModal}
deleteModal={deleteModal}
apModal={apModal}
setAddModal={setAddModal}
setEditModal={setEditModal}
setDeleteModal={setDeleteModal}
setApModal={setApModal}
onAddLocation={handleAddLocation}
onEditLocation={handleEditLocation}
onDeleteLocation={handleDeleteLocation}
onCreateEquipment={handleCreateEquipment}
profiles={(apProfiles && apProfiles.getAllProfiles && apProfiles.getAllProfiles.items) || []}
loadingProfile={loadingProfile}
errorProfile={errorProfile}
onFetchMoreProfiles={handleFetchProfiles}
isLastProfilesPage={apProfiles?.getAllProfiles?.context?.lastPage}
>
<Switch>
<Route
exact
path={`${path}/access-points/bulk-edit/:id`}
render={props => (
<BulkEditAccessPoints
locations={locationsTree}
checkedLocations={checkedLocations}
{...props}
/>
)}
/>
<Route
exact
path={`${path}/access-points`}
render={props => <AccessPoints checkedLocations={checkedLocations} {...props} />}
/>
<Route
exact
path={`${path}/access-points/:id/:tab`}
render={props => <AccessPointDetails locations={locationsTree} {...props} />}
/>
<Route
exact
path={`${path}/client-devices`}
render={props => <ClientDevices checkedLocations={checkedLocations} {...props} />}
/>
<Route exact path={`${path}/client-devices/:id`} component={ClientDeviceDetails} />
<Redirect from={`${path}/access-points/:id`} to={`${path}/access-points/:id/general`} />
<Redirect from={path} to={`${path}/access-points`} />
</Switch>
</NetworkPage>
);
};
export default Network; export default Network;

View File

@@ -1,13 +1,14 @@
import React, { useState, useContext } from 'react'; import React, { useState, useContext } from 'react';
import { useParams, Redirect } from 'react-router-dom'; import { useParams, Redirect } from 'react-router-dom';
import { useQuery, useMutation, gql } from '@apollo/client'; import { useQuery, useMutation, gql } from '@apollo/client';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import { ProfileDetails as ProfileDetailsPage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { ProfileDetails as ProfileDetailsPage } from '@tip-wlan/wlan-cloud-ui-library';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { GET_ALL_PROFILES } from 'graphql/queries'; import { GET_ALL_PROFILES } from 'graphql/queries';
import { FILE_UPLOAD } from 'graphql/mutations'; import { FILE_UPLOAD } from 'graphql/mutations';
import { updateQueryGetAllProfiles } from 'graphql/functions'; import { updateQueryGetAllProfiles } from 'graphql/functions';
import { withQuery } from 'containers/QueryWrapper';
const GET_PROFILE = gql` const GET_PROFILE = gql`
query GetProfile($id: ID!) { query GetProfile($id: ID!) {
@@ -68,187 +69,179 @@ const DELETE_PROFILE = gql`
} }
`; `;
const ProfileDetails = () => { const ProfileDetails = withQuery(
const { customerId } = useContext(UserContext); ({ data }) => {
const { id } = useParams(); const { customerId } = useContext(UserContext);
const { id } = useParams();
const [redirect, setRedirect] = useState(false); const [redirect, setRedirect] = useState(false);
const { loading, error, data } = useQuery(GET_PROFILE, { const { data: ssidProfiles, fetchMore } = useQuery(GET_ALL_PROFILES(), {
variables: { id }, variables: { customerId, type: 'ssid' },
fetchPolicy: 'network-only', });
});
const { data: ssidProfiles, fetchMore } = useQuery(GET_ALL_PROFILES(), { const { data: radiusProfiles, fetchMore: fetchMoreRadiusProfiles } = useQuery(
variables: { customerId, type: 'ssid' }, GET_ALL_PROFILES(),
}); {
variables: { customerId, type: 'radius' },
const { data: radiusProfiles, fetchMore: fetchMoreRadiusProfiles } = useQuery(
GET_ALL_PROFILES(),
{
variables: { customerId, type: 'radius' },
}
);
const { data: captiveProfiles, fetchMore: fetchMoreCaptiveProfiles } = useQuery(
GET_ALL_PROFILES(),
{
variables: { customerId, type: 'captive_portal' },
}
);
const [updateProfile] = useMutation(UPDATE_PROFILE);
const [deleteProfile] = useMutation(DELETE_PROFILE);
const [fileUpload] = useMutation(FILE_UPLOAD);
const handleDeleteProfile = () => {
deleteProfile({ variables: { id } })
.then(() => {
notification.success({
message: 'Success',
description: 'Profile successfully deleted.',
});
setRedirect(true);
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Profile could not be deleted.',
})
);
};
const handleUpdateProfile = (
name,
details,
childProfileIds = data.getProfile.childProfileIds
) => {
updateProfile({
variables: {
...data.getProfile,
name,
childProfileIds,
details,
},
})
.then(() => {
notification.success({
message: 'Success',
description: 'Profile successfully updated.',
});
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Profile could not be updated.',
})
);
};
const handleFileUpload = (fileName, file) =>
fileUpload({ variables: { fileName, file } })
.then(() => {
notification.success({
message: 'Success',
description: 'File successfully uploaded.',
});
})
.catch(() =>
notification.error({
message: 'Error',
description: 'File could not be uploaded.',
})
);
const handleFetchProfiles = e => {
if (ssidProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMore({
variables: { context: { ...ssidProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
});
}
return true;
};
const handleFetchRadiusProfiles = e => {
if (radiusProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMoreRadiusProfiles({
variables: { context: { ...radiusProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
});
}
return true;
};
const handleFetchCaptiveProfiles = e => {
if (captiveProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMoreCaptiveProfiles({
variables: { context: { ...captiveProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
});
}
return true;
};
if (loading) {
return <Loading />;
}
if (error) {
return (
<Alert message="Error" description="Failed to load profile data." type="error" showIcon />
);
}
if (redirect) {
return <Redirect to="/profiles" />;
}
return (
<ProfileDetailsPage
name={data.getProfile.name}
profileType={data.getProfile.profileType}
details={data.getProfile.details}
childProfileIds={data.getProfile.childProfileIds}
onDeleteProfile={handleDeleteProfile}
onUpdateProfile={handleUpdateProfile}
ssidProfiles={
(ssidProfiles && ssidProfiles.getAllProfiles && ssidProfiles.getAllProfiles.items) || []
} }
radiusProfiles={radiusProfiles?.getAllProfiles?.items} );
captiveProfiles={captiveProfiles?.getAllProfiles?.items}
fileUpload={handleFileUpload} const { data: captiveProfiles, fetchMore: fetchMoreCaptiveProfiles } = useQuery(
onFetchMoreProfiles={handleFetchProfiles} GET_ALL_PROFILES(),
onFetchMoreRadiusProfiles={handleFetchRadiusProfiles} {
onFetchMoreCaptiveProfiles={handleFetchCaptiveProfiles} variables: { customerId, type: 'captive_portal' },
/> }
); );
};
const [updateProfile] = useMutation(UPDATE_PROFILE);
const [deleteProfile] = useMutation(DELETE_PROFILE);
const [fileUpload] = useMutation(FILE_UPLOAD);
const handleDeleteProfile = () => {
deleteProfile({ variables: { id } })
.then(() => {
notification.success({
message: 'Success',
description: 'Profile successfully deleted.',
});
setRedirect(true);
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Profile could not be deleted.',
})
);
};
const handleUpdateProfile = (
name,
details,
childProfileIds = data.getProfile.childProfileIds
) => {
updateProfile({
variables: {
...data.getProfile,
name,
childProfileIds,
details,
},
})
.then(() => {
notification.success({
message: 'Success',
description: 'Profile successfully updated.',
});
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Profile could not be updated.',
})
);
};
const handleFileUpload = (fileName, file) =>
fileUpload({ variables: { fileName, file } })
.then(() => {
notification.success({
message: 'Success',
description: 'File successfully uploaded.',
});
})
.catch(() =>
notification.error({
message: 'Error',
description: 'File could not be uploaded.',
})
);
const handleFetchProfiles = e => {
if (ssidProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMore({
variables: { context: { ...ssidProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
});
}
return true;
};
const handleFetchRadiusProfiles = e => {
if (radiusProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMoreRadiusProfiles({
variables: { context: { ...radiusProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
});
}
return true;
};
const handleFetchCaptiveProfiles = e => {
if (captiveProfiles.getAllProfiles.context.lastPage) {
return false;
}
e.persist();
const { target } = e;
if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
fetchMoreCaptiveProfiles({
variables: { context: { ...captiveProfiles.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles,
});
}
return true;
};
if (redirect) {
return <Redirect to="/profiles" />;
}
return (
<ProfileDetailsPage
name={data.getProfile.name}
profileType={data.getProfile.profileType}
details={data.getProfile.details}
childProfileIds={data.getProfile.childProfileIds}
onDeleteProfile={handleDeleteProfile}
onUpdateProfile={handleUpdateProfile}
ssidProfiles={
(ssidProfiles && ssidProfiles.getAllProfiles && ssidProfiles.getAllProfiles.items) || []
}
radiusProfiles={radiusProfiles?.getAllProfiles?.items}
captiveProfiles={captiveProfiles?.getAllProfiles?.items}
fileUpload={handleFileUpload}
onFetchMoreProfiles={handleFetchProfiles}
onFetchMoreRadiusProfiles={handleFetchRadiusProfiles}
onFetchMoreCaptiveProfiles={handleFetchCaptiveProfiles}
/>
);
},
GET_PROFILE,
() => {
const { id } = useParams();
return { id, fetchPolicy: 'network-only' };
}
);
export default ProfileDetails; export default ProfileDetails;

View File

@@ -1,12 +1,13 @@
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client'; import { useMutation, gql } from '@apollo/client';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import { Profile as ProfilePage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { Profile as ProfilePage } from '@tip-wlan/wlan-cloud-ui-library';
import { GET_ALL_PROFILES } from 'graphql/queries'; import { GET_ALL_PROFILES } from 'graphql/queries';
import { updateQueryGetAllProfiles } from 'graphql/functions'; import { updateQueryGetAllProfiles } from 'graphql/functions';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { withQuery } from 'containers/QueryWrapper';
const DELETE_PROFILE = gql` const DELETE_PROFILE = gql`
mutation DeleteProfile($id: ID!) { mutation DeleteProfile($id: ID!) {
@@ -16,94 +17,85 @@ const DELETE_PROFILE = gql`
} }
`; `;
const Profiles = () => { const Profiles = withQuery(
const { customerId } = useContext(UserContext); ({ data, fetchMore, refetch }) => {
const { loading, error, data, refetch, fetchMore } = useQuery( const [deleteProfile] = useMutation(DELETE_PROFILE);
GET_ALL_PROFILES(`equipmentCount`), const { customerId } = useContext(UserContext);
{ const location = useLocation();
variables: { customerId },
fetchPolicy: 'network-only',
}
);
const [deleteProfile] = useMutation(DELETE_PROFILE);
const location = useLocation();
useEffect(() => { useEffect(() => {
if (location.state && location.state.refetch) { if (location.state && location.state.refetch) {
refetch({
variables: { refresh: Date.now() },
});
}
}, []);
const reloadTable = () => {
refetch({ refetch({
variables: { refresh: Date.now() }, variables: { refresh: Date.now() },
});
}
}, []);
const reloadTable = () => {
refetch({
variables: { refresh: Date.now() },
})
.then(() => {
notification.success({
message: 'Success',
description: 'Profiles reloaded.',
});
}) })
.catch(() => .then(() => {
notification.error({ notification.success({
message: 'Error', message: 'Success',
description: 'Profiles could not be reloaded.', description: 'Profiles reloaded.',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Profiles could not be reloaded.',
})
);
};
const handleLoadMore = () => { const handleLoadMore = () => {
if (!data.getAllProfiles.context.lastPage) { if (!data.getAllProfiles.context.lastPage) {
fetchMore({ fetchMore({
variables: { context: { ...data.getAllProfiles.context } }, variables: { context: { ...data.getAllProfiles.context } },
updateQuery: updateQueryGetAllProfiles, updateQuery: updateQueryGetAllProfiles,
});
}
};
const handleDeleteProfile = id => {
deleteProfile({
variables: { id },
refetchQueries: [
{
query: GET_ALL_PROFILES(`equipmentCount`),
variables: { customerId },
},
],
})
.then(() => {
notification.success({
message: 'Success',
description: 'Profile successfully deleted.',
}); });
}
};
const handleDeleteProfile = id => {
deleteProfile({
variables: { id },
refetchQueries: [
{
query: GET_ALL_PROFILES(`equipmentCount`),
variables: { customerId },
},
],
}) })
.catch(() => .then(() => {
notification.error({ notification.success({
message: 'Error', message: 'Success',
description: 'Profile could not be deleted.', description: 'Profile successfully deleted.',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
if (loading) { description: 'Profile could not be deleted.',
return <Loading />; })
);
};
return (
<ProfilePage
data={data.getAllProfiles.items}
onReload={reloadTable}
isLastPage={data?.getAllProfiles?.context?.lastPage}
onDeleteProfile={handleDeleteProfile}
onLoadMore={handleLoadMore}
/>
);
},
GET_ALL_PROFILES(`equipmentCount`),
() => {
const { customerId } = useContext(UserContext);
return { customerId, fetchPolicy: 'network-only' };
} }
);
if (error) {
return <Alert message="Error" description="Failed to load profiles." type="error" showIcon />;
}
return (
<ProfilePage
data={data.getAllProfiles.items}
onReload={reloadTable}
isLastPage={data?.getAllProfiles?.context?.lastPage}
onDeleteProfile={handleDeleteProfile}
onLoadMore={handleLoadMore}
/>
);
};
export default Profiles; export default Profiles;

View File

@@ -0,0 +1,25 @@
import React from 'react';
import { Alert } from 'antd';
import { Loading } from '@tip-wlan/wlan-cloud-ui-library';
import { useQuery } from '@apollo/client';
import { Redirect } from 'react-router-dom';
export const withQuery = (Comp, query, getVariables) => props => {
const { loading, error, data, refetch, fetchMore } = useQuery(query, {
variables: getVariables(),
});
if (loading) {
return <Loading />;
}
if (error) {
if (error.message === '403: Forbidden' || error.message === '401: Unauthorized') {
return <Redirect to="/login" />;
}
return <Alert message="Error" description="Failed to load profiles." type="error" showIcon />;
}
return <Comp {...props} data={data} fetchMore={fetchMore} refetch={refetch} />;
};

View File

@@ -1,87 +1,82 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useQuery, useMutation } from '@apollo/client'; import { useQuery, useMutation } from '@apollo/client';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import { AutoProvision as AutoProvisionPage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { AutoProvision as AutoProvisionPage } from '@tip-wlan/wlan-cloud-ui-library';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { GET_CUSTOMER, GET_ALL_LOCATIONS, GET_ALL_PROFILES } from 'graphql/queries'; import { GET_CUSTOMER, GET_ALL_LOCATIONS, GET_ALL_PROFILES } from 'graphql/queries';
import { UPDATE_CUSTOMER } from 'graphql/mutations'; import { UPDATE_CUSTOMER } from 'graphql/mutations';
import { withQuery } from 'containers/QueryWrapper';
const AutoProvision = () => { const AutoProvision = withQuery(
const { customerId } = useContext(UserContext); ({ data, refetch }) => {
const { data, loading, error, refetch } = useQuery(GET_CUSTOMER, { const { customerId } = useContext(UserContext);
variables: { id: customerId }, const [updateCustomer] = useMutation(UPDATE_CUSTOMER);
});
const [updateCustomer] = useMutation(UPDATE_CUSTOMER);
const { data: dataLocation, loading: loadingLoaction, error: errorLocation } = useQuery( const { data: dataLocation, loading: loadingLoaction, error: errorLocation } = useQuery(
GET_ALL_LOCATIONS, GET_ALL_LOCATIONS,
{ {
variables: { customerId }, variables: { customerId },
} }
); );
const { data: dataProfile, loading: loadingProfile, error: errorProfile } = useQuery( const { data: dataProfile, loading: loadingProfile, error: errorProfile } = useQuery(
GET_ALL_PROFILES(), GET_ALL_PROFILES(),
{ {
variables: { customerId, type: 'equipment_ap', limit: 100 }, variables: { customerId, type: 'equipment_ap', limit: 100 },
} }
);
const handleUpdateCustomer = (
id,
email,
name,
details,
createdTimestamp,
lastModifiedTimestamp
) => {
updateCustomer({
variables: {
id,
email,
name,
details,
createdTimestamp,
lastModifiedTimestamp,
},
})
.then(() => {
refetch();
notification.success({
message: 'Success',
description: 'Settings successfully updated.',
});
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Settings could not be updated.',
})
);
};
if (loading) {
return <Loading />;
}
if (error) {
return (
<Alert message="Error" description="Failed to load Customer Data." type="error" showIcon />
); );
}
return ( const handleUpdateCustomer = (
<AutoProvisionPage id,
data={data && data.getCustomer} email,
dataLocation={dataLocation && dataLocation.getAllLocations} name,
dataProfile={dataProfile && dataProfile.getAllProfiles.items} details,
loadingLoaction={loadingLoaction} createdTimestamp,
loadingProfile={loadingProfile} lastModifiedTimestamp
errorLocation={errorLocation} ) => {
errorProfile={errorProfile} updateCustomer({
onUpdateCustomer={handleUpdateCustomer} variables: {
/> id,
); email,
}; name,
details,
createdTimestamp,
lastModifiedTimestamp,
},
})
.then(() => {
refetch();
notification.success({
message: 'Success',
description: 'Settings successfully updated.',
});
})
.catch(() =>
notification.error({
message: 'Error',
description: 'Settings could not be updated.',
})
);
};
return (
<AutoProvisionPage
data={data && data.getCustomer}
dataLocation={dataLocation && dataLocation.getAllLocations}
dataProfile={dataProfile && dataProfile.getAllProfiles.items}
loadingLoaction={loadingLoaction}
loadingProfile={loadingProfile}
errorLocation={errorLocation}
errorProfile={errorProfile}
onUpdateCustomer={handleUpdateCustomer}
/>
);
},
GET_CUSTOMER,
() => {
const { customerId } = useContext(UserContext);
return { id: customerId };
}
);
export default AutoProvision; export default AutoProvision;

View File

@@ -1,78 +1,76 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useQuery, useMutation } from '@apollo/client'; import { useMutation } from '@apollo/client';
import { Alert, notification } from 'antd'; import { notification } from 'antd';
import { BlockedList as BlockedListPage, Loading } from '@tip-wlan/wlan-cloud-ui-library'; import { BlockedList as BlockedListPage } from '@tip-wlan/wlan-cloud-ui-library';
import { GET_BLOCKED_CLIENTS } from 'graphql/queries'; import { GET_BLOCKED_CLIENTS } from 'graphql/queries';
import { UPDATE_CLIENT, ADD_BLOCKED_CLIENT } from 'graphql/mutations'; import { UPDATE_CLIENT, ADD_BLOCKED_CLIENT } from 'graphql/mutations';
import UserContext from 'contexts/UserContext'; import UserContext from 'contexts/UserContext';
import { withQuery } from 'containers/QueryWrapper';
const BlockedList = () => { const BlockedList = withQuery(
const { customerId } = useContext(UserContext); ({ refetch, data }) => {
const { data, error, loading, refetch } = useQuery(GET_BLOCKED_CLIENTS, { const { customerId } = useContext(UserContext);
variables: { customerId }, const [addClient] = useMutation(ADD_BLOCKED_CLIENT);
}); const [updateClient] = useMutation(UPDATE_CLIENT);
const [addClient] = useMutation(ADD_BLOCKED_CLIENT);
const [updateClient] = useMutation(UPDATE_CLIENT);
const handleAddClient = macAddress => { const handleAddClient = macAddress => {
addClient({ addClient({
variables: { variables: {
customerId, customerId,
macAddress, macAddress,
}, },
})
.then(() => {
refetch();
notification.success({
message: 'Success',
description: 'Client successfully added to Blocked List',
});
}) })
.catch(() => .then(() => {
notification.error({ refetch();
message: 'Error', notification.success({
description: 'Client could not be added to Blocked List', message: 'Success',
description: 'Client successfully added to Blocked List',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Client could not be added to Blocked List',
})
);
};
const handleUpdateClient = (macAddress, details) => { const handleUpdateClient = (macAddress, details) => {
updateClient({ updateClient({
variables: { variables: {
customerId, customerId,
macAddress, macAddress,
details, details,
}, },
})
.then(() => {
refetch();
notification.success({
message: 'Success',
description: 'Client successfully removed from Blocked List',
});
}) })
.catch(() => .then(() => {
notification.error({ refetch();
message: 'Error', notification.success({
description: 'Client could not be removed from Blocked List', message: 'Success',
description: 'Client successfully removed from Blocked List',
});
}) })
); .catch(() =>
}; notification.error({
message: 'Error',
description: 'Client could not be removed from Blocked List',
})
);
};
if (loading) return <Loading />;
if (error)
return ( return (
<Alert message="Error" description="Failed to load Client Data." type="error" showIcon /> <BlockedListPage
data={data && data.getBlockedClients}
onUpdateClient={handleUpdateClient}
onAddClient={handleAddClient}
/>
); );
},
return ( GET_BLOCKED_CLIENTS,
<BlockedListPage () => {
data={data && data.getBlockedClients} const { customerId } = useContext(UserContext);
onUpdateClient={handleUpdateClient} return customerId;
onAddClient={handleAddClient} }
/> );
);
};
export default BlockedList; export default BlockedList;

View File

@@ -11,7 +11,7 @@
"test": "jest --passWithNoTests --coverage", "test": "jest --passWithNoTests --coverage",
"start": "cross-env NODE_ENV=development webpack-dev-server", "start": "cross-env NODE_ENV=development webpack-dev-server",
"start:bare": "cross-env API=https://wlan-graphql.zone3.lab.connectus.ai NODE_ENV=bare webpack-dev-server", "start:bare": "cross-env API=https://wlan-graphql.zone3.lab.connectus.ai NODE_ENV=bare webpack-dev-server",
"start:dev": "cross-env API=https://wlan-graphql.zone3.lab.connectus.ai NODE_ENV=development webpack-dev-server", "start:dev": "cross-env API=https://wlan-graphql.qa.lab.wlan.tip.build NODE_ENV=development webpack-dev-server",
"build": "webpack --mode=production", "build": "webpack --mode=production",
"format": "prettier --write \"app/**/*.js\"", "format": "prettier --write \"app/**/*.js\"",
"eslint-fix": "eslint --fix \"app/**/*.js\"", "eslint-fix": "eslint --fix \"app/**/*.js\"",