Skip to content

Commit

Permalink
search, pagination in ui
Browse files Browse the repository at this point in the history
  • Loading branch information
Roy Wiggins authored and Roy Wiggins committed Sep 27, 2024
1 parent 09242dd commit ff0bf7b
Show file tree
Hide file tree
Showing 17 changed files with 298 additions and 116 deletions.
34 changes: 33 additions & 1 deletion common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class Target(BaseModel, Compat):
contact: Optional[str] = ""
comment: str = ""

@property
def short_description(self) -> str:
return ""
@classmethod
def __get_validators__(cls):
# one or more validators may be yielded which will be called in the
Expand Down Expand Up @@ -59,6 +62,10 @@ class DicomTarget(Target):
aet_target: str
aet_source: Optional[str] = ""

@property
def short_description(self) -> str:
return f"{self.ip}:{self.port}"


class DicomTLSTarget(Target):
target_type: Literal["dicomtls"] = "dicomtls"
Expand All @@ -70,6 +77,9 @@ class DicomTLSTarget(Target):
tls_cert: str
ca_cert: str

@property
def short_description(self) -> str:
return f"{self.ip}:{self.port}"

class SftpTarget(Target):
target_type: Literal["sftp"] = "sftp"
Expand All @@ -78,6 +88,10 @@ class SftpTarget(Target):
host: str
password: Optional[str]

@property
def short_description(self) -> str:
return f"{self.folder}:{self.host}"


class RsyncTarget(Target):
target_type: Literal["rsync"] = "rsync"
Expand All @@ -86,7 +100,10 @@ class RsyncTarget(Target):
host: str
password: Optional[str]
run_on_complete: bool = False


@property
def short_description(self) -> str:
return f"{self.host}:{self.folder}"

class XnatTarget(Target):
target_type: Literal["xnat"] = "xnat"
Expand All @@ -95,6 +112,10 @@ class XnatTarget(Target):
user: str
password: str

@property
def short_description(self) -> str:
return self.host


class DicomWebTarget(Target):
target_type: Literal["dicomweb"] = "dicomweb"
Expand All @@ -106,6 +127,10 @@ class DicomWebTarget(Target):
http_user: Optional[str]
http_password: Optional[str]

@property
def short_description(self) -> str:
return self.url


class S3Target(Target):
target_type: Literal["s3"] = "s3"
Expand All @@ -115,12 +140,19 @@ class S3Target(Target):
access_key_id: str
secret_access_key: str

@property
def short_description(self) -> str:
return f"{self.bucket}/{self.prefix}"


class FolderTarget(Target):
target_type: Literal["folder"] = "folder"
folder: str
file_filter: Optional[str]

@property
def short_description(self) -> str:
return self.folder

class DummyTarget(Target):
target_type: Literal["dummy"] = "dummy"
Expand Down
4 changes: 4 additions & 0 deletions dispatch/target_types/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class TargetHandler(Generic[TargetTypeVar]):
def __init__(self):
pass

@property
def info_short(self) -> str:
return ""

def send_to_target(
self,
task_id: str,
Expand Down
4 changes: 2 additions & 2 deletions webinterface/statics/css/custom.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.rulecard {
.entitycard {
margin-bottom: 10px;
}

.rulecard-content {
.entitycard-content {
padding: 10px;
}

Expand Down
112 changes: 95 additions & 17 deletions webinterface/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,34 +35,31 @@
</a>
</div>
<div id="navbarMainMenu" class="navbar-menu">
{% macro highlight(the_page) -%}
{% if page != the_page %}has-text-grey-light{% endif %}
{%- endmacro %}
<div class="navbar-start">
{% if logged_in %}
<a class="navbar-item {% if page != 'homepage' %}has-text-grey-light{% endif %}" href="/">
<a class="navbar-item {{highlight('homepage')}}" href="/">
Overview
</a>
<a class="navbar-item {% if page != 'rules' %}has-text-grey-light{% endif %}" href="/rules">
Rules
</a>
<a class="navbar-item {% if page != 'targets' %}has-text-grey-light{% endif %}" href="/targets">
Targets
<a class="navbar-item {{highlight('queue')}}" href="/queue">
Queue
</a>
<a class="navbar-item {% if page != 'modules' %}has-text-grey-light{% endif %}" href="/modules">
Modules
<a class="navbar-item {% if page not in ['rules', 'targets','modules', 'users'] %} has-text-grey-light{%endif%}" href="/rules">
Rules
</a>
{% if is_admin %}
<a class="navbar-item {% if page != 'users' %}has-text-grey-light{% endif %}" href="/users">
Users
</a>
<a class="navbar-item {% if page != 'logs' %}has-text-grey-light{% endif %}" href="/logs">
<a class="navbar-item {{highlight('logs')}}" href="/logs">
Logs
</a>
<a class="navbar-item {{highlight('dashboards')}}" href="/dashboards">
Tools
</a>
{% endif %}
<a class="navbar-item {% if page != 'configuration' %}has-text-grey-light{% endif %}" href="/configuration">
<a class="navbar-item {{highlight('configuration')}}" href="/configuration">
Configuration
</a>
<a class="navbar-item {% if page != 'queue' %}has-text-grey-light{% endif %}" href="/queue">
Queue
</a>
{% endif %}
</div>
{% if logged_in %}{% if appliance_name != 'master' %}
Expand Down Expand Up @@ -100,7 +97,22 @@
</div>
</div>
</nav>
{% block extra_nav %} {% endblock %}
{% block extra_nav %}
{% if page in ['rules','targets','modules', 'users'] %}
<section>
<div class="container tabs">
<ul>
<li class="{% if page == 'rules' %}is-active{% endif %}"><a href="/rules">Rules</a></li>
<li class="{% if page == 'targets' %}is-active{% endif %}"><a href="/targets">Targets</a></li>
<li class="{% if page == 'modules' %}is-active{% endif %}"><a href="/modules">Modules</a></li>
{% if is_admin %}
<li class="{% if page == 'users' %}is-active{% endif %}"><a href="/users">Users</a></li>
{% endif %}
</ul>
</div>
</section>
{% endif %}
{% endblock %}

<section class="section" style="flex: 1;">
<div class="container">
Expand All @@ -123,6 +135,72 @@
<script type="module">
import { JSONEditor } from "{{ url_for('static', path='/js/svelte-jsoneditor.js') }}"

function paginate(cards, items_per_page=10) {
const paginationList = document.getElementById('paginationList');
const searchInput = document.getElementById('searchInput');
searchInput.value = '';
const ruleCards = cards;
const itemsPerPage = items_per_page; // Adjust this value to change items per page
let currentPage = 1;

function showPage(page) {
const startIndex = (page - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
let visibleCount = 0;

Array.from(ruleCards).forEach((card, index) => {
if (card.style.display !== 'none') {
visibleCount++;
if (visibleCount > startIndex && visibleCount <= endIndex) {
card.classList.remove('is-hidden');
} else {
card.classList.add('is-hidden');
}
}
});

updatePagination();
}

function updatePagination() {
const visibleCards = Array.from(ruleCards).filter(card => card.style.display !== 'none');
const pageCount = Math.ceil(visibleCards.length / itemsPerPage);

paginationList.innerHTML = '';
for (let i = 1; i <= pageCount; i++) {
const li = document.createElement('li');
const a = document.createElement('a');
a.classList.add('pagination-link');
if (i === currentPage) {
a.classList.add('is-current');
}
a.setAttribute('aria-label', `Goto page ${i}`);
a.textContent = i;
a.addEventListener('click', () => {
currentPage = i;
showPage(currentPage);
});
li.appendChild(a);
paginationList.appendChild(li);
}
}

searchInput.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
Array.from(ruleCards).forEach( card => {
const ruleName = card.getAttribute('data-name').toLowerCase();
if (ruleName.includes(searchTerm)) {
card.style.display = 'block';
} else {
card.style.display = 'none';
}
});
currentPage = 1;
showPage(currentPage);
});
showPage(currentPage);
}
window.paginate = paginate;
$(document).ready(function () {
// Check for click events on the navbar burger icon
$(".navbar-burger").click(function () {
Expand Down
6 changes: 5 additions & 1 deletion webinterface/templates/dashboards/dashboards.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
<div class="container">
<div class="tabs logtabs" style="margin-top: 40px;">
<ul>
<!-- <li class="{% if page == 'query' %}is-active{% endif %}"><a href="query">DICOM Query</a></li> -->
{% if is_admin %}
<li class="{% if page == 'tests' %}is-active{% endif %}"><a href="tests">Self-test</a></li>
<li class="{% if page == 'tasks' %}is-active{% endif %}"><a href="tasks">Tasks</a></li>
{% endif %}
<!-- <li class="{% if page == 'tasks' %}is-active{% endif %}"><a href="tasks">Tasks</a></li> -->

</ul>
</div>
</div>
Expand Down
39 changes: 27 additions & 12 deletions webinterface/templates/modules.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,48 +12,62 @@
<main role="main">
<div class="container">
<h1 class="title">Processing Modules</h1>
{% for x in modules %}
<div class="card rulecard">
<div class="field">
<div class="control has-icons-left">
<input class="input" type="text" id="searchInput" placeholder="Search..." value="">
<span class="icon is-small is-left">
<i class="fas fa-search"></i>
</span>
</div>
</div>

{% for module_name, module in modules.items() %}
<div class="card entitycard" data-name="{{module_name}} {{module.docker_tag}}">
<header class="card-header has-background-light">
<p class="card-header-title card-toggle">
<span class="icon"><i class="fas fa-cogs fa-lg"></i></span>&nbsp;&nbsp;{{ x }}
<span class="icon"><i class="fas fa-cogs fa-lg"></i></span>&nbsp;&nbsp;{{ module_name }}
<span style="margin-left: auto; font-weight: 200;">{{module.docker_tag|truncate(50, True)}}</span>
</p>
<a class="card-header-icon card-toggle">
<i class="fa fa-angle-down"></i>
</a>
</header>
<div class="card-content rulecard-content is-hidden">
<div class="card-content entitycard-content is-hidden">
<div class="content">
<table class="table is-narrow" style="margin-bottom: 8px;">
<col width="150">
<tr>
<td>Docker Tag:</td>
<td>{{ modules[x]['docker_tag'] }}</td>
<td>{{ module.docker_tag }}</td>
</tr>
<tr>
<td>Contact:</td>
<td>{{ modules[x]['contact'] }}</td>
<td>{{ module.contact }}</td>
</tr>
<tr>
<td>Comment:</td>
<td>{{ modules[x]['comment'] }}</td>
<td>{{ module.comment }}</td>
</tr>
</table>
<div class="buttons is-right">
{% if is_admin %}
<a class="button is-success" href="/modules/edit/{{x}}"><i
<a class="button is-success" href="/modules/edit/{{module_name}}"><i
class="fas fa-pen"></i>&nbsp;Edit</a>
<button class="button is-danger" id="confirm-me" value="{{x}}"
onclick="confirmDelete(this.value)" {% if x in used_modules%}disabled
title="Cannot delete because target is used by rule '{{ used_modules[x] }}'" {% endif %}><i
<button class="button is-danger" id="confirm-me" value="{{module_name}}"
onclick="confirmDelete(this.value)" {% if module_name in used_modules%}disabled
title="Cannot delete because target is used by rule '{{ used_module }}'" {% endif %}><i
class="fas fa-trash-alt"></i>&nbsp;Delete</button>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}

<nav class="pagination is-centered" role="navigation" aria-label="pagination">
<ul class="pagination-list" id="paginationList">
</ul>
</nav>

{% if is_admin %}
<div class="buttons is-left" style="margin-top: 20px;">
<button class="button is-success" onclick="showAddModal()"><i class="fas fa-plus"></i>&nbsp;Install
Expand Down Expand Up @@ -137,6 +151,7 @@ <h1 class="title">Processing Modules</h1>
e.currentTarget.parentElement.parentElement.childNodes[3].classList.toggle('is-hidden');
});
}
paginate(document.getElementsByClassName('entitycard'))
});

function showAddModal(val) {
Expand Down
Loading

0 comments on commit ff0bf7b

Please sign in to comment.