mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge pull request #790 from dunithd/master
Adding an API method to retrieve an activity by it's ID and a device ID
This commit is contained in:
commit
3deffa99dd
@ -140,6 +140,93 @@ public interface ActivityInfoProviderService {
|
||||
@HeaderParam("If-Modified-Since") String ifModifiedSince);
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/{id}/{devicetype}/{deviceid}")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Details of an Activity for a specific device",
|
||||
notes = "Retrieve the details of a specific activity/operation, such as the meta information of " +
|
||||
"an operation, including the responses from a given device",
|
||||
tags = "Activity Info Provider",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:get-activity")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK. \n Successfully fetched the activity details.",
|
||||
response = Activity.class,
|
||||
responseHeaders = {
|
||||
@ResponseHeader(
|
||||
name = "Content-Type",
|
||||
description = "The content type of the body"),
|
||||
@ResponseHeader(
|
||||
name = "ETag",
|
||||
description = "Entity Tag of the response resource.\n" +
|
||||
"Used by caches, or in conditional requests."),
|
||||
@ResponseHeader(
|
||||
name = "Last-Modified",
|
||||
description = "Date and time the resource was last modified.\n" +
|
||||
"Used by caches, or in conditional requests."),
|
||||
}),
|
||||
@ApiResponse(
|
||||
code = 304,
|
||||
message = "Not Modified. \n Empty body because the client already has the latest version of " +
|
||||
"the requested resource."),
|
||||
@ApiResponse(
|
||||
code = 400,
|
||||
message = "Bad Request. \n Invalid request or validation error.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 401,
|
||||
message = "Unauthorized. \n Unauthorized request."),
|
||||
@ApiResponse(
|
||||
code = 404,
|
||||
message = "Not Found. \n No activity found with the given ID.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 406,
|
||||
message = "Not Acceptable.\n The requested media type is not supported"),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Internal Server Error. \n Server error occurred while fetching the activity data.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getActivityByDevice(
|
||||
@ApiParam(
|
||||
name = "id",
|
||||
value = "Activity id of the operation/activity.",
|
||||
required = true,
|
||||
defaultValue = "ACTIVITY_1")
|
||||
@PathParam("id")
|
||||
@Size(max = 45)
|
||||
String id,
|
||||
@ApiParam(
|
||||
name = "devicetype",
|
||||
value = "The device type name, such as ios, android, windows or fire-alarm.",
|
||||
required = true)
|
||||
@PathParam("devicetype")
|
||||
@Size(max = 45)
|
||||
String type,
|
||||
@ApiParam(
|
||||
name = "deviceid",
|
||||
value = "The device identifier of the device you want ot get details.",
|
||||
required = true)
|
||||
@PathParam("deviceid")
|
||||
@Size(max = 45)
|
||||
String deviceid,
|
||||
@ApiParam(
|
||||
name = "If-Modified-Since",
|
||||
value = "Checks if the requested variant was modified, since the specified date-time\n." +
|
||||
"Provide the value in the Java Date Format: EEE, d MMM yyyy HH:mm:ss Z\n." +
|
||||
"Example: Mon, 05 Jan 2014 15:10:00 +0200",
|
||||
required = false)
|
||||
@HeaderParam("If-Modified-Since") String ifModifiedSince);
|
||||
|
||||
@GET
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
|
||||
@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.jaxrs.service.impl;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
|
||||
@ -72,6 +73,43 @@ public class ActivityProviderServiceImpl implements ActivityInfoProviderService
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Override
|
||||
@Path("/{id}/{devicetype}/{deviceid}")
|
||||
public Response getActivityByDevice(@PathParam("id")
|
||||
@Size(max = 45) String id,
|
||||
@PathParam("devicetype")
|
||||
@Size(max = 45) String devicetype,
|
||||
@PathParam("deviceid")
|
||||
@Size(max = 45) String deviceid,
|
||||
@HeaderParam("If-Modified-Since") String ifModifiedSince) {
|
||||
Activity activity;
|
||||
DeviceManagementProviderService dmService;
|
||||
try {
|
||||
RequestValidationUtil.validateActivityId(id);
|
||||
|
||||
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
|
||||
deviceIdentifier.setId(deviceid);
|
||||
deviceIdentifier.setType(devicetype);
|
||||
|
||||
dmService = DeviceMgtAPIUtils.getDeviceManagementService();
|
||||
activity = dmService.getOperationByActivityIdAndDevice(id, deviceIdentifier);
|
||||
if (activity == null) {
|
||||
return Response.status(404).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage("No activity can be " +
|
||||
"found upon the provided activity id '" + id + "'").build()).build();
|
||||
}
|
||||
return Response.status(Response.Status.OK).entity(activity).build();
|
||||
} catch (OperationManagementException e) {
|
||||
String msg = "ErrorResponse occurred while fetching the activity for the supplied id.";
|
||||
log.error(msg, e);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Override
|
||||
public Response getActivities(@QueryParam("since") String since, @QueryParam("offset") int offset,
|
||||
|
||||
@ -93,6 +93,8 @@ public interface OperationManager {
|
||||
|
||||
Activity getOperationByActivityId(String activity) throws OperationManagementException;
|
||||
|
||||
Activity getOperationByActivityIdAndDevice(String activity, DeviceIdentifier deviceId) throws OperationManagementException;
|
||||
|
||||
List<Operation> getOperationUpdatedAfter(long timestamp) throws OperationManagementException;
|
||||
|
||||
List<Activity> getActivitiesUpdatedAfter(long timestamp) throws OperationManagementException;
|
||||
|
||||
@ -812,6 +812,28 @@ public class OperationManagerImpl implements OperationManager {
|
||||
}
|
||||
}
|
||||
|
||||
public Activity getOperationByActivityIdAndDevice(String activity, DeviceIdentifier deviceId) throws OperationManagementException {
|
||||
// This parses the operation id from activity id (ex : ACTIVITY_23) and converts to the integer.
|
||||
int operationId = Integer.parseInt(
|
||||
activity.replace(DeviceManagementConstants.OperationAttributes.ACTIVITY, ""));
|
||||
if (operationId == 0) {
|
||||
throw new IllegalArgumentException("Operation ID cannot be null or zero (0).");
|
||||
}
|
||||
|
||||
Device device = this.getDevice(deviceId);
|
||||
try {
|
||||
OperationManagementDAOFactory.openConnection();
|
||||
return operationDAO.getActivityByDevice(operationId, device.getId());
|
||||
} catch (SQLException e) {
|
||||
throw new OperationManagementException("Error occurred while opening a connection to the data source.", e);
|
||||
} catch (OperationManagementDAOException e) {
|
||||
throw new OperationManagementException("Error occurred while retrieving the operation with activity Id '" +
|
||||
activity + " and device Id: " + deviceId.getId(), e);
|
||||
} finally {
|
||||
OperationManagementDAOFactory.closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Operation> getOperationUpdatedAfter(long timestamp) throws OperationManagementException {
|
||||
return null;
|
||||
|
||||
@ -70,6 +70,8 @@ public interface OperationDAO {
|
||||
|
||||
Activity getActivity(int operationId) throws OperationManagementDAOException;
|
||||
|
||||
Activity getActivityByDevice(int operationId, int deviceId) throws OperationManagementDAOException;
|
||||
|
||||
int getEnrolmentIdFromMappingId(int enrollmentOpMappingId) throws OperationManagementDAOException;
|
||||
|
||||
List<Operation> getOperationsUpdatedAfter(long timestamp) throws OperationManagementDAOException;
|
||||
|
||||
@ -384,6 +384,83 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
return activity;
|
||||
}
|
||||
|
||||
public Activity getActivityByDevice(int operationId, int deviceId) throws OperationManagementDAOException {
|
||||
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
Activity activity = null;
|
||||
List<ActivityStatus> activityStatusList = new ArrayList<>();
|
||||
try {
|
||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
||||
String sql = "SELECT eom.ENROLMENT_ID, eom.OPERATION_ID, eom.ID AS EOM_MAPPING_ID, dor.ID AS OP_RES_ID,\n" +
|
||||
"de.DEVICE_ID, d.DEVICE_IDENTIFICATION, \n" +
|
||||
"d.DEVICE_TYPE_ID, dt.NAME AS DEVICE_TYPE_NAME, eom.STATUS, eom.CREATED_TIMESTAMP, \n" +
|
||||
"eom.UPDATED_TIMESTAMP, op.OPERATION_CODE, op.TYPE AS OPERATION_TYPE, dor.OPERATION_RESPONSE, \n" +
|
||||
"dor.RECEIVED_TIMESTAMP FROM DM_ENROLMENT_OP_MAPPING AS eom \n" +
|
||||
"INNER JOIN DM_OPERATION AS op ON op.ID=eom.OPERATION_ID\n" +
|
||||
"INNER JOIN DM_ENROLMENT AS de ON de.ID=eom.ENROLMENT_ID\n" +
|
||||
"INNER JOIN DM_DEVICE AS d ON d.ID=de.DEVICE_ID \n" +
|
||||
"INNER JOIN DM_DEVICE_TYPE AS dt ON dt.ID=d.DEVICE_TYPE_ID\n" +
|
||||
"LEFT JOIN DM_DEVICE_OPERATION_RESPONSE AS dor ON dor.ENROLMENT_ID=de.id \n" +
|
||||
"AND dor.OPERATION_ID = eom.OPERATION_ID\n" +
|
||||
"WHERE eom.OPERATION_ID = ? AND de.device_id = ? AND de.TENANT_ID = ?";
|
||||
|
||||
stmt = conn.prepareStatement(sql);
|
||||
stmt.setInt(1, operationId);
|
||||
stmt.setInt(2, deviceId);
|
||||
stmt.setInt(3, PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId());
|
||||
rs = stmt.executeQuery();
|
||||
|
||||
int enrolmentId = 0;
|
||||
ActivityStatus activityStatus = null;
|
||||
|
||||
while (rs.next()) {
|
||||
if (enrolmentId == 0) {
|
||||
activity = new Activity();
|
||||
activity.setType(Activity.Type.valueOf(rs.getString("OPERATION_TYPE")));
|
||||
activity.setCreatedTimeStamp(new java.util.Date(rs.getLong(("CREATED_TIMESTAMP")) * 1000).toString());
|
||||
activity.setCode(rs.getString("OPERATION_CODE"));
|
||||
}
|
||||
if (enrolmentId != rs.getInt("ENROLMENT_ID")) {
|
||||
activityStatus = new ActivityStatus();
|
||||
|
||||
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
|
||||
deviceIdentifier.setId(rs.getString("DEVICE_IDENTIFICATION"));
|
||||
deviceIdentifier.setType(rs.getString("DEVICE_TYPE_NAME"));
|
||||
activityStatus.setDeviceIdentifier(deviceIdentifier);
|
||||
|
||||
activityStatus.setStatus(ActivityStatus.Status.valueOf(rs.getString("STATUS")));
|
||||
|
||||
List<OperationResponse> operationResponses = new ArrayList<>();
|
||||
if (rs.getInt("UPDATED_TIMESTAMP") != 0) {
|
||||
activityStatus.setUpdatedTimestamp(new java.util.Date(rs.getLong(("UPDATED_TIMESTAMP")) * 1000).toString());
|
||||
operationResponses.add(OperationDAOUtil.getOperationResponse(rs));
|
||||
}
|
||||
activityStatus.setResponses(operationResponses);
|
||||
|
||||
activityStatusList.add(activityStatus);
|
||||
|
||||
enrolmentId = rs.getInt("ENROLMENT_ID");
|
||||
activity.setActivityStatus(activityStatusList);
|
||||
} else {
|
||||
if (rs.getInt("UPDATED_TIMESTAMP") != 0) {
|
||||
activityStatus.getResponses().add(OperationDAOUtil.getOperationResponse(rs));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new OperationManagementDAOException("Error occurred while getting the operation details from " +
|
||||
"the database.", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new OperationManagementDAOException("Error occurred while converting the operation response to string.", e);
|
||||
} catch (IOException e) {
|
||||
throw new OperationManagementDAOException("IO exception occurred while converting the operations responses.", e);
|
||||
} finally {
|
||||
OperationManagementDAOUtil.cleanupResources(stmt, rs);
|
||||
}
|
||||
return activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Activity> getActivitiesUpdatedAfter(long timestamp) throws OperationManagementDAOException {
|
||||
return this.getActivitiesUpdatedAfter(timestamp, 0, 0);
|
||||
|
||||
@ -116,6 +116,11 @@ public class PushNotificationBasedOperationManager implements OperationManager {
|
||||
return this.operationManager.getOperationByActivityId(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Activity getOperationByActivityIdAndDevice(String activity, DeviceIdentifier deviceId) throws OperationManagementException {
|
||||
return this.operationManager.getOperationByActivityIdAndDevice(activity, deviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Operation> getOperationUpdatedAfter(long timestamp) throws OperationManagementException {
|
||||
return this.operationManager.getOperationUpdatedAfter(timestamp);
|
||||
|
||||
@ -532,6 +532,8 @@ public interface DeviceManagementProviderService {
|
||||
|
||||
Activity getOperationByActivityId(String activity) throws OperationManagementException;
|
||||
|
||||
Activity getOperationByActivityIdAndDevice(String activity, DeviceIdentifier deviceId) throws OperationManagementException;
|
||||
|
||||
List<Activity> getActivitiesUpdatedAfter(long timestamp) throws OperationManagementException;
|
||||
|
||||
List<Activity> getActivitiesUpdatedAfter(long timestamp, int limit, int offset) throws OperationManagementException;
|
||||
|
||||
@ -1008,6 +1008,10 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
|
||||
return DeviceManagementDataHolder.getInstance().getOperationManager().getOperationByActivityId(activity);
|
||||
}
|
||||
|
||||
public Activity getOperationByActivityIdAndDevice(String activity, DeviceIdentifier deviceId) throws OperationManagementException {
|
||||
return DeviceManagementDataHolder.getInstance().getOperationManager().getOperationByActivityIdAndDevice(activity, deviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Activity> getActivitiesUpdatedAfter(long timestamp) throws OperationManagementException {
|
||||
return DeviceManagementDataHolder.getInstance().getOperationManager().getActivitiesUpdatedAfter(timestamp);
|
||||
|
||||
@ -0,0 +1,345 @@
|
||||
.operation-icon{
|
||||
width: 88px;
|
||||
height: 100px;
|
||||
background-color: #ebebeb;
|
||||
float: left;
|
||||
margin: 0px 10px 10px 0px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.operation-icon i{
|
||||
padding: 15px 0px 0px 0px;
|
||||
display: block;
|
||||
min-height: 65px;
|
||||
font-size: 3em !important;
|
||||
margin: 0px !important;
|
||||
}
|
||||
|
||||
.operation-icon span{
|
||||
height: 35px;
|
||||
line-height: 15px;
|
||||
vertical-align: middle;
|
||||
display: table-cell;
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
.application{
|
||||
width: 250px;
|
||||
height: 100px;
|
||||
background-color: #ebebeb;
|
||||
float: left;
|
||||
margin: 0px 10px 10px 0px;
|
||||
}
|
||||
|
||||
.application img{
|
||||
height: inherit;
|
||||
padding: 10px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.app-info h4{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.application i{
|
||||
float: right;
|
||||
margin: 0px 10px;
|
||||
position: relative;
|
||||
bottom: -20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-tabs>li>a{
|
||||
color: #333;
|
||||
}
|
||||
.nav-tabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover{
|
||||
border-bottom: 2px solid #37474f;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
.nav-tabs-selector{
|
||||
margin: 0px;
|
||||
border: 1px solid #37474f;
|
||||
}
|
||||
|
||||
.tab-pane{
|
||||
padding: 20px 0px;
|
||||
}
|
||||
|
||||
#location{
|
||||
height: calc(100vh - 400px);
|
||||
}
|
||||
|
||||
.page-loader{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: calc(100vh - 160px);
|
||||
z-index: 9999;
|
||||
background: url(images/page-loader.gif) 50% 50% no-repeat rgb(249,249,249);
|
||||
}
|
||||
|
||||
.page-loader .loader{
|
||||
left: 43%;
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
width: 13%;
|
||||
}
|
||||
|
||||
.page-loader .loader span{
|
||||
padding: 9px;
|
||||
position: absolute;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.device-info-container{
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.device-type{
|
||||
font-size: 9em;
|
||||
}
|
||||
.device-info h1, .device-info h4:not(:last-child){
|
||||
margin: 0px 0px 9px 0px;
|
||||
position: relative;
|
||||
}
|
||||
.device-id a{
|
||||
font-size: 0.4em;
|
||||
position: absolute;
|
||||
margin: 0px 5px;
|
||||
}
|
||||
.device-info h4:last-child{
|
||||
margin: 0px;
|
||||
}
|
||||
.tab-actions{
|
||||
position: relative;
|
||||
}
|
||||
.tab-actions .action-btn{
|
||||
padding: 10px 15px;
|
||||
background-color: #ebebeb;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
margin-left: 10px;
|
||||
ma
|
||||
}
|
||||
.tab-actions .action{
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.tab-actions .action-btn.show a{
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
.tab-actions .action-btn a{
|
||||
margin: 0px;
|
||||
}
|
||||
.tab-actions {
|
||||
margin: 0px;
|
||||
}
|
||||
.tab-actions .action-prop{
|
||||
padding: 10px;
|
||||
background: #ebebeb;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.tab-action-active{
|
||||
padding-bottom: 15px !important;
|
||||
}
|
||||
.action-btn-container:after{
|
||||
content: '';
|
||||
display: block;
|
||||
clear:both;
|
||||
}
|
||||
.input-group .fw{
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.vital-strip{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #ebebeb;
|
||||
padding: 10px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.vital-strip p{
|
||||
flex-grow: 1;
|
||||
margin: 0px;
|
||||
display: inline-flex;
|
||||
}
|
||||
.vital-strip p i{
|
||||
margin: 0px 10px;
|
||||
}
|
||||
.vital-strip p span{
|
||||
padding: 5px 0px;
|
||||
}
|
||||
.memory-amt{
|
||||
font-size: 0.8em;
|
||||
position: relative;
|
||||
bottom: -3px;
|
||||
padding-left: 2px !important;
|
||||
}
|
||||
|
||||
.policy-item{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 10px;
|
||||
background-color: #ebebeb;
|
||||
}
|
||||
.policy-item .policy-status, .policy-item p{
|
||||
flex-grow: 1;
|
||||
}
|
||||
.policy-item .policy-status{
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
margin-right: 10px;
|
||||
align-self: center;
|
||||
color: #5cb85c;
|
||||
}
|
||||
.policy-name{
|
||||
font-size: 1.5em;
|
||||
display: flex;
|
||||
}
|
||||
.policy-platform{
|
||||
display: flex;
|
||||
}
|
||||
.policy-item p:nth-child(2){
|
||||
margin: 0px;
|
||||
}
|
||||
.policy-item p:nth-child(3){
|
||||
flex-grow: 7;
|
||||
align-self: center;
|
||||
margin: 0px;
|
||||
}
|
||||
.policy-item p:nth-child(3) span{
|
||||
display: flex;
|
||||
}
|
||||
.policy-item .actions{
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
}
|
||||
.policy-item .action-btn{
|
||||
flex-grow: 1;
|
||||
margin: 3px 5px;
|
||||
background-color: #ccc;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.policy-item .action-btn p{
|
||||
align-self: center;
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.policy-item .action-btn p i{
|
||||
padding: 0px 5px;
|
||||
}
|
||||
.policy-item .action-btn span{
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
|
||||
#operation-log tr td{
|
||||
border-bottom: 15px solid #fff !important;
|
||||
}
|
||||
#operation-log tr.shown td{
|
||||
border-bottom: none !important;
|
||||
}
|
||||
.log-data-row td{
|
||||
padding: 0px !important;
|
||||
border-bottom: 15px solid #fff !important;
|
||||
}
|
||||
.log-data{
|
||||
background-color: #f6f6f6;
|
||||
padding: 0px 20px;
|
||||
}
|
||||
.log-data:after{
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
border: 1px solid #ced8db;
|
||||
top: 0;
|
||||
left: 50px;
|
||||
}
|
||||
.log-record-status{
|
||||
background-color: #4c4c4c !important;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.log-record-status i:first-child{
|
||||
float: left;
|
||||
line-height: 19px;
|
||||
padding: 0px 10px 0px 0px;
|
||||
}
|
||||
.log-record-status span{
|
||||
float: left;
|
||||
line-height: 17px;
|
||||
}
|
||||
.log-status{
|
||||
padding-left: 14px;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
}
|
||||
.log-status i{
|
||||
margin: 0px 10px;
|
||||
background-color: #f6f6f6;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.log-entry{
|
||||
padding: 15px 0px;
|
||||
}
|
||||
.log-entry:not(:first-child){
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* custom css fixes
|
||||
*/
|
||||
|
||||
.page-content-wrapper, .page-content-wrapper[data-container-behaviour=static]{
|
||||
min-height: calc(100vh - 123px);
|
||||
}
|
||||
|
||||
.content{
|
||||
/*opacity: 0;*/
|
||||
}
|
||||
|
||||
.content-wrapper{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dataTablesTop{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.table.list-table:not(.grid-view)>tbody>tr>td, .table.list-table:not(.grid-view)>tbody>tr>th{
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
.table.table-hover>tbody>tr:hover td:not(.dataTables_empty){
|
||||
background-color: inherit !important;
|
||||
}
|
||||
.table-hover>tbody>tr:hover,{
|
||||
background-color:
|
||||
}
|
||||
.table.list-table>tbody>tr:nth-of-type(even), .table.list-table>tbody>tr:nth-of-type(odd){
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
.table.table-hover>tbody>tr:hover td:not(.dataTables_empty){
|
||||
background-color: inherit !important;
|
||||
}
|
||||
.table.table-hover>tbody>tr:hover td.log-record-status{
|
||||
background-color: #4c4c4c !important;
|
||||
}
|
||||
|
||||
.tab-content{
|
||||
border:none;
|
||||
}
|
||||
@ -16,12 +16,12 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
var deviceId = $(".device-id");
|
||||
var deviceIdentifier = deviceId.data("deviceid");
|
||||
var deviceType = deviceId.data("type");
|
||||
var deviceOwner = deviceId.data("owner");
|
||||
var deviceId = $(".device-id");
|
||||
var deviceIdentifier = deviceId.data("deviceid");
|
||||
var deviceType = deviceId.data("type");
|
||||
var deviceOwner = deviceId.data("owner");
|
||||
|
||||
$(document).ready(function () {
|
||||
$(document).ready(function() {
|
||||
$(".panel-body").removeClass("hidden");
|
||||
$("#loading-content").remove();
|
||||
|
||||
@ -34,25 +34,143 @@
|
||||
}
|
||||
|
||||
|
||||
$("#refresh-policy").click(function () {
|
||||
$("#refresh-policy").click(function() {
|
||||
$('#policy-spinner').removeClass('hidden');
|
||||
loadPolicyCompliance();
|
||||
});
|
||||
|
||||
$("#refresh-operations").click(function () {
|
||||
$("#refresh-operations").click(function() {
|
||||
$('#operations-spinner').removeClass('hidden');
|
||||
loadOperationsLog(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function loadOperationsLog() {
|
||||
var table = $('#operation-log').DataTable({
|
||||
serverSide: true,
|
||||
processing: false,
|
||||
searching: false,
|
||||
ordering: false,
|
||||
pageLength: 10,
|
||||
order: [],
|
||||
autoWidth: false,
|
||||
ajax: {
|
||||
url: "/devicemgt/api/operation/paginate",
|
||||
data: {
|
||||
deviceId: deviceIdentifier,
|
||||
deviceType: deviceType,
|
||||
owner: deviceOwner
|
||||
},
|
||||
dataSrc: function(json) {
|
||||
$("#operations-spinner").addClass("hidden");
|
||||
$("#operations-log-container").empty();
|
||||
return json.data;
|
||||
}
|
||||
},
|
||||
columnDefs: [{
|
||||
targets: 0,
|
||||
data: "code",
|
||||
class: "icon-only content-fill"
|
||||
},
|
||||
{
|
||||
targets: 1,
|
||||
data: "createdTimeStamp",
|
||||
class: "text-right",
|
||||
render: function(date) {
|
||||
var value = String(date);
|
||||
return value.slice(0, 16);
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 2,
|
||||
data: "status",
|
||||
class: "text-right extended-log-data log-record-status",
|
||||
render: function(data, type, full, meta) {
|
||||
return '<i class="icon fw fw-success"></i><span> ' + data + ' </span><i class="icon fw fw-down"></i>';
|
||||
},
|
||||
width: "100%"
|
||||
}
|
||||
],
|
||||
fnCreatedRow: function(nRow, aData, iDataIndex) {
|
||||
$('td:eq(0)', nRow)
|
||||
.attr('data-search', aData.Device_Type)
|
||||
.attr('data-display', aData.Device_Type)
|
||||
.addClass(' icon-only content-fill');
|
||||
|
||||
$('td:eq(1), td:eq(2)', nRow).addClass('text-right');
|
||||
$('td:eq(2)', nRow).addClass('log-record-status')
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
function loadOperationsLog(update) {
|
||||
$('#operation-log tbody').on('click', 'td.extended-log-data', function() {
|
||||
var tr = $(this).closest('tr');
|
||||
var row = table.row(tr);
|
||||
var rowData = row.data()
|
||||
var deviceid = $('.device-id').data('deviceid');
|
||||
var deviceType = $('.device-id').data('type');
|
||||
var uri = "/api/device-mgt/v1.0/activities/" + rowData.activityId + "/" + deviceType + "/" + deviceid;
|
||||
var contentType = "application/json";
|
||||
|
||||
if (row.child.isShown()) {
|
||||
row.child.hide();
|
||||
$(row.child()).removeClass('log-data-row');
|
||||
tr.removeClass('shown');
|
||||
} else {
|
||||
invokerUtil.get(uri,(payload) => {
|
||||
row.child(renderLogDetails(row.data(),payload)).show();
|
||||
$(row.child()).addClass('log-data-row');
|
||||
tr.addClass('shown');
|
||||
},(error) => {
|
||||
|
||||
},contentType);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function renderLogDetails(obj,data) {
|
||||
var payload = JSON.parse(data);
|
||||
var logStream = '<div class="log-data">';
|
||||
|
||||
Object.entries(payload.activityStatus).forEach(
|
||||
([key, entry]) => {
|
||||
logStream += '<div class="row log-entry">' +
|
||||
'<div class="col-lg-8">' +
|
||||
'<div class="log-status"><i class="icon fw ' + getLogStatusIcon(entry.status) + ' "></i>' +
|
||||
'<span>' + entry.status + '</span></div>' +
|
||||
'</div>' +
|
||||
'<div class="col-lg-4">' +
|
||||
'<div class="log-time text-right"><span>' + entry.updatedTimestamp + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
);
|
||||
logStream += '</div></div>';
|
||||
return logStream;
|
||||
|
||||
function getLogStatusIcon(entry) {
|
||||
switch (entry) {
|
||||
case 'COMPLETED':
|
||||
return 'fw-success'
|
||||
break;
|
||||
case 'PENDING':
|
||||
return 'fw-pending'
|
||||
break;
|
||||
default:
|
||||
return 'fw-info'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadOperationsLog2(update) {
|
||||
var operationsLogTable = "#operations-log-table";
|
||||
|
||||
if (update) {
|
||||
operationTable = $(operationsLogTable).DataTable();
|
||||
$("#operations-spinner").removeClass("hidden");
|
||||
operationTable.ajax.reload(function ( json ) {
|
||||
operationTable.ajax.reload(function(json) {
|
||||
$("#operations-spinner").addClass("hidden");
|
||||
}, false);
|
||||
return;
|
||||
@ -62,45 +180,54 @@
|
||||
processing: false,
|
||||
searching: false,
|
||||
ordering: false,
|
||||
pageLength : 10,
|
||||
pageLength: 10,
|
||||
order: [],
|
||||
ajax: {
|
||||
|
||||
url: "/devicemgt/api/operation/paginate",
|
||||
data: {deviceId : deviceIdentifier, deviceType: deviceType, owner: deviceOwner},
|
||||
dataSrc: function (json) {
|
||||
data: {
|
||||
deviceId: deviceIdentifier,
|
||||
deviceType: deviceType,
|
||||
owner: deviceOwner
|
||||
},
|
||||
dataSrc: function(json) {
|
||||
$("#operations-spinner").addClass("hidden");
|
||||
$("#operations-log-container").empty();
|
||||
return json.data;
|
||||
}
|
||||
},
|
||||
columnDefs: [
|
||||
{targets: 0, data: "code" },
|
||||
{targets: 1, data: "status", render:
|
||||
function (status) {
|
||||
columnDefs: [{
|
||||
targets: 0,
|
||||
data: "code"
|
||||
},
|
||||
{
|
||||
targets: 1,
|
||||
data: "status",
|
||||
render: function(status) {
|
||||
var html;
|
||||
switch (status) {
|
||||
case "COMPLETED" :
|
||||
case "COMPLETED":
|
||||
html = "<span><i class='fw fw-success icon-success'></i> Completed</span>";
|
||||
break;
|
||||
case "PENDING" :
|
||||
case "PENDING":
|
||||
html = "<span><i class='fw fw-warning icon-warning'></i> Pending</span>";
|
||||
break;
|
||||
case "ERROR" :
|
||||
case "ERROR":
|
||||
html = "<span><i class='fw fw-error icon-danger'></i> Error</span>";
|
||||
break;
|
||||
case "IN_PROGRESS" :
|
||||
case "IN_PROGRESS":
|
||||
html = "<span><i class='fw fw-success icon-warning'></i> In Progress</span>";
|
||||
break;
|
||||
case "REPEATED" :
|
||||
case "REPEATED":
|
||||
html = "<span><i class='fw fw-success icon-warning'></i> Repeated</span>";
|
||||
break;
|
||||
}
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{targets: 2, data: "createdTimeStamp", render:
|
||||
function (date) {
|
||||
{
|
||||
targets: 2,
|
||||
data: "createdTimeStamp",
|
||||
render: function(date) {
|
||||
var value = String(date);
|
||||
return value.slice(0, 16);
|
||||
}
|
||||
@ -112,7 +239,7 @@
|
||||
$(row).attr("data-id", data["id"]);
|
||||
$.each($("td", row),
|
||||
function(colIndex) {
|
||||
switch(colIndex) {
|
||||
switch (colIndex) {
|
||||
case 1:
|
||||
$(this).attr("data-grid-label", "Code");
|
||||
$(this).attr("data-display", data["code"]);
|
||||
@ -130,9 +257,9 @@
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function loadPolicyCompliance() {
|
||||
function loadPolicyCompliance() {
|
||||
var policyCompliance = $("#policy-view");
|
||||
var policyComplianceTemplate = policyCompliance.attr("src");
|
||||
var deviceId = policyCompliance.data("device-id");
|
||||
@ -142,23 +269,23 @@
|
||||
$.template(
|
||||
"policy-view",
|
||||
policyComplianceTemplate,
|
||||
function (template) {
|
||||
function(template) {
|
||||
var getEffectivePolicyURL = "/api/device-mgt/v1.0/devices/" + deviceType + "/" + deviceId + "/effective-policy";
|
||||
var getDeviceComplianceURL = "/api/device-mgt/v1.0/devices/" + deviceType + "/" + deviceId + "/compliance-data";
|
||||
invokerUtil.get(
|
||||
getEffectivePolicyURL,
|
||||
// success-callback
|
||||
function (data, textStatus, jqXHR) {
|
||||
function(data, textStatus, jqXHR) {
|
||||
if (jqXHR.status == 200) {
|
||||
$("#policy-spinner").addClass("hidden");
|
||||
if(data){
|
||||
if (data) {
|
||||
data = JSON.parse(data);
|
||||
if (data["active"] == true) {
|
||||
activePolicy = data;
|
||||
invokerUtil.get(
|
||||
getDeviceComplianceURL,
|
||||
// success-callback
|
||||
function (data, textStatus, jqXHR) {
|
||||
function(data, textStatus, jqXHR) {
|
||||
if (jqXHR.status == 200 && data) {
|
||||
var viewModel = {};
|
||||
viewModel["policy"] = activePolicy;
|
||||
@ -188,7 +315,7 @@
|
||||
}
|
||||
},
|
||||
// error-callback
|
||||
function () {
|
||||
function() {
|
||||
$("#policy-list-container").
|
||||
html("<div class='panel-body'><br><p class='fw-warning'> Loading policy compliance related data " +
|
||||
"was not successful. please try refreshing data in a while.<p></div>");
|
||||
@ -199,7 +326,7 @@
|
||||
}
|
||||
},
|
||||
// error-callback
|
||||
function () {
|
||||
function() {
|
||||
$("#policy-list-container").
|
||||
html("<div class='panel-body'><br><p class='fw-warning'> Loading policy compliance related data " +
|
||||
"was not successful. please try refreshing data in a while.<p></div>");
|
||||
@ -207,4 +334,4 @@
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,135 +15,93 @@
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
}}
|
||||
{{#zone "topCss"}}
|
||||
{{css "css/main.css"}}
|
||||
{{/zone}}
|
||||
{{unit "cdmf.unit.lib.editable"}}
|
||||
{{#zone "content"}}
|
||||
{{#if deviceFound}}
|
||||
{{#if isAuthorized}}
|
||||
<span id="logged-in-user" class="hidden" data-username="{{@user.username}}" data-domain="{{@user.domain}}"
|
||||
data-tenant-id="{{@user.tenantId}}" data-iscloud="{{isCloud}}"></span>
|
||||
{{#defineZone "device-details-header"}}
|
||||
<h1 class="page-sub-title device-id device-select" data-deviceid="{{device.deviceIdentifier}}"
|
||||
data-type="{{device.type}}">
|
||||
Device {{device.name}}
|
||||
{{#if device.viewModel.model}}
|
||||
<span class="lbl-device">
|
||||
( {{device.viewModel.vendor}} {{device.viewModel.model}} )
|
||||
</span>
|
||||
{{/if}}
|
||||
</h1>
|
||||
{{/defineZone}}
|
||||
<div class="row no-gutter add-padding-5x add-margin-top-5x" style="border: 1px solid #e4e4e4;">
|
||||
<div class="media">
|
||||
<div id="device_overview">
|
||||
<div class="media-left media-middle asset-image col-xs-2 col-sm-2 col-md-2 col-lg-2">
|
||||
<div class="thumbnail icon">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="device-info-container">
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
{{#defineZone "device-thumbnail"}}
|
||||
<i class="square-element text fw fw-mobile"></i>
|
||||
<i class="fw fw-mobile device-type fw-2x"></i>
|
||||
{{/defineZone}}
|
||||
</div>
|
||||
<div class="col-lg-9">
|
||||
<div class="device-info">
|
||||
{{#defineZone "device-details-header"}}
|
||||
<h1 data-deviceid="{{device.deviceIdentifier}}"
|
||||
data-type="{{device.type}}"
|
||||
data-ownership="{{device.ownership}}"
|
||||
data-owner="{{device.owner}}">
|
||||
{{#if device.viewModel.model}}
|
||||
<h4>{{device.viewModel.vendor}} {{device.viewModel.model}}</h4>
|
||||
{{/if}}
|
||||
<h4>Ownership - <strong>{{device.viewModel.ownership}}</strong></h4>
|
||||
<h4>Device is
|
||||
<strong>
|
||||
{{#equal device.status "ACTIVE"}}Active{{/equal}}
|
||||
{{#equal device.status "INACTIVE"}}Inactive{{/equal}}
|
||||
{{#equal device.status "BLOCKED"}}Blocked{{/equal}}
|
||||
{{#equal device.status "REMOVED"}}Removed{{/equal}}
|
||||
{{#equal device.status "UNREACHABLE"}}Unreachable{{/equal}}
|
||||
</strong>
|
||||
</h4>
|
||||
{{/defineZone}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="media-body asset-desc add-padding-left-5x">
|
||||
{{#defineZone "overview-section"}}
|
||||
<div style="background: #11375B; color: #fff; padding: 10px; margin-bottom: 5px">
|
||||
Device Overview - {{label}}</div>
|
||||
{{unit "cdmf.unit.device.overview-section" device=device}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="vital-strip">
|
||||
{{#defineZone "device-details"}}
|
||||
{{/defineZone}}
|
||||
{{#defineZone "operation-status"}}{{/defineZone}}
|
||||
</div>
|
||||
{{#defineZone "device-opetations"}}
|
||||
<div style="background: #11375B; color: #fff; padding: 10px; margin-bottom: 5px">
|
||||
Operations
|
||||
<div class="operation-container">
|
||||
<div class="operation-title">
|
||||
<h4>Device Operations</h4>
|
||||
</div>
|
||||
<div class="add-margin-top-4x" style="height: 90px;">
|
||||
{{unit "cdmf.unit.device.operation-bar" device=device}}
|
||||
</div>
|
||||
{{/defineZone}}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="media tab-responsive">
|
||||
<div class="media-left col-xs-1 col-sm-1 col-md-2 col-lg-2 hidden-xs">
|
||||
<ul class="list-group nav nav-pills nav-stacked" role="tablist">
|
||||
<!-- /col-lg-4 -->
|
||||
<div class="col-lg-8">
|
||||
<ul class="nav nav-tabs">
|
||||
{{#defineZone "device-view-tabs"}}
|
||||
{{#defineZone "device-details-tab"}}
|
||||
<li role="presentation" class="list-group-item active">
|
||||
<a href="#device_details_tab" role="tab" data-toggle="tab"
|
||||
aria-controls="device_details_tab">
|
||||
<i class="icon fw fw-mobile"></i><span class="hidden-sm">Device Details</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/defineZone}}
|
||||
<li class="active"><a data-toggle="tab" href="#event_log">Operations Log</a></li>
|
||||
{{#defineZone "device-details-tab-injected"}}
|
||||
{{/defineZone}}
|
||||
{{#defineZone "device-details-tab-operations"}}
|
||||
<li role="presentation" class="list-group-item">
|
||||
<a href="#event_log_tab" role="tab" data-toggle="tab" aria-controls="event_log_tab">
|
||||
<i class="icon fw fw-text"></i><span class="hidden-sm">Operations Log</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/defineZone}}
|
||||
{{/defineZone}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="media-body add-padding-left-5x remove-padding-xs">
|
||||
<div class="panel-group tab-content remove-padding" id="tabs" role="tablist"
|
||||
data-status="{{device.isNotRemoved}}" aria-multiselectable="true">
|
||||
<div class="arrow-left hidden-xs"></div>
|
||||
|
||||
<div class="tab-content">
|
||||
{{#defineZone "device-view-tab-contents"}}
|
||||
{{#defineZone "device-details-tab-contents"}}
|
||||
<div class="message message-info">
|
||||
<h4 class="remove-margin">
|
||||
<i class="icon fw fw-info"></i>
|
||||
No Device details avaialbe yet.
|
||||
</h4>
|
||||
</div>
|
||||
{{/defineZone}}
|
||||
|
||||
{{#defineZone "device-view-tab-injected-conents"}}
|
||||
{{/defineZone}}
|
||||
|
||||
{{#defineZone "device-view-tab-operations-log-conents"}}
|
||||
<div class="panel panel-default visible-xs-block" role="tabpanel" id="event_log_tab">
|
||||
<div class="panel-heading visible-xs collapsed" id="event_log">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#tabs"
|
||||
href="#collapseFive" aria-expanded="true" aria-controls="collapseFive">
|
||||
<i class="fw fw-text fw-2x"></i>
|
||||
Operations Log
|
||||
<i class="caret-updown fw fw-down"></i>
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="panel-heading display-none-xs">
|
||||
Operations Log
|
||||
<span>
|
||||
<a href="javascript:void(0);" id="refresh-operations">
|
||||
<i class="fw fw-refresh"></i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div id="collapseFive" class="panel-collapse collapse in" role="tabpanel"
|
||||
aria-labelledby="event_log">
|
||||
<div class="panel-body">
|
||||
<span class="visible-xs add-padding-2x text-right">
|
||||
<a href="javascript:void(0);" id="refresh-operations">
|
||||
<i class="fw fw-refresh"></i>
|
||||
</a>
|
||||
</span>
|
||||
<div id="operations-spinner" class="wr-advance-operations-init hidden">
|
||||
<i class="fw fw-settings fw-spin fw-2x"></i> Loading Operations Log...
|
||||
</div>
|
||||
<div id="operations-log-container">
|
||||
<div class="message message-info">
|
||||
<h4 class="remove-margin">
|
||||
<i class="icon fw fw-info"></i>
|
||||
There are no operations, performed yet on this device.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-striped table-hover table-bordered display data-table"
|
||||
<div id="event_log" class="tab-pane fade in active">
|
||||
<div class="clearfix"></div>
|
||||
<div class="operation-log-container">
|
||||
<table class="table table-striped table-hover table-responsive list-table display responsive nowrap data-table"
|
||||
id="operation-log">
|
||||
<thead class="block">
|
||||
<tr class="sort-row">
|
||||
<!-- <th class="content-fill no-sort"></th> -->
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Office</th>
|
||||
<!-- <th>Age</th>
|
||||
<th>Start date</th>
|
||||
<th>Salary</th>
|
||||
<th class="no-sort"></th> -->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- <table class="table table-striped table-hover table-bordered display data-table"
|
||||
id="operations-log-table">
|
||||
<thead>
|
||||
<tr class="sort-row">
|
||||
@ -154,17 +112,17 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</table> -->
|
||||
</div>
|
||||
</div>
|
||||
{{#defineZone "device-view-tab-injected-conents"}}
|
||||
{{/defineZone}}
|
||||
{{/defineZone}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /col-lg-08 -->
|
||||
</div>
|
||||
<!-- /row -->
|
||||
{{else}}
|
||||
<h1 class="page-sub-title">
|
||||
Permission Denied
|
||||
|
||||
@ -2859,7 +2859,8 @@ a.ast-type-item:hover {
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
margin-right: 10px;
|
||||
color: #526A84;
|
||||
/*color: #526A84;*/
|
||||
color: #333;
|
||||
min-width: 70px;
|
||||
background: #fafafa;
|
||||
padding: 2px 10px 10px 10px;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user