mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-16 12:38:13 +00:00
implement the confidential fields of metadata dashboard
This commit is contained in:
parent
5d3b534086
commit
2a4f281ba5
@ -23,12 +23,8 @@ import play.mvc.Result;
|
|||||||
import play.Logger;
|
import play.Logger;
|
||||||
import play.mvc.Security;
|
import play.mvc.Security;
|
||||||
import utils.Tree;
|
import utils.Tree;
|
||||||
import views.html.index;
|
import views.html.*;
|
||||||
import views.html.login;
|
|
||||||
import views.html.lineage;
|
|
||||||
import views.html.schemaHistory;
|
|
||||||
import views.html.scriptFinder;
|
|
||||||
import views.html.idpc;
|
|
||||||
import static play.data.Form.form;
|
import static play.data.Form.form;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import security.AuthenticationManager;
|
import security.AuthenticationManager;
|
||||||
@ -143,6 +139,18 @@ public class Application extends Controller
|
|||||||
return ok(idpc.render(username, isInternal));
|
return ok(idpc.render(username, isInternal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Security.Authenticated(Secured.class)
|
||||||
|
public static Result dashboard()
|
||||||
|
{
|
||||||
|
Boolean isInternal = Play.application().configuration().getBoolean(LINKEDIN_INTERNAL_KEY, false);
|
||||||
|
String username = session("user");
|
||||||
|
if (username == null)
|
||||||
|
{
|
||||||
|
username = "";
|
||||||
|
}
|
||||||
|
return ok(dashboard.render(username, isInternal));
|
||||||
|
}
|
||||||
|
|
||||||
public static Result login()
|
public static Result login()
|
||||||
{
|
{
|
||||||
Boolean isInternal = Play.application().configuration().getBoolean(LINKEDIN_INTERNAL_KEY, false);
|
Boolean isInternal = Play.application().configuration().getBoolean(LINKEDIN_INTERNAL_KEY, false);
|
||||||
|
|||||||
81
web/app/controllers/api/v1/Dashboard.java
Normal file
81
web/app/controllers/api/v1/Dashboard.java
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 LinkedIn Corp. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
package controllers.api.v1;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import dao.DashboardDAO;
|
||||||
|
import dao.JiraDAO;
|
||||||
|
import dao.UserDAO;
|
||||||
|
import models.JiraTicket;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import play.Logger;
|
||||||
|
import play.libs.Json;
|
||||||
|
import play.mvc.Controller;
|
||||||
|
import play.mvc.Result;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Dashboard extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
public static Result getConfidentialDatasetsPercentage(String managerId)
|
||||||
|
{
|
||||||
|
return ok(DashboardDAO.getConfidentialPercentageByManagerId(managerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result getPagedConfidentialDatasets(String managerId)
|
||||||
|
{
|
||||||
|
int page = 1;
|
||||||
|
String pageStr = request().getQueryString("page");
|
||||||
|
if (StringUtils.isBlank(pageStr))
|
||||||
|
{
|
||||||
|
page = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
page = Integer.parseInt(pageStr);
|
||||||
|
}
|
||||||
|
catch(NumberFormatException e)
|
||||||
|
{
|
||||||
|
Logger.error("Dashboard Controller getPagedConfidentialDatasets wrong page parameter. Error message: " + e.getMessage());
|
||||||
|
page = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = 10;
|
||||||
|
String sizeStr = request().getQueryString("size");
|
||||||
|
if (StringUtils.isBlank(sizeStr))
|
||||||
|
{
|
||||||
|
size = 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
size = Integer.parseInt(sizeStr);
|
||||||
|
}
|
||||||
|
catch(NumberFormatException e)
|
||||||
|
{
|
||||||
|
Logger.error("Dashboard Controller getPagedConfidentialDatasets wrong size parameter. Error message: " + e.getMessage());
|
||||||
|
size = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok(DashboardDAO.getPagedConfidentialDatasetsByManagerId(managerId, page, size));
|
||||||
|
}
|
||||||
|
}
|
||||||
230
web/app/dao/DashboardDAO.java
Normal file
230
web/app/dao/DashboardDAO.java
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 LinkedIn Corp. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
package dao;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import models.*;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
import play.Logger;
|
||||||
|
import play.libs.Json;
|
||||||
|
|
||||||
|
public class DashboardDAO extends AbstractMySQLOpenSourceDAO
|
||||||
|
{
|
||||||
|
private final static String GET_ORG_HIERARCHY = "SELECT display_name, org_hierarchy FROM " +
|
||||||
|
"dir_external_user_info WHERE user_id = ? limit 1";
|
||||||
|
|
||||||
|
private final static String GET_CONFIDENTIAL_DATASETS = "SELECT SQL_CALC_FOUND_ROWS o.dataset_id, " +
|
||||||
|
"GROUP_CONCAT(o.owner_id ORDER BY o.owner_id ASC SEPARATOR ',') as owner_id, d.name FROM " +
|
||||||
|
"dataset_owner o JOIN dict_dataset d ON o.dataset_id = d.id WHERE o.dataset_id in " +
|
||||||
|
"( SELECT DISTINCT dataset_id from dict_pii_field )" +
|
||||||
|
" and owner_id in ( " +
|
||||||
|
"SELECT user_id FROM dir_external_user_info WHERE org_hierarchy = ? or org_hierarchy like ?) " +
|
||||||
|
"GROUP BY o.dataset_id, d.name ORDER BY d.name LIMIT ?, ?";
|
||||||
|
|
||||||
|
private final static String GET_TOP_LEVEL_CONFIDENTIAL_DATASETS = "SELECT SQL_CALC_FOUND_ROWS o.dataset_id, " +
|
||||||
|
"GROUP_CONCAT(o.owner_id ORDER BY o.owner_id ASC SEPARATOR ',') as owner_id, d.name FROM " +
|
||||||
|
"dataset_owner o JOIN dict_dataset d ON o.dataset_id = d.id WHERE o.dataset_id in " +
|
||||||
|
"( SELECT DISTINCT dataset_id from dict_pii_field )" +
|
||||||
|
" and owner_id in ( " +
|
||||||
|
"SELECT user_id FROM dir_external_user_info WHERE org_hierarchy = ? or org_hierarchy like ?) " +
|
||||||
|
"GROUP BY o.dataset_id, d.name ORDER BY d.name LIMIT ?, ?";
|
||||||
|
|
||||||
|
private final static String GET_CONFIDENTIAL_INFO = "SELECT count(distinct o.dataset_id) as count " +
|
||||||
|
"FROM dataset_owner o JOIN dict_dataset d ON o.dataset_id = d.id " +
|
||||||
|
"WHERE o.dataset_id in ( SELECT DISTINCT dataset_id from dict_pii_field ) and owner_id in ( " +
|
||||||
|
"SELECT user_id FROM dir_external_user_info WHERE org_hierarchy = ? or org_hierarchy like ?)";
|
||||||
|
|
||||||
|
private final static String GET_TOP_LEVEL_CONFIDENTIAL_INFO = "SELECT count(distinct o.dataset_id) as count " +
|
||||||
|
"FROM dataset_owner o JOIN dict_dataset d ON o.dataset_id = d.id " +
|
||||||
|
"WHERE o.dataset_id in ( SELECT DISTINCT dataset_id from dict_pii_field ) and owner_id in ( " +
|
||||||
|
"SELECT user_id FROM dir_external_user_info WHERE org_hierarchy = ? or org_hierarchy like ?)";
|
||||||
|
|
||||||
|
private final static String GET_CONFIDENTIAL_FIELDS = "SELECT field_name " +
|
||||||
|
"FROM dict_pii_field WHERE dataset_id = ?";
|
||||||
|
|
||||||
|
|
||||||
|
public static ObjectNode getConfidentialPercentageByManagerId(String managerId) {
|
||||||
|
|
||||||
|
ObjectNode resultNode = Json.newObject();
|
||||||
|
ConfidentialFieldsOwner currentUser = null;
|
||||||
|
List<ConfidentialFieldsOwner> memberList = new ArrayList<ConfidentialFieldsOwner>();
|
||||||
|
if (StringUtils.isNotBlank(managerId))
|
||||||
|
{
|
||||||
|
List<LdapInfo> ldapInfoList = JiraDAO.getCurrentUserLdapInfo(managerId);
|
||||||
|
if (ldapInfoList != null && ldapInfoList.size() > 0)
|
||||||
|
{
|
||||||
|
LdapInfo ldapInfo = ldapInfoList.get(0);
|
||||||
|
if (ldapInfo != null)
|
||||||
|
{
|
||||||
|
currentUser = new ConfidentialFieldsOwner();
|
||||||
|
currentUser.displayName = ldapInfo.displayName;
|
||||||
|
currentUser.iconUrl = ldapInfo.iconUrl;
|
||||||
|
currentUser.managerUserId = ldapInfo.managerUserId;
|
||||||
|
currentUser.orgHierarchy = ldapInfo.orgHierarchy;
|
||||||
|
currentUser.userName = ldapInfo.userName;
|
||||||
|
if (StringUtils.isNotBlank(ldapInfo.orgHierarchy)) {
|
||||||
|
currentUser.potentialDatasets = getJdbcTemplate().queryForObject(
|
||||||
|
GET_CONFIDENTIAL_INFO,
|
||||||
|
Long.class,
|
||||||
|
currentUser.orgHierarchy,
|
||||||
|
currentUser.orgHierarchy + "/%");
|
||||||
|
}
|
||||||
|
else if (managerId.equalsIgnoreCase("jweiner"))
|
||||||
|
{
|
||||||
|
currentUser.potentialDatasets = getJdbcTemplate().queryForObject(
|
||||||
|
GET_CONFIDENTIAL_INFO,
|
||||||
|
Long.class,
|
||||||
|
"/" + currentUser.userName,
|
||||||
|
"/" + currentUser.userName + "/%");
|
||||||
|
}
|
||||||
|
currentUser.confirmed = 0L;
|
||||||
|
if (currentUser.potentialDatasets != 0)
|
||||||
|
{
|
||||||
|
currentUser.completed = 100.0 * (currentUser.confirmed / currentUser.potentialDatasets);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentUser.completed = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<LdapInfo> members = JiraDAO.getFirstLevelLdapInfo(managerId);
|
||||||
|
if (members != null)
|
||||||
|
{
|
||||||
|
for(LdapInfo member : members)
|
||||||
|
{
|
||||||
|
if (member != null && StringUtils.isNotBlank(member.orgHierarchy))
|
||||||
|
{
|
||||||
|
ConfidentialFieldsOwner owner = new ConfidentialFieldsOwner();
|
||||||
|
owner.displayName = member.displayName;
|
||||||
|
owner.fullName = member.fullName;
|
||||||
|
owner.userName = member.userName;
|
||||||
|
owner.iconUrl = member.iconUrl;
|
||||||
|
owner.managerUserId = member.managerUserId;
|
||||||
|
owner.orgHierarchy = member.orgHierarchy;
|
||||||
|
owner.potentialDatasets = getJdbcTemplate().queryForObject(
|
||||||
|
GET_CONFIDENTIAL_INFO,
|
||||||
|
Long.class,
|
||||||
|
owner.orgHierarchy,
|
||||||
|
owner.orgHierarchy + "/%");
|
||||||
|
|
||||||
|
owner.confirmed = 0L;
|
||||||
|
if (owner.potentialDatasets != 0)
|
||||||
|
{
|
||||||
|
owner.completed = 100.0 * (owner.confirmed / owner.potentialDatasets);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
owner.completed = 0.0;
|
||||||
|
}
|
||||||
|
memberList.add(owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultNode.put("status", "ok");
|
||||||
|
resultNode.set("currentUser", Json.toJson(currentUser));
|
||||||
|
resultNode.set("members", Json.toJson(memberList));
|
||||||
|
return resultNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectNode getPagedConfidentialDatasetsByManagerId(String managerId, Integer page, Integer size) {
|
||||||
|
|
||||||
|
ObjectNode result = Json.newObject();
|
||||||
|
|
||||||
|
javax.sql.DataSource ds = getJdbcTemplate().getDataSource();
|
||||||
|
DataSourceTransactionManager tm = new DataSourceTransactionManager(ds);
|
||||||
|
TransactionTemplate txTemplate = new TransactionTemplate(tm);
|
||||||
|
result = txTemplate.execute(new TransactionCallback<ObjectNode>()
|
||||||
|
{
|
||||||
|
public ObjectNode doInTransaction(TransactionStatus status)
|
||||||
|
{
|
||||||
|
ObjectNode resultNode = Json.newObject();
|
||||||
|
Long count = 0L;
|
||||||
|
List<DatasetConfidential> confidentialList = new ArrayList<DatasetConfidential>();
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(managerId))
|
||||||
|
{
|
||||||
|
List<LdapInfo> ldapInfoList = JiraDAO.getCurrentUserLdapInfo(managerId);
|
||||||
|
if (ldapInfoList != null && ldapInfoList.size() > 0)
|
||||||
|
{
|
||||||
|
LdapInfo ldapInfo = ldapInfoList.get(0);
|
||||||
|
if (ldapInfo != null)
|
||||||
|
{
|
||||||
|
List<Map<String, Object>> rows = null;
|
||||||
|
if (StringUtils.isNotBlank(ldapInfo.orgHierarchy)) {
|
||||||
|
rows = getJdbcTemplate().queryForList(
|
||||||
|
GET_CONFIDENTIAL_DATASETS,
|
||||||
|
ldapInfo.orgHierarchy,
|
||||||
|
ldapInfo.orgHierarchy + "/%",
|
||||||
|
(page - 1) * size,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
else if (managerId.equalsIgnoreCase("jweiner"))
|
||||||
|
{
|
||||||
|
rows = getJdbcTemplate().queryForList(
|
||||||
|
GET_CONFIDENTIAL_DATASETS,
|
||||||
|
"/" + ldapInfo.userName,
|
||||||
|
"/" + ldapInfo.userName + "/%",
|
||||||
|
(page - 1) * size,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
count = getJdbcTemplate().queryForObject(
|
||||||
|
"SELECT FOUND_ROWS()",
|
||||||
|
Long.class);
|
||||||
|
}
|
||||||
|
catch(EmptyResultDataAccessException e)
|
||||||
|
{
|
||||||
|
Logger.error("Exception = " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map row : rows) {
|
||||||
|
DatasetConfidential datasetConfidential = new DatasetConfidential();
|
||||||
|
datasetConfidential.datasetId = (Long) row.get("dataset_id");
|
||||||
|
datasetConfidential.datasetName = (String) row.get("name");
|
||||||
|
datasetConfidential.ownerId = (String) row.get("owner_id");
|
||||||
|
if (datasetConfidential.datasetId != null && datasetConfidential.datasetId > 0) {
|
||||||
|
datasetConfidential.confidentialFieldList =
|
||||||
|
getJdbcTemplate().queryForList(
|
||||||
|
GET_CONFIDENTIAL_FIELDS,
|
||||||
|
String.class,
|
||||||
|
datasetConfidential.datasetId);
|
||||||
|
}
|
||||||
|
confidentialList.add(datasetConfidential);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultNode.put("status", "ok");
|
||||||
|
resultNode.put("count", count);
|
||||||
|
resultNode.put("page", page);
|
||||||
|
resultNode.put("itemsPerPage", size);
|
||||||
|
resultNode.put("totalPages", (int) Math.ceil(count / ((double) size)));
|
||||||
|
resultNode.set("datasets", Json.toJson(confidentialList));
|
||||||
|
return resultNode;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
web/app/models/ConfidentialFieldsOwner.java
Normal file
28
web/app/models/ConfidentialFieldsOwner.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 LinkedIn Corp. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
package models;
|
||||||
|
|
||||||
|
public class ConfidentialFieldsOwner {
|
||||||
|
|
||||||
|
public String userName;
|
||||||
|
public String fullName;
|
||||||
|
public String displayName;
|
||||||
|
public String email;
|
||||||
|
public String managerUserId;
|
||||||
|
public String orgHierarchy;
|
||||||
|
public String iconUrl;
|
||||||
|
public Long potentialDatasets;
|
||||||
|
public Long confirmed;
|
||||||
|
public Double completed;
|
||||||
|
}
|
||||||
24
web/app/models/DatasetConfidential.java
Normal file
24
web/app/models/DatasetConfidential.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 LinkedIn Corp. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
package models;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DatasetConfidential {
|
||||||
|
|
||||||
|
public Long datasetId;
|
||||||
|
public String ownerId;
|
||||||
|
public String datasetName;
|
||||||
|
public List<String> confidentialFieldList;
|
||||||
|
}
|
||||||
189
web/app/views/dashboard.scala.html
Normal file
189
web/app/views/dashboard.scala.html
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
@(user: String, isInternal:Boolean)
|
||||||
|
@main(user, "", isInternal) {
|
||||||
|
<div id="content">
|
||||||
|
<script type="text/x-handlebars" id="dashboard">
|
||||||
|
<div id="schemaView" class="container-fluid">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<h3>Metadata Dashboard</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12 well well-sm">
|
||||||
|
<ul class="breadcrumbs">
|
||||||
|
{{#each breadcrumbs as |crumb|}}
|
||||||
|
<li>
|
||||||
|
<a href={{crumb.urn}} title={{crumb.title }}>
|
||||||
|
{{ crumb.title }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul id="dashboardtabs" class="nav nav-tabs">
|
||||||
|
<li id="confidentialpage">
|
||||||
|
<a id="confidentiallink" data-toggle="tab" href="#confidentialtab">Confidential Fields</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div id="confidentialtab" class="tab-pane">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
|
<h4>Confidential Fields for {{ currentConfidentialFieldsUser.displayName }}</h4>
|
||||||
|
<table class="table table-bordered table-condensed table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">Name</th>
|
||||||
|
<th class="text-center">Completion</th>
|
||||||
|
<th class="text-center">Total Potential</th>
|
||||||
|
<th class="text-center">Confirmed</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src={{currentConfidentialFieldsUser.iconUrl}} title={{currentConfidentialFieldsUser.displayName}}
|
||||||
|
width="25px"
|
||||||
|
height="25px"/>
|
||||||
|
<a href='metadata#/dashboard/{{currentConfidentialFieldsUser.userName}}' title={{currentConfidentialFieldsUser.displayName}}>
|
||||||
|
{{ currentConfidentialFieldsUser.displayName }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">{{ currentConfidentialFieldsUser.completed }}%</td>
|
||||||
|
<td class="text-center">{{ currentConfidentialFieldsUser.potentialDatasets }}</td>
|
||||||
|
<td class="text-center">{{ currentConfidentialFieldsUser.confirmed }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h4>Ticket Roll-Up for Individual User</h4>
|
||||||
|
<table class="table table-bordered table-condensed table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">Name</th>
|
||||||
|
<th class="text-center">Completion</th>
|
||||||
|
<th class="text-center">Total Potential</th>
|
||||||
|
<th class="text-center">Confirmed</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#if userNoMembers}}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
This user has no one that reports to them.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{else}}
|
||||||
|
{{#each confidentialFieldsOwners as |user|}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src={{user.iconUrl}} title={{user.displayName}}
|
||||||
|
width="25px"
|
||||||
|
height="25px"/>
|
||||||
|
<a href='metadata#/dashboard/{{user.userName}}' title={{user.displayName}}>
|
||||||
|
{{ user.displayName }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">{{ user.completed }}%</td>
|
||||||
|
<td class="text-center">{{ user.potentialDatasets }}</td>
|
||||||
|
<td class="text-center">{{ user.confirmed }}</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-md-8">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-9">
|
||||||
|
<h4>List of Potential Datasets</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-pagination">
|
||||||
|
<ul class="pager">
|
||||||
|
{{#unless cfFirst}}
|
||||||
|
<li class="previous">
|
||||||
|
<a {{ action "prevCfPage" }}>
|
||||||
|
← Prev
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/unless}}
|
||||||
|
<li>
|
||||||
|
{{ confidentialFieldsDatasets.count }} datasets - page {{ confidentialFieldsDatasets.page }} of {{ confidentialFieldsDatasets.totalPages }}
|
||||||
|
</li>
|
||||||
|
{{#unless cfLast}}
|
||||||
|
<li class="next">
|
||||||
|
<a {{ action "nextCfPage" }}>
|
||||||
|
Next →
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/unless}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<table class="table table-bordered table-condensed table-hover table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">Dataset</th>
|
||||||
|
<th class="text-center">Fields</th>
|
||||||
|
<th class="text-center">Owners</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#if ticketsInProgress}}
|
||||||
|
<tr>
|
||||||
|
<td colspan="8" class="text-center">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<i class="fa fa-spinner spinning fa-4x">
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{else}}
|
||||||
|
{{#if userNoConfidentialFields}}
|
||||||
|
<tr>
|
||||||
|
<td colspan="8">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12 text-center">
|
||||||
|
This user has no datasets with confidential fields.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{else}}
|
||||||
|
{{#each confidentialFieldsDatasets.datasets as |dataset|}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/#/datasets/{{dataset.datasetId}}">
|
||||||
|
{{ dataset.datasetName }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{{ dataset.confidentialFieldList }}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">{{ dataset.ownerId }}</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="@routes.Assets.at("vendors/ember-2.6.2/ember-template-compiler.js")" type="text/javascript"></script>
|
||||||
|
<script src="@routes.Assets.at("vendors/ember-2.6.2/ember.js")" type="text/javascript"></script>
|
||||||
|
<script src="@routes.Assets.at("javascripts/dashboard.js")" type="text/javascript"></script>
|
||||||
|
}
|
||||||
@ -90,6 +90,13 @@
|
|||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
@if(isInternal) {
|
@if(isInternal) {
|
||||||
|
<li>
|
||||||
|
<a href="/metadata">
|
||||||
|
<span>
|
||||||
|
Metadata Dashboard
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/scriptFinder">
|
<a href="/scriptFinder">
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@ -35,6 +35,8 @@ GET /lineage/metric/:id controllers.Application.metr
|
|||||||
|
|
||||||
GET /lineage/flow/:application/:project/:flow controllers.Application.flowLineage(application: String, project: String, flow: String)
|
GET /lineage/flow/:application/:project/:flow controllers.Application.flowLineage(application: String, project: String, flow: String)
|
||||||
|
|
||||||
|
GET /metadata controllers.Application.dashboard()
|
||||||
|
|
||||||
GET /scriptFinder controllers.Application.scriptFinder()
|
GET /scriptFinder controllers.Application.scriptFinder()
|
||||||
|
|
||||||
GET /schemaHistory controllers.Application.schemaHistory()
|
GET /schemaHistory controllers.Application.schemaHistory()
|
||||||
@ -213,6 +215,10 @@ GET /api/v1/jira/ldapinfo controllers.api.v1.Jira.getL
|
|||||||
|
|
||||||
GET /api/v1/jira/members/:managerId controllers.api.v1.Jira.getFirstLevelLdapInfo(managerId :String)
|
GET /api/v1/jira/members/:managerId controllers.api.v1.Jira.getFirstLevelLdapInfo(managerId :String)
|
||||||
|
|
||||||
|
GET /api/v1/metadata/dashboard/:managerId controllers.api.v1.Dashboard.getConfidentialDatasetsPercentage(managerId :String)
|
||||||
|
|
||||||
|
GET /api/v1/metadata/dataset/:managerId controllers.api.v1.Dashboard.getPagedConfidentialDatasets(managerId :String)
|
||||||
|
|
||||||
GET /api/v1/scriptFinder/scripts controllers.api.v1.ScriptFinder.getScripts()
|
GET /api/v1/scriptFinder/scripts controllers.api.v1.ScriptFinder.getScripts()
|
||||||
|
|
||||||
GET /api/v1/scriptFinder/scripts/types controllers.api.v1.ScriptFinder.getAllScriptTypes()
|
GET /api/v1/scriptFinder/scripts/types controllers.api.v1.ScriptFinder.getAllScriptTypes()
|
||||||
|
|||||||
193
web/public/javascripts/dashboard.js
Normal file
193
web/public/javascripts/dashboard.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
(function ($) {
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
App = Ember.Application.create({rootElement: "#content"});
|
||||||
|
|
||||||
|
if (Ember.Debug && typeof Ember.Debug.registerDeprecationHandler === 'function') {
|
||||||
|
Ember.Debug.registerDeprecationHandler(function(message, options, next) {
|
||||||
|
if (options && options.id && options.id == 'ember-routing.router-resource') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next(message, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
App.Router.map(function() {
|
||||||
|
this.resource('dashboard', function(){
|
||||||
|
this.resource('user', {path: '/:user'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
App.IndexRoute = Ember.Route.extend({
|
||||||
|
redirect: function() {
|
||||||
|
this.transitionTo('user', "jweiner");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var genBreadcrumbs = function(urn) {
|
||||||
|
var breadcrumbs = []
|
||||||
|
var b = urn.split('/')
|
||||||
|
b.shift();
|
||||||
|
for(var i = 0; i < b.length; i++) {
|
||||||
|
var updatedUrn = "/metadata#/dashboard/" + b[i]
|
||||||
|
if(i === 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
breadcrumbs.push({title: b[i], urn: updatedUrn})
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
breadcrumbs.push({title: b[i], urn: updatedUrn})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return breadcrumbs
|
||||||
|
}
|
||||||
|
|
||||||
|
var setActiveTab = function(){
|
||||||
|
$('#dashboardtabs a:last').tab("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCfDatasets(user, page, size)
|
||||||
|
{
|
||||||
|
if (!user)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!page)
|
||||||
|
page = 1;
|
||||||
|
if (!size)
|
||||||
|
size = 10;
|
||||||
|
var datasetsUrl = '/api/v1/metadata/dataset/' + user + '?page=' + page + '&size=' + size;
|
||||||
|
$.get(datasetsUrl, function(data) {
|
||||||
|
if (data && data.status == "ok") {
|
||||||
|
var currentPage = data.page;
|
||||||
|
var totalPage = data.totalPages;
|
||||||
|
if (currentPage == 1)
|
||||||
|
{
|
||||||
|
jiraController.set('cfFirst', true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jiraController.set('cfFirst', false);
|
||||||
|
}
|
||||||
|
if (currentPage == totalPage)
|
||||||
|
{
|
||||||
|
jiraController.set('cfLast', true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jiraController.set('cfLast', false);
|
||||||
|
}
|
||||||
|
jiraController.set('confidentialFieldsDatasets', data);
|
||||||
|
jiraController.set('currentCfPage', data.page);
|
||||||
|
if (data.datasets && data.datasets.length > 0)
|
||||||
|
{
|
||||||
|
jiraController.set('userNoConfidentialFields', false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jiraController.set('userNoConfidentialFields', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var jiraController = null;
|
||||||
|
var hierarchy = '/jweiner';
|
||||||
|
var breadcrumbs;
|
||||||
|
var sortOptions = ['Assignee First', 'Jira Status First', 'Directory Path First'];
|
||||||
|
var selectedUser = {
|
||||||
|
'userId': 'jweiner',
|
||||||
|
'displayName': 'jweiner',
|
||||||
|
'headlessTicketsCompletion': 0,
|
||||||
|
'totalHeadlessTickets': 0,
|
||||||
|
'openedHeadlessTickets': 0,
|
||||||
|
'closedHeadlessTickets': 0,
|
||||||
|
'cfCompletion': 0,
|
||||||
|
'cfTotalDatasets': 0,
|
||||||
|
'cfConfirmedDatasets': 0,
|
||||||
|
'url': '/metadata#/dashboard/jweiner'};
|
||||||
|
setTimeout(setActiveTab, 500);
|
||||||
|
|
||||||
|
App.DashboardRoute = Ember.Route.extend({
|
||||||
|
setupController: function(controller) {
|
||||||
|
jiraController = controller;
|
||||||
|
breadcrumbs = genBreadcrumbs(hierarchy);
|
||||||
|
jiraController.set('breadcrumbs', breadcrumbs);
|
||||||
|
jiraController.set('selectedUser', selectedUser);
|
||||||
|
jiraController.set('sortOptions', sortOptions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
App.UserRoute = Ember.Route.extend({
|
||||||
|
setupController: function(controller, params) {
|
||||||
|
if (params && params.user)
|
||||||
|
{
|
||||||
|
jiraController.set('ticketsInProgress', true);
|
||||||
|
var confidentialUrl = 'api/v1/metadata/dashboard/' + params.user;
|
||||||
|
var headlessTickets;
|
||||||
|
var userTickets;
|
||||||
|
$.get(confidentialUrl, function(data) {
|
||||||
|
jiraController.set('ticketsInProgress', false);
|
||||||
|
if (data && data.status == "ok") {
|
||||||
|
jiraController.set('membersInProgress', true);
|
||||||
|
jiraController.set('confidentialFieldsOwners', data.members);
|
||||||
|
if (data.members && data.members.length > 0)
|
||||||
|
{
|
||||||
|
jiraController.set('userNoMembers', false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jiraController.set('userNoMembers', true);
|
||||||
|
}
|
||||||
|
jiraController.set('currentConfidentialFieldsUser', data.currentUser);
|
||||||
|
var breadcrumbs;
|
||||||
|
if (data.currentUser.orgHierarchy)
|
||||||
|
{
|
||||||
|
breadcrumbs = genBreadcrumbs(data.currentUser.orgHierarchy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var hierarchy = '/jweiner';
|
||||||
|
breadcrumbs = genBreadcrumbs(hierarchy);
|
||||||
|
}
|
||||||
|
jiraController.set('breadcrumbs', breadcrumbs);
|
||||||
|
|
||||||
|
refreshCfDatasets(params.user, 1, 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
App.DashboardController = Ember.Controller.extend({
|
||||||
|
cfFirst: false,
|
||||||
|
cfLast: false,
|
||||||
|
actions: {
|
||||||
|
prevCfPage: function() {
|
||||||
|
var cfInfo = this.get("confidentialFieldsDatasets");
|
||||||
|
var user = this.get("currentConfidentialFieldsUser");
|
||||||
|
if (cfInfo && user) {
|
||||||
|
var currentPage = parseInt(cfInfo.page) - 1;
|
||||||
|
if (currentPage > 0) {
|
||||||
|
refreshCfDatasets(user.userName, currentPage, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nextCfPage: function() {
|
||||||
|
var cfInfo = this.get("confidentialFieldsDatasets");
|
||||||
|
var user = this.get("currentConfidentialFieldsUser");
|
||||||
|
if (cfInfo && user) {
|
||||||
|
var currentPage = parseInt(cfInfo.page) + 1;
|
||||||
|
var totalPages = cfInfo.totalPages;
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
refreshCfDatasets(user.userName, currentPage, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
})(jQuery)
|
||||||
Loading…
x
Reference in New Issue
Block a user