Compare commits

...

4 Commits

Author SHA1 Message Date
david-spacil 7ea2a99ada fix/small-fixes: drobné úpravy stylu a čitelnosti kódu (#54)
* small fixes

* fix: refactoring
rozbaleny listy, doplněny trailing commas
2026-06-28 11:03:15 +02:00
david-spacil 6772a99ead feature/projektové akce: filtrování a sloupec Projekt v akcích (#53)
* feature/projektove-akce: do dialogu akce přidán checkbox pro filtrování projektových akcí + backend logika

* feature/projektove-akce: do atributové tabulky akcí přidáno pole Projekt (prázdné, pokud nejde o projektovou akci)
2026-06-28 10:35:25 +02:00
Claude 9e8863b879 chore: sladění governance se vzorem aiscr-management
- ekosystémová poznámka (sibling hubu aiscr-management)
- konvence větví feat/fix/docs/chore + agents/<jméno>/<téma>
- pravidla pro AI agenty (git delivery)
- bezpečnost/soukromí (žádné secrets/PII)
- deterministické datum pro changelog
- PR šablona: pole Zapojení AI + položka konvence větví

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C8nJvecSSf6vB3NYZsMaVt
2026-06-28 10:26:06 +02:00
Claude 0eb8008e27 chore: PR šablona + AGENTS.md (a CLAUDE.md odkaz) pro standardizaci repozitáře
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C8nJvecSSf6vB3NYZsMaVt
2026-06-28 10:24:00 +02:00
5 changed files with 222 additions and 23 deletions
+35
View File
@@ -0,0 +1,35 @@
<!--
Děkujeme za příspěvek! Vyplň prosím sekce níže.
Nepotřebné body můžeš smazat. Komentáře (<!-- ... -->) se v PR nezobrazují.
-->
## Souhrn
<!-- Stručně co a proč. 13 věty. -->
## Změny
<!-- Co se konkrétně mění, ideálně po souborech / oblastech. -->
-
## Testování
<!-- Jak ověřit, že to funguje (kroky v QGIS, scénáře). -->
-
## Zapojení AI
<!-- Byla u změny použita AI? Jak? Např. "text navržen AI, ručně zkontrolováno
a upraveno". Smaž, pokud AI použita nebyla. -->
-
## Kontrolní seznam
- [ ] Změny jsou v souladu se stylem projektu (viz `AGENTS.md`)
- [ ] Při změně funkcí povýšena verze v `amcr_viewer/metadata.txt` a doplněn `changelog`
- [ ] Otestováno v QGIS (min. podporovaná verze 3.44)
- [ ] PR míří do správné cílové větve
- [ ] Větev odpovídá konvenci (`feat/ fix/ docs/ chore/<téma>`, AI `agents/<jméno>/<téma>`)
## Související issue
<!-- Např. "Closes #123". Smaž, pokud se neváže k issue. -->
+122
View File
@@ -0,0 +1,122 @@
# AGENTS.md
Pokyny pro AI agenty i lidské přispěvatele pracující v tomto repozitáři.
Tento soubor je jediný zdroj pravdy; `CLAUDE.md` na něj pouze odkazuje.
## O projektu
**AMČR Viewer** je plugin do QGIS pro stahování a vizualizaci dat z Digitálního
archivu Archeologické mapy ČR (AMČR / AIS CR) akce (*Fieldwork events*),
lokality (*Sites*) a jejich komponenty. Podporuje anonymní i přihlášený přístup
přes AMČR účet.
Zdroj dat: https://digiarchiv.aiscr.cz/ · Nápověda: https://amcr-help.aiscr.cz/digiarchiv/qgis-viewer.html
## Zařazení v ekosystému AIS CR
Tento repozitář je jedním ze **sourozeneckých repozitářů** ekosystému AIS CR.
Centrální governance a AI konfigurace spravuje hub **`aiscr-management`**; konvence
v tomto souboru jsou s tímto vzorem sladěné a zjednodušené pro potřeby jednoho
QGIS pluginu. Těžkou mašinerii hubu (složka `.agents/`, OpenSpec, sync skripty,
multi-assistant generování) tento repozitář **záměrně nepřebírá**. Při širších
otázkách governance má přednost vzor z `aiscr-management`.
## Struktura repozitáře
```
amcr_viewer/ # vlastní kód pluginu (toto se balí do releasu)
amcr_viewer.py # vstupní bod pluginu, integrace do QGIS
amcr_dialog.py # dialogy a UI (filtry, přihlášení)
amcr_tools.py # stahování dat z API, sestavení vrstev a atributů
amcr_codelists.py # hesláře / číselníky (codelists)
codelists/heslar.csv # lokální kopie číselníků
metadata.txt # metadata pluginu + verze + changelog
i18n/ # překlady (.ts)
*.png # ikony
.github/workflows/ # CI release pluginu
README.md # uživatelská dokumentace (anglicky)
```
## Konvence
### Jazyk
- **Kód a identifikátory:** anglicky. Atributová pole vrstev musí být ASCII
kompatibilní (bez diakritiky) viz historie změn v `metadata.txt`.
- **README a uživatelská dokumentace:** anglicky.
- **Commity, PR a komentáře v issue:** česky.
### Commity
- Styl odpovídá historii: česky, věcně, popisně; jeden commit = jedna logická
změna.
- První řádek stručně a výstižně (ideálně v imperativu); podrobnosti do těla.
- Pokud je commit připraven s pomocí AI, uveď to v těle commitu nebo v popisu PR.
### Větve
Konvence názvů je sladěná s hubem `aiscr-management`:
- **lidé:** `feat/<téma>` (nová funkce), `fix/<téma>` (oprava), `docs/<téma>`
(dokumentace), `chore/<téma>` (údržba).
- **AI agenti:** `agents/<jméno-agenta>/<téma>` (např. `agents/claude/oprava-pian`).
Další pravidla:
- Cílová větev pro nový vývoj je aktuální `version/v2.x.y` (ne přímo do
výchozí větve bez PR).
- **Nikdy** nepushuj přímo do chráněných větví; vždy přes Pull Request.
- Standardizační / nefunkční změny drž v samostatné větvi, ať se nemíchají do
feature PR.
### Pravidla pro AI agenty (git)
- AI ve výchozím stavu zůstává u **lokální práce na aktuální větvi**.
- Bez **výslovného pokynu** uživatele AI nestageuje (`git add`), necommituje,
nepushuje ani samo nepřepíná/nezakládá větev pro vzdálené doručení.
- Při výslovném požadavku na push/PR použij větev `agents/<jméno-agenta>/<téma>`;
pokud aktuální větev tomuto vzoru neodpovídá, vyžádej si nejdřív potvrzení.
- Vytvoření větve, stage, commit, push ani draft PR AI běžně nenabízí; zmiňuj je
jen tehdy, když jsou pro splnění úkolu opravdu nutné.
### QGIS specifika
- Minimální podporovaná verze QGIS je **3.44** (`qgisMinimumVersion` v
`metadata.txt`); kód nesmí spoléhat na novější API.
- Vrstvy a atributy se sestavují přes `QgsField` / QGIS API v `amcr_tools.py`.
Při přidání atributu je potřeba doplnit ho konzistentně na všech místech:
definice pole (`QgsField`), naplnění hodnoty z dokumentu, překlad hlavičky
sloupce a export atributů.
## Verzování a release
- Verze pluginu žije v **`amcr_viewer/metadata.txt`** (`version=`).
- **Při každé změně chování / nové funkci** povyš verzi a doplň položku do
`changelog=` v `metadata.txt` (formát `vX.Y.Z (RRRR-MM-DD)` + odrážky).
- Datum v changelogu ber z **deterministického zdroje**, ne z paměti, např.
`python -c "import datetime; print(datetime.date.today().isoformat())"`.
- Release se vytváří publikací GitHub Release; workflow
`.github/workflows/release_plugin.yml` zabalí složku `amcr_viewer/` do
`amcr_viewer.zip` a přiloží ji k releasu. Do ZIPu se nesmí dostat `.git*`
soubory.
## Pull requesty
- Používej PR šablonu (`.github/pull_request_template.md`): Souhrn / Změny /
Testování / Kontrolní seznam.
- PR musí mířit do správné `version/v2.x.y` větve.
- Před požádáním o review projdi kontrolní seznam v šabloně (zejména bump verze
v `metadata.txt`, pokud měníš chování).
- V popisu PR uveď **podíl AI** (např. „text navržen AI, ručně zkontrolováno")
a odkaz na související issue, pokud existuje.
## Bezpečnost a soukromí
- Do promptů, příkladů ani commitů **nevkládej** ostrá produkční data, plné
log dumpy ani reálné osobní údaje (PII).
- **Rediguj** secrets, tokeny, API klíče a hesla z čehokoli, co posíláš AI;
nikdy je necommituj do repozitáře (ani přihlašovací údaje k AMČR účtu).
- Pro interní infrastrukturu (URL, hostname, prostředí) používej placeholdery,
pokud konkrétní hodnota není nutná a povolená.
## Lokální ověření
Plugin se testuje načtením do QGIS (Plugins → Manage and Install Plugins →
Install from ZIP, nebo nasazením složky `amcr_viewer/` do adresáře pluginů
QGIS). Automatizované testy zatím repozitář neobsahuje změny ověřuj ručně
v QGIS na podporované verzi.
+6
View File
@@ -0,0 +1,6 @@
# CLAUDE.md
Pokyny pro tento repozitář jsou v [`AGENTS.md`](./AGENTS.md).
Tento soubor je záměrně jen odkaz, aby existoval jeden zdroj pravdy a obsah se
nerozjel. Cokoli platí pro AI agenty v tomto projektu, najdeš v `AGENTS.md`.
+25 -8
View File
@@ -44,16 +44,19 @@ class UpdateCodelistsTask(QgsTask):
refresh_globals()
QgsMessageLog.logMessage(
"Hesláře AMČR byly úspěšně aktualizovány.",
"AMČR", Qgis.Info)
"AMČR", Qgis.Info
)
else:
if self.isCanceled():
QgsMessageLog.logMessage(
"Aktualizace heslářů byla zrušena.",
"AMČR", Qgis.Warning)
"AMČR", Qgis.Warning
)
else:
QgsMessageLog.logMessage(
f"Chyba aktualizace: {self.exception}",
"AMČR", Qgis.Critical)
"AMČR", Qgis.Critical
)
class FilterableSelectionDialog(QDialog):
@@ -151,10 +154,20 @@ class AmcrFilterDialog(QDialog):
# Cache dictionary to store selected codes for each category
self.selection_cache = {
'organizace': [], 'kraj': [], 'obdobi': [], 'areal': [],
'typ_akce': [], 'okres': [], 'katastr': [], 'vedouci': [],
'pian_presnost': [], 'pristupnost': [], 'typ_lokality': [],
'druh_lokality': [], 'jistota': [], 'lokalita_zachovalost': []
'organizace': [],
'kraj': [],
'obdobi': [],
'areal': [],
'typ_akce': [],
'okres': [],
'katastr': [],
'vedouci': [],
'pian_presnost': [],
'pristupnost': [],
'typ_lokality': [],
'druh_lokality': [],
'jistota': [],
'lokalita_zachovalost': [],
}
layout = QVBoxLayout()
@@ -169,6 +182,8 @@ class AmcrFilterDialog(QDialog):
if self.typ_dat == "akce":
self.chk_posevidence = QCheckBox("Pouze pozitivní zjištění")
layout.addWidget(self.chk_posevidence)
self.chk_proj_akce = QCheckBox("Pouze projektové akce")
layout.addWidget(self.chk_proj_akce)
layout.addSpacing(10)
@@ -361,7 +376,7 @@ class AmcrFilterDialog(QDialog):
self.selection_cache[cache_key] = [
'HES-000861',
'HES-000862',
'HES-000863'
'HES-000863',
]
btn.clicked.connect(open_dialog)
@@ -453,6 +468,8 @@ class AmcrFilterDialog(QDialog):
if self.typ_dat == "akce":
if self.chk_posevidence.isChecked():
filters['posevidence'] = 'true'
if self.chk_proj_akce.isChecked():
filters['proj_akce'] = 'true'
if self.selection_cache['organizace']:
filters['f_organizace'] = self.selection_cache['organizace']
if self.selection_cache['typ_akce']:
+34 -15
View File
@@ -283,7 +283,7 @@ def load_amcr_data(canvas, bb, filters=None,
base_params = {
"mapa": "true",
"sort": "ident_cely asc",
"entity": typ_dat
"entity": typ_dat,
}
# Restrict search to map window if requested
@@ -317,6 +317,12 @@ def load_amcr_data(canvas, bb, filters=None,
else False
)
only_projektove_akce = (
filters.get('proj_akce') == 'true'
if filters
else False
)
# Check whether we should filter results based on component filters
filter_areal = "f_areal" in filters if filters else False
filter_datace = "f_obdobi" in filters if filters else False
@@ -439,6 +445,9 @@ def load_amcr_data(canvas, bb, filters=None,
if not piani:
continue
if only_projektove_akce and not doc.get("akce_projekt", False):
continue
actions_with_geom += 1
# Extract protected fields ('or {}' key may hold None)
@@ -470,7 +479,7 @@ def load_amcr_data(canvas, bb, filters=None,
"katastr": g_list(doc, 'katastr'),
"dalsi_katastr": dalsi_kat_str,
"pristupnost": g(doc, 'pristupnost'),
"loc": g_list(doc, 'loc')
"loc": g_list(doc, 'loc'),
}
# Add entity-specific metadata
@@ -515,6 +524,11 @@ def load_amcr_data(canvas, bb, filters=None,
if doc.get('akce_je_nz') is True
else "Ne"
),
"projekt": g(
doc,
'akce_projekt',
""
),
})
elif typ_dat == "lokalita":
@@ -654,8 +668,10 @@ def load_amcr_data(canvas, bb, filters=None,
)
fl_pian = [
"ident_cely", "pian_typ",
"pian_chranene_udaje", "pian_presnost"
"ident_cely",
"pian_typ",
"pian_chranene_udaje",
"pian_presnost",
]
for i in range(0, total_pians, BATCH_PIAN):
@@ -668,7 +684,7 @@ def load_amcr_data(canvas, bb, filters=None,
"entity": "pian",
"q": fq_pian,
"rows": len(batch),
"fl": ",".join(fl_pian)
"fl": ",".join(fl_pian),
}
try:
QApplication.processEvents()
@@ -725,7 +741,7 @@ def load_amcr_data(canvas, bb, filters=None,
QgsField("odkaz_do_digiarchivu", QMetaType.Type.QString),
QgsField("okres", QMetaType.Type.QString),
QgsField("katastr", QMetaType.Type.QString),
QgsField("dalsi_katastry", QMetaType.Type.QString)
QgsField("dalsi_katastry", QMetaType.Type.QString),
]
# Extend table based on data type
@@ -741,6 +757,7 @@ def load_amcr_data(canvas, bb, filters=None,
QgsField("vedlejsi_typ", QMetaType.Type.QString),
QgsField("zjisteni", QMetaType.Type.QString),
QgsField("nahrazuje_NZ", QMetaType.Type.QString),
QgsField("projekt", QMetaType.Type.QString),
]
elif typ_dat == "lokalita":
cols += [
@@ -748,7 +765,7 @@ def load_amcr_data(canvas, bb, filters=None,
QgsField("popis_lokality", QMetaType.Type.QString),
QgsField("typ_lokality", QMetaType.Type.QString),
QgsField("druh_lokality", QMetaType.Type.QString),
QgsField("zachovalost", QMetaType.Type.QString)
QgsField("zachovalost", QMetaType.Type.QString),
]
cols.append(QgsField("Přístupnost", QMetaType.Type.QString))
@@ -784,6 +801,7 @@ def load_amcr_data(canvas, bb, filters=None,
"komponenta": "Komponenta",
"komponenta_areal": "Areál",
"komponenta_obdobi": "Období",
"projekt": "Projekt",
}
if komponenty == "true":
@@ -904,7 +922,7 @@ def load_amcr_data(canvas, bb, filters=None,
+ meta['ident_cely'],
meta['az_okres'],
meta['katastr'],
meta['dalsi_katastr']
meta['dalsi_katastr'],
]
if is_akce:
atributy.extend([
@@ -917,7 +935,8 @@ def load_amcr_data(canvas, bb, filters=None,
meta['akce_hlavni_typ'],
meta['akce_vedlejsi_typ'],
meta['dj_negativni'],
meta['akce_je_nz']
meta['akce_je_nz'],
meta['projekt'],
])
else:
atributy.extend([
@@ -925,7 +944,7 @@ def load_amcr_data(canvas, bb, filters=None,
meta['lokalita_popis'],
meta['lokalita_typ'],
meta['lokalita_druh'],
meta['lokalita_zachovalost']
meta['lokalita_zachovalost'],
])
atributy.append(meta['pristupnost'])
@@ -955,12 +974,12 @@ def load_amcr_data(canvas, bb, filters=None,
(feats_pt, vl_point, "Body"),
]
for f, l, n in layers_to_process:
for f, L, n in layers_to_process:
if f:
l.dataProvider().addFeatures(f)
l.updateExtents()
l.setName(f"AMCR_{archeologicky_zaznam}_{n}")
proj.addMapLayer(l)
L.dataProvider().addFeatures(f)
L.updateExtents()
L.setName(f"AMCR_{archeologicky_zaznam}_{n}")
proj.addMapLayer(L)
added += len(f)
if network_error: