Skip to content

Commit 14b6cd9

Browse files
mpasternakclaude
andauthored
Tabela krzyżowa rekordów i autorów na stronie „Wyszukiwanie zapytaniem" (fazy 2-4) (#686)
* docs(zapytanie): spec wachlarza wyjść dla wyszukiwania zapytaniem Eksporty (CSV/XLSX/HTML/DOCX/BibTeX) i tabela krzyżowa na stronie /zapytanie/ w parytecie z multiseekiem, plus nowy rejestr wymiarów tabeli krzyżowej dla modelu Autor (bazy: kadrowa / prace / udziały). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(zapytanie): self-review speca — 3 poprawki - Część IV: usunięta sprzeczność (jeden annotate vs osobne zapytania); metryki dorobku liczone dwoma zapytaniami, bo dwa JOIN-y do relacji do-wielu w jednym annotate zawyżają sumy - postać dla model=autor to 'rekordy' + 'pivot' (nie 'lista') - doprecyzowany routing eksportu przy postac=pivot i sanityzacja ?tytul= Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(zapytanie): plan wdrożenia w 12 zadaniach Cztery fazy: wspólny silnik wyjścia + eksporty rekordów, pivot rekordów, pakiet bpp/pivot/ + rejestr autorski (baza kadrowa), metryki bibliometryczne + eksport autorów. Self-review planu wykrył trzy blokery reużycia report-body-pivot.html (formularz GET gubiący model/query, relatywne linki eksportu, selektory nieświadome baz agregacji) — wszystkie rozpisane jako konkretne edycje. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(plan): konwencje testowe repo + mocniejsze asercje Pre-flight scan planu: testy dotykające Rekordu wymagają fixture denorms i denorms.flush() (Rekord to zdenormalizowany cache), fixture 'tytul' nie istnieje (jest 'tytuly'), a dwie asercje były zbyt słabe (dowolne '2' w wierszu CSV; brak '5000' w komunikacie) — zamienione na parsowanie CSV i sprawdzenie treści komunikatu. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(zapytanie): wykonaj_zapytanie() jako jedno źródło prawdy * test(zapytanie): test dedupu faktycznie produkuje duplikat wierszy * refactor(multiseek): document_export_response() jako funkcja * docs: postac to identyfikatory ReportType, nie polskie etykiety Task 2 wykrył, że plan brał drugi argument ReportType('list', 'lista') — etykietę UI — za wartość report_type. postac=tabela nigdy nie trafiłaby w TABLE_REPORT_TYPES, więc tabela renderowałaby się jako lista, bez błędu. Poprawione w planie (zadania 2-6, 12) i w specyfikacji. Druga poprawka: nh3 w sanitize_export_html zdejmuje atrybuty class, więc asercje testów eksportu HTML/DOCX nie mogą opierać się na klasach CSS — tylko render na stronie je zachowuje. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(zapytanie): postać wyniku (lista/tabela/punktacja) z partiali multiseeka * docs(plan): pivot wchodzi do <select> dopiero gdy działa Review Task 3: postać 'tabela krzyżowa' była wybieralna, a renderowała placeholder listy (dla autorów: puste wiersze, bo Autor nie ma js_safe_pk ani opisu bibliograficznego). Zadanie 3 usuwa ją z list postaci, zadania 6 i 9 dopisują ją z powrotem wraz z implementacją. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(zapytanie): eksport CSV/XLSX/HTML/DOCX/BibTeX z zapytania DjangoQL * fix(zapytanie): review fixes — usun niedzialajacy pivot, uzyj partiala bibtex, ikona fi-page-edit - POSTACIE_REKORD/POSTACIE_AUTOR: wyrzucone "pivot" (bez dedykowanego partiala renderowal sie jako zepsuta lista rekordow/autorow). - postac="bibtex" renderuje teraz wlasny partial multiseeka (report-body-bibtex.html) zamiast placeholder-owej listy opisow. - ikona edycji ✎ -> fi-page-edit (Foundation Icons, zgodnie z konwencja repo dla frontendu publicznego) w obu partialach (list/table). - test_postac_tabela_ma_sumy: asercja na realnej wartosci sumy (dwa rekordy, 40+10=50,00), nie tylko na obecnosci kontenera. - nowe testy regresyjne: pivot niewybieralny/degradujacy, bibtex uzywa wlasnego partiala, pager zachowuje postac miedzy stronami, stopka "Suma:" tylko na ostatniej stronie tabeli. * fix(zapytanie): chowaj martwy przycisk kopiowania BibTeX poza multiseekiem Przycisk "Skopiuj wszystko do schowka" w report-body-bibtex.html ma handler JS tylko inline w multiseekowym common-results.html — na /zapytanie/ (hide_chrome=True) byl martwy (klik bez efektu). Ten sam wzorzec co widget usuwania (❌): {% if not hide_chrome %} wokol .bibtex-actions. Multiseek nie przekazuje hide_chrome, wiec jego przycisk dziala jak dotad; /zapytanie/ dostaje sam <pre> z BibTeX-em (w pelni zaznaczalny/kopiowalny recznie). * fix(zapytanie): eksport — 400 jako text/plain + escape() błędu DjangoQL (XSS) * feat(zapytanie): pasek eksportu w UI + newsfragment * docs(plan): zadanie 11 przywraca pasek eksportu dla autorów Zadanie 5 celowo zwróciło pustą krotkę formatów dla model=autor, bo backend 400-ował każdy format i pasek pokazywałby martwe linki. Po wdrożeniu eksportu autorów gałąź ma wrócić do (csv, xlsx). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(zapytanie): poprawki z końcowego review — asercja 403, martwe re-eksporty, komunikat nieznanego modelu Test uprawnien testuje teraz sztywno 403 (raise_exception=True gwarantuje to niezaleznie od stanu logowania — potwierdzone w kodzie mixinow Django). Usuniete szesc martwych re-eksportow z mymultiseek.py (niepotwierdzone grepem uzycie poza tym plikiem). Rozdzielony komunikat 400 dla eksportu autorow i dla realnie nieznanego modelu. Dwa testy degradacji postaci dla autora dostaly pozytywna asercje na "rekord-id-cell" zamiast samego "not in". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(zapytanie): tabela krzyżowa rekordów na stronie zapytania Postać "tabela krzyżowa" (postac=pivot) wraca do selektora dla modelu rekord — zadanie 3 ją usunęło, bo bez implementacji renderowała placeholder listy. Silnik pivota (parse_pivot_params/zbuduj_pivot/DIMENSIONS/METRICS) jest brany z multiseeka bez zmian; widok dokłada tylko kontekst i trzy klucze, których partial potrzebuje pod tym URL-em: form action, ukryte pola model/query/postac (strona zapytania trzyma filtr w URL-u, nie w sesji jak multiseek) i prefiks linków eksportu. Eksport macierzy do CSV/XLSX omija capy rekordowe 25000/5000 — rozmiar macierzy nie zależy od liczby rekordów źródłowych. Bramka PIVOT_MAX_CELLS pokazuje komunikat na ekranie zamiast 500. Przy okazji naprawione cztery fałszywie zielone asercje testowe: sprawdzały obecność gołej nazwy klasy "rekord-id-cell", która występuje na KAŻDEJ stronie, bo zapytanie.html definiuje dla niej regułę CSS w bloku <style>. Test "pivot dla rekordu degraduje" przechodził więc nadal, mimo że pivot dostał już własny render. Asercje celują teraz w '<td class="rekord-id-cell">', a strażnik wybieralności pivota został odwrócony na model autor, który własnego rejestru wymiarów jeszcze nie ma. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(pivot): silnik do bpp/pivot/, multiseek_registry re-eksportuje Silnik tabeli krzyżowej przestał być multiseek-specyficzny w momencie, gdy dostała ją też strona „Wyszukiwanie zapytaniem", a zadania 8-10 dokładają drugi rejestr wymiarów (dla modelu Autor, z trzema bazami agregacji). Kod rozdzielony na generyczny silnik (bpp/pivot/core.py) i rejestr wymiarów Rekordu (bpp/pivot/rekord.py); multiseek_registry/pivot.py zostaje cienkim re-eksportem, żeby nie ruszać call-site'ów w szablonach i widokach. Jedyna zmiana sygnatury: zbuduj_pivot(..., *, model=None) — strategia dedupu potrzebuje modelu bazowego, dotąd zaszytego jako Rekord. Domyślny None zachowuje wszystkie istniejące wywołania; zadanie 8 poda tu Autora. Progi PIVOT_MAX_CELLS/PIVOT_MAX_PAIRS świadomie NIE są re-eksportowane przez shim: zbuduj_pivot czyta je jako globalne swojego modułu, więc kopia nazwy pod starą ścieżką byłaby martwa — monkeypatch na niej przestawiłby kopię, nie bramkę. Trzy testy patchujące progi celują teraz w bpp.pivot.core, gdzie te stałe mieszkają. Brak nazwy w shimie jest tu cechą, nie luką: monkeypatch domyślnie podnosi AttributeError na nieistniejącym atrybucie, więc pomyłka wyjdzie głośno w linii patcha, zamiast dać fałszywie zielony test. Neutralność: 25 testów pivota multiseeka przechodzi bez zmian w asercjach (zmienione tylko trzy cele monkeypatcha — patch site idzie za przeprowadzką stałej dokładnie tak jak import site). Cała suita pivot/zapytanie/multiseek: 458 passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(pivot): rejestr autorski, baza kadrowa (liczba autorów) Drugi rejestr silnika pivota (bpp/pivot/autor.py) obok rejestru rekordowego z zadania 7 — model Autor, na razie tylko baza K (kadrowa, metryka „liczba autorów"). Bazy P (liczba prac) i U (Σ slotów, Σ pkdaut) to zadanie 10; seam dla nich jest gotowy (PivotDimension.expr jako dict per baza, PivotMetric.baza), więc dołożenie ich nie wymaga przeprojektowania. core.py: PivotDimension zyskuje annotation (adnotacja ORM dokładana przed grupowaniem — potrzebna dla wymiarów bool typu „ma ORCID", gdzie grupowanie po surowym polu dałoby grupę na wartość) oraz expr_dla()/alias() do odczytu ścieżki per baza; PivotMetric zyskuje baza i distinct_field. Rejestr rekordowy nie zauważa zmiany — przekazuje expr jako zwykły str; 25 testów bez zmian. Poprawki względem brief-u: fixture „tytul" w tym repo nie istnieje (jest tylko „tytuly") — Tytul tworzony inline; test odrzucania wymiaru niedostępnego w bazie był wsobny przy jednej bazie K (klucz „rok" nie istnieje w DIMENSIONS autorskich, więc fallback zadziałałby i bez logiki expr_dla) — przemianowany na to, co faktycznie sprawdza; asercja liczby autorów zastąpiona pełnym mapowaniem etykieta→suma ze stałą BRAK zamiast wklejonego literału. Nośność dedupu zmierzona, nie założona: po usunięciu dedupu w zbuduj_pivot_autora wszystkie 7 testów nadal przechodzi, bo Count(pk, distinct=True) sam zwija wiersze zwielokrotnione JOIN-em. Dedup zostaje (poprawny, tani, jednakowy dla baz), ale test przestał twierdzić, że go dowodzi, a wymóg testu padającego bez dedupu — możliwego dopiero dla metryk Σ, gdzie Sum nie rozpozna duplikatu — jest dopisany do zadania 10 w planie. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(zapytanie): tabela krzyżowa autorów w UI + presety Rejestr pivota autorskiego (bpp.pivot.autor, baza kadrowa K) zostaje wpięty w /zapytanie/ i eksport: postac=pivot jest teraz wybieralna dla obu modeli, ZapytanieView._pivot_context i ZapytanieExportView rozgałęziają się po modelu przez wspólny helper bpp.pivot.wybierz_rejestr_pivota, eksport macierzy autorskiej (CSV/XLSX) naprawdę działa i ma link w pasku, a sekcja pomocy dostaje cztery klikalne presety (struktura kadrowa, ORCID, PBN UID, płeć wg tytułów). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(pivot): metryki bibliometryczne autorów (liczba prac, Σ slotów, Σ pkdaut) Bazy P (prace, przez `autorzy` → Rekord) i U (udziały, przez `cache_punktacja_autora_query` → Rekord) w rejestrze pivota autorskiego, razem z wymiarami publikacyjnymi o `expr` per baza: rok, dyscyplina, jednostka przy pracy, typ odpowiedzialności, charakter formalny. KRYTYCZNE: każdy wymiar publikacyjny idzie DOKŁADNIE tą samą relacją do-wielu, po której agreguje metryka jego bazy (P → `autorzy__…`, U → `cache_punktacja_autora_query__…`). Zmieszanie dwóch relacji daje iloczyn kartezjański i `Sum` zwraca wielokrotność prawdy — zmierzone: autor z dwiema pracami i dwoma wierszami udziału daje Σ slotów 3.0 zamiast 1.5. Pilnuje tego test niezawyżania na dokładnej liczbie. Dedup przez świeży queryset w `zbuduj_pivot_autora`, dotąd redundantny w bazie K (`Count(pk, distinct=True)` sam zwija duplikaty), staje się nośny dla metryk Σ — dowodzi tego nowy test, który po zakomentowaniu tamtej linii pada (0.5 → 1.5). Do UI dochodzą cztery presety oparte na nowych bazach (produktywność jednostek, ranking slotowy autorów, udziały dyscyplinowe, wkład punktowy jednostek) plus test, że każdy preset przeżywa `parse_pivot_params_autor` bez cichej podmiany wymiaru. Zdjęty `xfail(strict=True)` z `test_metryka_slotowa_pokazuje_rok`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(zapytanie): eksport autorów CSV/XLSX z metrykami dorobku ZapytanieExportView eksportuje teraz listę autorów (nie tylko macierz pivota) do CSV/XLSX: dane kadrowe (jednostka, tytuł, ORCID, PBN UID i inne) plus liczba prac, Σ slotów i Σ pkdaut. _metryki_dorobku() liczy te trzy metryki DWOMA osobnymi zapytaniami (Count przez relację "autorzy", Sum przez "cache_punktacja_autora_query") — jeden wspólny annotate() na dwóch różnych relacjach do-wielu zawyżałby sumy (dowód: test_eksport_autorow_nie_zawyza_metryk). Te same ścieżki ORM, co metryki bpp.pivot.autor.METRICS, żeby lista i tabela krzyżowa autorów nigdy nie pokazały dwóch różnych liczb dla tej samej populacji. eksport_formaty() (zapytanie.py) pokazuje teraz pasek CSV/XLSX dla modelu "autor" niezależnie od postaci wyniku — wcześniej ograniczone do postac="pivot", bo lista 400-owała. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(zapytanie): test Playwright postaci wyniku + dokumentacja Dopisuje test przegladarkowy dowodzacy, ze wybor postaci wyniku (#id_postac) faktycznie jedzie przez formularz GET /zapytanie/ - domyslna tabela redakcyjna ustepuje partialowi multiseeka po przelaczeniu na "lista", a URL zawiera postac=list. Dodaje sekcje w dokumentacji redaktora o postaciach wyniku, eksporcie i tabeli krzyzowej strony /zapytanie/. Newsfragmenty na ta funkcjonalnosc juz istnieja z wczesniejszych zadan tego planu (zapytanie-eksporty, zapytanie-tabela-krzyzowa[-autorzy], zapytanie-pivot-autor-metryki-bibliometryczne, zapytanie-eksport-autorow) - nie dodano duplikatu. Pelna suita bez Playwrighta: 8748 passed, 4 skipped, 1 xfailed. Suita Playwright: 119 passed. pre-commit: czysto. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(zapytanie): poprawki z końcowego review faz 2-4 K1 (krytyczne) — górny pasek eksportu przy postac=pivot ściągał INNĄ macierz niż widoczna: budował URL z samych model/query/postac, więc gubił pivot_row/pivot_col/pivot_val. Zmierzone: link z górnego paska zwracał "Rok,RAZEM / 2026,1,1 / RAZEM,1" (macierz domyślna), a link spod macierzy "Charakter ogólny (rodzaj),…" — dwa przyciski CSV kilka centymetrów od siebie, dwa różne pliki. Górny pasek nie renderuje się teraz przy pivocie: pasek w report-body-pivot.html składa URL z request.GET.urlencode, więc jest z konstrukcji zgodny z ekranem (także po dołożeniu kolejnego parametru pivota) i stoi przy selektorach, które macierz konfigurują. Wariant "dołóż trzy parametry do href-a" odrzucony — zostawiałby dwie listy parametrów do ręcznego synchronizowania, czyli dokładnie mechanizm, który K1 wyprodukował. W1 — pivot autorski nigdy nie pokazywał adnotacji o dublowaniu (twarde has_autorzy_dim=False), choć baza P dubluje tak samo jak pivot rekordowy. Zmierzone: jedna praca, dwóch autorów z różnych jednostek, row=jednostka → GRAND 2 przy jednej unikatowej pracy i BRAK ostrzeżenia (a to jest preset "Produktywność jednostek"). Flaga liczona teraz uczciwie: nowe pole PivotDimension.atrybut_rekordu (ten sam kształt co `autorzy` w rejestrze rekordowym), ustawione dla `rok` i `charakter_formalny`, plus _dubluje(): baza P + jakikolwiek wymiar, który nie jest atrybutem pracy. Po poprawce jednostka → 2 + True, rok → 1 + False. Tekst notki przeredagowany na neutralny modelowo. W2 — distinct=True w METRICS["liczba_prac"] nie było pokryte: wszystkie testy grupowały po `autor`, gdzie DISTINCT jest no-opem (zmierzone: bez=1, z=1; przy row=jednostka bez=2, z=1). Dopisany test dwóch współautorów jednej jednostki (grand_total == 1) plus testy dublowania/niedublowania z W1. Mutacja "usuń distinct=True" wywala teraz 2 testy. W3 — testy eksportu macierzy asertowały samo b"RAZEM", które jest w KAŻDEJ macierzy (także w błędnej domyślnej) — dlatego K1 przeszedł trzy rundy review. Cztery testy sprawdzają teraz etykiety zamówionych wymiarów i dokładne wartości komórek (XLSX przez openpyxl, nie przez Content-Type), doszedł też test biorący WSZYSTKIE linki eksportu ze strony pivota i wymagający od każdego macierzy zgodnej z ekranem. Mutacja "eksport ignoruje parametry GET" wywala 4 testy, mutacja "przywróć stary górny pasek" — 2. W4 — presety były martwe na świeżej stronie: renderowały się z query= i po kliknięciu dawały 200 bez wyników, bez macierzy i bez komunikatu. Puste zapytanie nie jest "wszyscy autorzy" — apply_search rzuca DjangoQLParserError ("Unexpected end of input"), więc widok w ogóle nie wchodzi w render_results. Bez wysłanego zapytania blok pokazuje więc nazwy presetów jako tekst plus zdanie, co zrobić, żeby ożyły (discoverability bez klikalnej obietnicy); z zapytaniem — linki jak dotąd, z tekstem mówiącym wprost, że jadą z WYSŁANYM zapytaniem, nie z niewysłaną treścią pola. Drobne: prawdziwy docstring PivotDimension.expr_dla (D2); martwa bramka {% if eksport_formaty %} i nieaktualny komentarz zastąpione realną bramką postac != "pivot" (D3); jeden słownik TAK/NIE/— brak — dla wartości logicznych (core.etykieta_bool) używany i przez pivot, i przez eksport autorów, gdzie orcid_w_pbn jechał dotąd jako "True"/"False" (D5). Świadomie odłożone (bez zmian): grupy o sumie 0 znikające z macierzy, paginacja/URL-e admina liczone na darmo przy postac=pivot, rsplit("csv/"). Weryfikacja: pytest -k "pivot or zapytanie or multiseek" → 496 passed (było 490), pre-commit czysty, zero zmian w migracjach i baseline-sql. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent f6e935d commit 14b6cd9

33 files changed

Lines changed: 7312 additions & 482 deletions

‎docs/redaktor/wyszukiwanie-redagowanie.md‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,77 @@ Analogicznie w przykładzie matematycznym:
238238
``` python
239239
(10 + 20) * 30 * 40 # wynik to 36000
240240
```
241+
242+
## Samodzielna strona "Wyszukiwanie zapytaniem" (`/zapytanie/`)
243+
244+
Oprócz filtru DjangoQL wbudowanego w listy modułu Redagowanie, dla
245+
zalogowanych redaktorów dostępna jest osobna strona pod adresem
246+
`/zapytanie/` (w menu **szukaj → zapytaniem**). Różni się od filtru
247+
listy tym, że:
248+
249+
- zapytanie wpisuje się raz, niezależnie od konkretnej tabeli — wybiera
250+
się tylko model (**rekord** albo **autor**), a samo zapytanie DjangoQL
251+
działa tak samo jak opisano wyżej,
252+
- wynik można pokazać w kilku **postaciach**, wyeksportować w kilku
253+
formatach oraz zestawić jako **tabelę krzyżową** — czego filtr listy
254+
w Redagowaniu nie oferuje.
255+
256+
### Postać wyniku
257+
258+
Nad wynikami znajduje się rozwijana lista **Postać wyniku**. Wybór jedzie
259+
razem z zapytaniem — po kliknięciu "Szukaj" URL zawiera parametr
260+
`postac`, więc wynik da się też przesłać jako link czy zapisać w
261+
zakładkach.
262+
263+
Dla modelu **rekord** dostępne są:
264+
265+
- **rekordy (ID + akcje)** — domyślna, dzisiejsza tabela z ID rekordu
266+
i linkami "Zobacz" / "Edytuj",
267+
- **lista** — numerowana lista opisów bibliograficznych,
268+
- **tabela** — tabela z sumami (impact factor, liczba cytowań, punkty
269+
KBN, punktacja wewnętrzna),
270+
- **punktacja z wewnętrzną** / **punktacja sumaryczna** — warianty
271+
tabeli z innym zestawem kolumn punktowych,
272+
- **BibTeX** — lista opisów jako brama do eksportu pliku `.bib`,
273+
- **tabela krzyżowa** — patrz niżej.
274+
275+
Dla modelu **autor** dostępne są tylko **autorzy (ID + akcje)**
276+
(domyślna) i **tabela krzyżowa**.
277+
278+
### Eksport wyników
279+
280+
Pod nagłówkiem wyników pojawia się pasek **Eksport** z linkami do
281+
formatów sensownych dla wybranej postaci i modelu:
282+
283+
- **rekord**: CSV i XLSX zawsze; HTML i DOCX dla postaci innych niż
284+
tabela krzyżowa; BibTeX (`.bib`) tylko przy postaci **BibTeX**,
285+
- **autor**: CSV i XLSX — kartoteka kadrowa (jednostka, tytuł, stopień,
286+
ORCID, PBN UID i inne) wraz z metrykami dorobku (liczba prac, Σ
287+
slotów, Σ pkdaut).
288+
289+
Eksport zawsze obejmuje **cały** wynik zapytania, nie tylko widoczną
290+
stronę wyników. Ze względu na to jest ograniczony limitami: eksport
291+
danych (CSV/XLSX) — maksymalnie 25 000 rekordów, eksport dokumentu
292+
(HTML/DOCX) — maksymalnie 5 000 rekordów. Po przekroczeniu limitu
293+
strona pokazuje komunikat z liczbą trafień i prośbą o zawężenie
294+
zapytania.
295+
296+
### Tabela krzyżowa
297+
298+
Wybranie postaci **tabela krzyżowa** odsłania dodatkowe pola wyboru
299+
wiersza, kolumny i miary macierzy — działa to tak samo, jak tabela
300+
krzyżowa znana z wyszukiwania precyzyjnego (formularzowego), ale liczy
301+
się na wyniku zapytania DjangoQL. Dostępna jest zarówno dla rekordów
302+
(np. rok × charakter formalny, liczba prac albo suma punktów), jak i
303+
dla autorów — w dwóch rodzinach wymiarów:
304+
305+
- **kadrowej** — jednostka, tytuł, stopień, funkcja, płeć, kompletność
306+
ORCID/PBN/e-mail,
307+
- **bibliometrycznej** — liczba prac, Σ slotów, Σ pkdaut wg roku
308+
publikacji, dyscypliny, jednostki przy pracy, typu odpowiedzialności
309+
i charakteru formalnego.
310+
311+
W sekcji pomocy nad formularzem znajdują się gotowe **presety** —
312+
linki, które od razu dokładają wiersz/kolumnę/miarę do bieżącego
313+
zapytania i przełączają postać wyniku na tabelę krzyżową. Samą macierz
314+
(bez surowych wyników) można wyeksportować do CSV i XLSX.

0 commit comments

Comments
 (0)