Docs / docs (push) Successful in 22s
Playwright Tests / test-playwright (1, 2) (push) Successful in 3m14s
Playwright Tests / test-playwright (2, 2) (push) Successful in 1m53s
pre-commit / pre-commit (push) Failing after 2m13s
Test Backend / test-backend (push) Successful in 2m38s
Compose Smoke Test / test-compose (push) Successful in 38s
Playwright Tests / merge-reports (push) Successful in 1m8s
`GET /api/v1/search/` hands the client one flat index of everything worth jumping to — flows and the nodes inside them, dashboards and the widgets on them, panels, secrets, modules, workers and alert channels — and cmdk matches it in the browser, so results narrow while typing without a round trip per keystroke. A node hit is the one thing no list endpoint could answer: it opens its flow with that node in focus. The panel is reached from **Search** above Documentation in the sidebar, or ⌘K anywhere. The flow canvas palette moves to ⌘P, being the narrower of the two. The panels dialog gains an address (`/dashboards?panels`) so a panel hit has somewhere to land, and the sidebar logo gets `shrink-0`: the rail's width animates while the logo is already back, and a flex item short of room is squeezed rather than clipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vGH7jqcXxWKP9wZFPyVdU
81 lines
2.8 KiB
Python
81 lines
2.8 KiB
Python
"""The one index the global search matches against."""
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from fluksio.core.config import settings
|
|
|
|
PREFIX = f"{settings.API_V1_STR}/search"
|
|
FLOWS = f"{settings.API_V1_STR}/flows"
|
|
DASHBOARDS = f"{settings.API_V1_STR}/dashboards"
|
|
SECRETS = f"{settings.API_V1_STR}/secrets"
|
|
|
|
|
|
def test_search_requires_authentication(client: TestClient) -> None:
|
|
assert client.get(f"{PREFIX}/").status_code == 401
|
|
|
|
|
|
def test_index_reaches_inside_flows_and_dashboards(
|
|
client: TestClient, superuser_token_headers: dict[str, str]
|
|
) -> None:
|
|
"""A node and a widget are the point: neither is on any list endpoint."""
|
|
client.put(
|
|
f"{FLOWS}/searchable",
|
|
headers=superuser_token_headers,
|
|
json={
|
|
"name": "searchable",
|
|
"title": "Searchable",
|
|
"nodes": [{"id": "sensor", "type": "python", "title": "Hall sensor"}],
|
|
},
|
|
)
|
|
client.put(
|
|
f"{DASHBOARDS}/hall",
|
|
headers=superuser_token_headers,
|
|
json={
|
|
"name": "hall",
|
|
"title": "Hall",
|
|
"widgets": [
|
|
{
|
|
"id": "temperature",
|
|
"type": "stat",
|
|
"title": "Temperature",
|
|
"layout": {"lg": {"x": 0, "y": 0, "w": 3, "h": 2}},
|
|
"config": {"message": "hall.temperature", "dtype": "float"},
|
|
}
|
|
],
|
|
"version": 0,
|
|
},
|
|
)
|
|
|
|
entries = client.get(f"{PREFIX}/", headers=superuser_token_headers).json()
|
|
# Keyed on the parent too: an id is only unique within the document it is
|
|
# in, and the other suites seed their own `sensor` and `temperature`.
|
|
found = {
|
|
(entry["category"], entry["parent"], entry["name"]): entry for entry in entries
|
|
}
|
|
|
|
assert found[("flow", "", "searchable")]["title"] == "Searchable"
|
|
assert found[("node", "searchable", "sensor")]["title"] == "Hall sensor"
|
|
assert found[("node", "searchable", "sensor")]["kind"] == "python"
|
|
assert found[("dashboard", "", "hall")]["title"] == "Hall"
|
|
assert found[("widget", "hall", "temperature")]["title"] == "Temperature"
|
|
assert found[("widget", "hall", "temperature")]["kind"] == "stat"
|
|
|
|
|
|
def test_secrets_are_named_only_to_a_superuser(
|
|
client: TestClient,
|
|
superuser_token_headers: dict[str, str],
|
|
normal_user_token_headers: dict[str, str],
|
|
) -> None:
|
|
client.put(
|
|
f"{SECRETS}/broker_password",
|
|
headers=superuser_token_headers,
|
|
json={"value": "hunter2"},
|
|
)
|
|
|
|
def secrets(headers: dict[str, str]) -> set[str]:
|
|
entries = client.get(f"{PREFIX}/", headers=headers).json()
|
|
return {e["name"] for e in entries if e["category"] == "secret"}
|
|
|
|
assert "broker_password" in secrets(superuser_token_headers)
|
|
assert secrets(normal_user_token_headers) == set()
|