332 lines
11 KiB
Plaintext
332 lines
11 KiB
Plaintext
@using Server.Models
|
|
@using System.Web
|
|
@model HomeIndexViewModel
|
|
@{
|
|
ViewData["Title"] = "Home Page";
|
|
int i = 0;
|
|
Dictionary<int, string> domains = [];
|
|
Model.Searchdomains.ForEach(domain =>
|
|
{
|
|
domains[i++] = domain;
|
|
});
|
|
}
|
|
|
|
<div class="container-fluid mt-4">
|
|
<div class="row">
|
|
|
|
<!-- Sidebar -->
|
|
<div class="col-md-4 sidebar">
|
|
<div class="card">
|
|
<div class="card-body p-2">
|
|
<ul class="list-group list-group-flush mb-2" style="max-height: 60vh; overflow-y: auto;">
|
|
@foreach (var domain in domains)
|
|
{
|
|
<li id="sidebar_domain_@(domain.Key)" class="domain-item list-group-item list-group-item-action text-nowrap" style="width: max-content" title="@domain.Value" onclick="selectDomain(@(domain.Key))">
|
|
@domain.Value
|
|
</li>
|
|
}
|
|
</ul>
|
|
<button class="btn btn-primary w-100">Add</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="col col-md-8">
|
|
|
|
<div class="card section-card">
|
|
<div class="card-body">
|
|
|
|
<!-- Header -->
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h4 class="mb-0 text-nowrap overflow-auto">Searchdomain1</h4>
|
|
<div class="col-md-3 text-end w-auto">
|
|
<button class="btn btn-warning btn-sm me-2">Rename</button>
|
|
<button class="btn btn-danger btn-sm">Delete</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings -->
|
|
<div class="row align-items-center mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label">Settings</label>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
placeholder="JSON-string"
|
|
disabled
|
|
/>
|
|
</div>
|
|
<div class="col-md-2 mt-3 mt-md-0">
|
|
<button class="btn btn-warning w-100">Update</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Cache -->
|
|
<div class="d-flex align-items-center mb-4">
|
|
<div class="me-3">
|
|
<strong>Cache utilization:</strong> 2.47MiB
|
|
</div>
|
|
<button class="btn btn-primary btn-sm">Reset</button>
|
|
</div>
|
|
|
|
<!-- Recent Queries -->
|
|
<div class="card section-card mb-4">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<strong>Recent queries</strong>
|
|
<input
|
|
type="text"
|
|
class="form-control form-control-sm w-25"
|
|
placeholder="filter"
|
|
/>
|
|
</div>
|
|
|
|
@* <div class="list-row">
|
|
<span>Some test query</span>
|
|
<button class="btn btn-primary btn-sm">Details</button>
|
|
</div>
|
|
<div class="list-row">
|
|
<span>Some other test query</span>
|
|
<button class="btn btn-primary btn-sm">Details</button>
|
|
</div> *@
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Entities -->
|
|
<div class="card section-card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<strong>Entities</strong>
|
|
<input
|
|
id="entitiesFilter"
|
|
type="text"
|
|
class="form-control form-control-sm w-25"
|
|
placeholder="filter"
|
|
/>
|
|
</div>
|
|
<div class="spinner d-none"></div>
|
|
<table id="entitiesTable" class="table table-striped" style="max-height: 60vh; overflow-y: auto; display: block;">
|
|
<thead>
|
|
<tr>
|
|
<th class="visually-hidden">Name</th>
|
|
<th class="visually-hidden">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table>
|
|
|
|
@* <div class="list-row">
|
|
<span>Someentity</span>
|
|
<button class="btn btn-primary btn-sm">Details</button>
|
|
</div>
|
|
<div class="list-row">
|
|
<span>Some other test query</span>
|
|
<button class="btn btn-primary btn-sm">Details</button>
|
|
</div> *@
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Entity Details Modal -->
|
|
<div class="modal fade" id="entityDetailsModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="entityDetailsTitle">Entity Details</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<!-- Attributes -->
|
|
<h6>Attributes</h6>
|
|
<table class="table table-sm table-bordered mb-4">
|
|
<thead>
|
|
<tr>
|
|
<th>Key</th>
|
|
<th>Value</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="entityAttributesBody">
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- Datapoints -->
|
|
<h6>Datapoints</h6>
|
|
<table class="table table-sm table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>ProbMethod</th>
|
|
<th>SimilarityMethod</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="entityDatapointsBody">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
|
Close
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<script>
|
|
var domains = JSON.parse('@Html.Raw(System.Text.Json.JsonSerializer.Serialize(domains))');
|
|
var entities = null;
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const filterInput = document.getElementById('entitiesFilter');
|
|
|
|
filterInput.addEventListener('input', () => {
|
|
populateEntitiesTable(filterInput.value);
|
|
});
|
|
});
|
|
|
|
function selectDomain(domainKey) {
|
|
// Deselect all domain items
|
|
document.querySelectorAll('.domain-item').forEach(item => {
|
|
item.classList.remove('active');
|
|
});
|
|
|
|
// Select the clicked domain item
|
|
var selectedItem = document.getElementById('sidebar_domain_' + domainKey);
|
|
selectedItem.classList.add('active');
|
|
|
|
// Update main content header
|
|
var domainName = domains[domainKey];
|
|
document.querySelector('.section-card h4').innerText = domainName;
|
|
|
|
// Request the entities from that searchdomain
|
|
let url = `/Entity/List?searchdomain=${encodeURIComponent(domainName)}&returnEmbeddings=false`;
|
|
let table = document.querySelector("#entitiesTable").parentElement;
|
|
clearEntitiesTable();
|
|
showEntitiesLoading(table);
|
|
fetch(url)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
entities = data.Results;
|
|
populateEntitiesTable();
|
|
hideEntitiesLoading(table);
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching entities:', error);
|
|
flagSearchdomainAsErroneous(domainKey);
|
|
hideEntitiesLoading(table);
|
|
});
|
|
}
|
|
|
|
function clearEntitiesTable() {
|
|
var tableBody = document.querySelector('#entitiesTable tbody');
|
|
tableBody.innerHTML = '';
|
|
}
|
|
|
|
function populateEntitiesTable(filterText = '') {
|
|
if (!entities) return;
|
|
|
|
var tableBody = document.querySelector('#entitiesTable tbody');
|
|
tableBody.innerHTML = '';
|
|
|
|
const normalizedFilter = filterText.toLowerCase();
|
|
|
|
entities
|
|
.filter(e => e.Name.toLowerCase().includes(normalizedFilter))
|
|
.forEach(entity => {
|
|
var row = document.createElement('tr');
|
|
|
|
var nameCell = document.createElement('td');
|
|
nameCell.textContent = entity.Name;
|
|
row.appendChild(nameCell);
|
|
|
|
var actionCell = document.createElement('td');
|
|
var detailsButton = document.createElement('button');
|
|
detailsButton.className = 'btn btn-primary btn-sm';
|
|
detailsButton.textContent = 'Details';
|
|
detailsButton.setAttribute("data-index", entities.findIndex(en => en == entity));
|
|
detailsButton.addEventListener('click', () => {
|
|
showEntityDetails(entity);
|
|
});
|
|
|
|
actionCell.appendChild(detailsButton);
|
|
row.appendChild(actionCell);
|
|
|
|
tableBody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
function flagSearchdomainAsErroneous(domainKey) {
|
|
var domainItem = document.getElementById('sidebar_domain_' + domainKey);
|
|
domainItem.classList.add('list-group-item-danger');
|
|
}
|
|
|
|
function showEntitiesLoading(element = null) {
|
|
if (element == null) element = document;
|
|
element.querySelector('.spinner').classList.remove('d-none');
|
|
}
|
|
|
|
function hideEntitiesLoading(element = null) {
|
|
if (element == null) element = document;
|
|
element.querySelector('.spinner').classList.add('d-none');
|
|
}
|
|
|
|
function showEntityDetails(entity) {
|
|
// Title
|
|
document.getElementById('entityDetailsTitle').innerText = entity.Name;
|
|
|
|
// Attributes
|
|
const attrBody = document.getElementById('entityAttributesBody');
|
|
attrBody.innerHTML = '';
|
|
|
|
const attributes = entity.Attributes || {};
|
|
const attrKeys = Object.keys(attributes);
|
|
|
|
if (attrKeys.length === 0) {
|
|
attrBody.innerHTML = `
|
|
<tr>
|
|
<td colspan="2" class="text-muted text-center">No attributes</td>
|
|
</tr>`;
|
|
} else {
|
|
attrKeys.forEach(key => {
|
|
const row = document.createElement('tr');
|
|
attributeKV = attributes[key];
|
|
row.innerHTML = `
|
|
<td>${attributeKV["Name"]}</td>
|
|
<td>${attributeKV["Value"]}</td>
|
|
`;
|
|
attrBody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
// Datapoints
|
|
const dpBody = document.getElementById('entityDatapointsBody');
|
|
dpBody.innerHTML = '';
|
|
|
|
(entity.Datapoints || []).forEach(dp => {
|
|
const row = document.createElement('tr');
|
|
row.innerHTML = `
|
|
<td>${dp.Name}</td>
|
|
<td>${dp.ProbMethod}</td>
|
|
<td>${dp.SimilarityMethod}</td>
|
|
`;
|
|
dpBody.appendChild(row);
|
|
});
|
|
|
|
// Show modal
|
|
const modal = new bootstrap.Modal(
|
|
document.getElementById('entityDetailsModal')
|
|
);
|
|
modal.show();
|
|
}
|
|
</script> |