Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

78 project search functionality #140

Merged
merged 1 commit into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion alembic.ini
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ keys = console
keys = generic

[logger_root]
level = WARN
level = INFO
handlers = console
qualname =

Expand Down
9 changes: 6 additions & 3 deletions amt/api/routes/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ async def get_root(
projects_service: Annotated[ProjectsService, Depends(ProjectsService)],
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1),
search: str = Query(""),
) -> HTMLResponse:
projects = projects_service.paginate(skip=skip, limit=limit)
projects = projects_service.paginate(skip=skip, limit=limit, search=search)
next = skip + limit

if request.state.htmx:
return templates.TemplateResponse(request, "projects/_list.html.j2", {"projects": projects, "next": next})
return templates.TemplateResponse(
request, "projects/_list.html.j2", {"projects": projects, "next": next, "search": search}
)

return templates.TemplateResponse(
request, "projects/index.html.j2", {"projects": projects, "next": next, "limit": limit}
request, "projects/index.html.j2", {"projects": projects, "next": next, "limit": limit, "search": search}
)


Expand Down
2 changes: 0 additions & 2 deletions amt/clients/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@ def get_content(self, url: str) -> bytes:
"""
This method should implement getting the content of an instrument from given URL.
"""
...

@abstractmethod
def list_content(self, url: str = "") -> RepositoryContent:
"""
This method should implement getting list of instruments from given URL.
"""
...

def _get(self, url: str) -> httpx.Response:
"""
Expand Down
8 changes: 6 additions & 2 deletions amt/locale/base.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-07-26 13:53+0200\n"
"POT-Creation-Date: 2024-08-15 15:18+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
"Generated-By: Babel 2.16.0\n"

#: amt/site/templates/header.html.j2:4
msgid "Algorithm Management Toolkit"
Expand Down Expand Up @@ -66,6 +66,10 @@ msgstr ""
msgid "Unknown"
msgstr ""

#: amt/site/templates/projects/index.html.j2:11
msgid "Find projects..."
msgstr ""

#: amt/site/templates/projects/new.html.j2:4
msgid "New Project"
msgstr ""
Expand Down
Binary file modified amt/locale/en_US/LC_MESSAGES/messages.mo
Binary file not shown.
8 changes: 6 additions & 2 deletions amt/locale/en_US/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-07-26 13:53+0200\n"
"POT-Creation-Date: 2024-08-15 15:18+0200\n"
"PO-Revision-Date: 2024-07-25 21:01+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en_US\n"
Expand All @@ -16,7 +16,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
"Generated-By: Babel 2.16.0\n"

#: amt/site/templates/header.html.j2:4
msgid "Algorithm Management Toolkit"
Expand Down Expand Up @@ -67,6 +67,10 @@ msgstr ""
msgid "Unknown"
msgstr ""

#: amt/site/templates/projects/index.html.j2:11
msgid "Find project..."
msgstr ""

#: amt/site/templates/projects/new.html.j2:4
msgid "New Project"
msgstr ""
Expand Down
Binary file modified amt/locale/nl_FY/LC_MESSAGES/messages.mo
Binary file not shown.
8 changes: 6 additions & 2 deletions amt/locale/nl_FY/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-07-26 13:53+0200\n"
"POT-Creation-Date: 2024-08-15 15:18+0200\n"
"PO-Revision-Date: 2024-07-25 21:01+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: nl_FY\n"
Expand All @@ -16,7 +16,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
"Generated-By: Babel 2.16.0\n"

#: amt/site/templates/header.html.j2:4
msgid "Algorithm Management Toolkit"
Expand Down Expand Up @@ -67,6 +67,10 @@ msgstr "Dien"
msgid "Unknown"
msgstr ""

#: amt/site/templates/projects/index.html.j2:11
msgid "Find project..."
msgstr "Fine projekt..."

#: amt/site/templates/projects/new.html.j2:4
msgid "New Project"
msgstr ""
Expand Down
Binary file modified amt/locale/nl_NL/LC_MESSAGES/messages.mo
Binary file not shown.
8 changes: 6 additions & 2 deletions amt/locale/nl_NL/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-07-26 13:53+0200\n"
"POT-Creation-Date: 2024-08-15 15:18+0200\n"
"PO-Revision-Date: 2024-07-25 21:01+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: nl_NL\n"
Expand All @@ -16,7 +16,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
"Generated-By: Babel 2.16.0\n"

#: amt/site/templates/header.html.j2:4
msgid "Algorithm Management Toolkit"
Expand Down Expand Up @@ -67,6 +67,10 @@ msgstr "Afgerond"
msgid "Unknown"
msgstr "Onbekend"

#: amt/site/templates/projects/index.html.j2:11
msgid "Find project..."
msgstr "Zoek project..."

#: amt/site/templates/projects/new.html.j2:4
msgid "New Project"
msgstr "Nieuw project"
Expand Down
12 changes: 8 additions & 4 deletions amt/repositories/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
from sqlalchemy import func, select
from sqlalchemy.exc import NoResultFound, SQLAlchemyError
from sqlalchemy.orm import Session
from sqlalchemy_utils import escape_like # pyright: ignore[reportMissingTypeStubs, reportUnknownVariableType]

from amt.core.exceptions import RepositoryError, RepositoryNoResultFound
from amt.core.exceptions import RepositoryError
from amt.models import Project
from amt.repositories.deps import get_session

Expand Down Expand Up @@ -52,9 +53,12 @@ def find_by_id(self, project_id: int) -> Project:
except NoResultFound as e:
raise RepositoryError from e

def paginate(self, skip: int, limit: int) -> list[Project]:
def paginate(self, skip: int, limit: int, search: str) -> list[Project]:
try:
statement = select(Project).order_by(func.lower(Project.name)).offset(skip).limit(limit)
statement = select(Project)
if search != "":
statement = statement.filter(Project.name.ilike(f"%{escape_like(search)}%"))
statement = statement.order_by(func.lower(Project.name)).offset(skip).limit(limit)
return list(self.session.execute(statement).scalars())
except Exception as e:
raise RepositoryNoResultFound from e
raise RepositoryError from e
1 change: 0 additions & 1 deletion amt/services/instruments.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ def fetch_github_content(self, url: str) -> Instrument:
return Instrument(**data)

def fetch_instruments(self, urns: Sequence[str] | None = None) -> list[Instrument]:
# todo (Robbert): we 'type ignore' Task.sort_order because it works correctly, but pyright does not agree
content_list = self.fetch_github_content_list()

instruments: list[Instrument] = []
Expand Down
4 changes: 2 additions & 2 deletions amt/services/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ def create(self, project_new: ProjectNew) -> Project:

return project

def paginate(self, skip: int, limit: int) -> list[Project]:
return self.repository.paginate(skip=skip, limit=limit)
def paginate(self, skip: int, limit: int, search: str) -> list[Project]:
return self.repository.paginate(skip=skip, limit=limit, search=search)

def update(self, project: Project) -> Project:
return self.repository.save(project)
2 changes: 1 addition & 1 deletion amt/site/templates/projects/_list.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
<li><a href="/project/{{ project.id }}">{{ project.name }}</a></li>
{% endfor %}
{% if projects|length > 0 %}
<li hx-get="/projects/?skip={{next}}" hx-swap="outerHTML" hx-trigger="revealed">More</li>
<li hx-get="/projects/?skip={{ next }}&search={{ search }}" hx-swap="outerHTML" hx-trigger="revealed">More</li>
{% endif %}
22 changes: 21 additions & 1 deletion amt/site/templates/projects/index.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,27 @@

{% block content %}
<h1 class="margin-bottom--large">{% trans %}Projects{% endtrans %}</h1>
<ul class="project-list">

<form>
<label>
<input
size="100"
type="search"
placeholder="{% trans %}Find project...{% endtrans %}"
name="search"
hx-get="/projects/?skip=0"
hx-trigger="input changed delay:500ms, search"
hx-target="#project-search-results"
hx-indicator=".htmx-indicator"
hx-swap="innerHTML"
autocomplete="false"
id="project-search-input"
/>
</label>
<input type="reset" value="X" style="position: relative; margin-left: -30px" />
</form>

<ul class="project-list" id="project-search-results">
{% include 'projects/_list.html.j2' %}
</ul>

Expand Down
2 changes: 2 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ services:
- PGDATA=/var/lib/postgresql/data/pgdata
healthcheck:
test: ["CMD", "pg_isready", "-q", "-d", "amt", "-U", "amt"]
ports:
- 5432:5432

db-admin:
image: dpage/pgadmin4:8.6
Expand Down
36 changes: 32 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ click = "^8.1.7"
python-ulid = "^2.7.0"
fastapi-csrf-protect = "^0.3.4"
sqlalchemy = "^2.0.32"
sqlalchemy-utils = "^0.41.2"


[tool.poetry.group.test.dependencies]
Expand Down
6 changes: 3 additions & 3 deletions tests/api/routes/test_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ def test_projects_get_root(client: TestClient) -> None:
response = client.get("/projects/")

assert response.status_code == 200
assert b'<ul class="project-list">' in response.content
assert b'<ul class="project-list" id="project-search-results">' in response.content


def test_projects_get_root_missing_slash(client: TestClient) -> None:
response = client.get("/projects")

assert response.status_code == 200
assert b'<ul class="project-list">' in response.content
assert b'<ul class="project-list" id="project-search-results">' in response.content


def test_projects_get_root_htmx(client: TestClient) -> None:
response = client.get("/projects/", headers={"HX-Request": "true"})

assert response.status_code == 200
assert b'<ul class="project-list">' not in response.content
assert b'<ul class="project-list" id="project-search-results">' not in response.content


def test_get_new_projects(client: TestClient, init_instruments: Generator[None, None, None]) -> None:
Expand Down
4 changes: 2 additions & 2 deletions tests/database_e2e_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def setup_database_e2e(session: Session) -> None:
db_e2e.given([task1, task2, task3])

projects: list[Project] = []
for _ in range(120):
projects.append(default_project())
for idx in range(120):
projects.append(default_project(name=f"Project {idx}"))

db_e2e.given([*projects])
8 changes: 4 additions & 4 deletions tests/e2e/test_scroll_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
def test_e2e_scroll_projects(page: Page) -> None:
page.goto("/projects/")

project_links = page.locator(".project-list > li", has_text="default project").count()
project_links = page.locator(".project-list > li").count()

assert 90 <= project_links <= 100
assert 90 <= project_links <= 101

with page.expect_response("/projects/?skip=100", timeout=3000) as response_info:
with page.expect_response("/projects/?skip=100&search=", timeout=3000) as response_info:
page.get_by_text("More").scroll_into_view_if_needed()

response = response_info.value
assert response.status == 200

project_links = page.locator(".project-list > li", has_text="default project").count()
project_links = page.locator(".project-list > li").count()
assert project_links > 100
Loading