conversions web4
This commit is contained in:
@@ -358,11 +358,8 @@ ecb-description = Importér načítá zveřejněné kurzy ECB jednou denně a za
|
||||
ecb-unavailable-title = Devizové kurzy nejsou dostupné
|
||||
ecb-forbidden = Pro otevření této stránky se vyžaduje čtení údajů o devizových kurzech.
|
||||
ecb-import-attempts = Pokusy o import
|
||||
ecb-failed-count = { $count ->
|
||||
[one] { $count } neúspěšný
|
||||
[few] { $count } neúspěšné
|
||||
*[other] { $count } neúspěšných
|
||||
}
|
||||
ecb-technical-history = Technická historie aktualizací
|
||||
ecb-technical-history-hint = Pouze pro řešení problémů. Stará selhání zůstávají v auditním záznamu i po úspěšnější aktualizaci.
|
||||
ecb-no-attempts-hint = Importér nezaznamenal žádný pokus. Běží při startu a poté denně, takže prázdný záznam znamená, že server od vytvoření této tabulky nedokončil žádný běh.
|
||||
ecb-th-result = Výsledek
|
||||
ecb-th-started = Spuštěno
|
||||
@@ -376,11 +373,11 @@ ecb-batch-running = probíhá
|
||||
ecb-batch-failed = neúspěšné
|
||||
ecb-still-running = stále běží
|
||||
ecb-audit-hint = Pokusy jsou auditní záznam: nelze je upravovat ani mazat a dávka, která znovu načetla den, který už vlastnila starší, nevloží nic — proto může být nový počet nižší než celkový.
|
||||
ecb-import-running = import probíhá
|
||||
ecb-postable-lead = Co lze zaúčtovat právě teď
|
||||
ecb-import-running = právě se aktualizuje
|
||||
ecb-postable-lead = Povolená data transakcí
|
||||
ecb-ordinary-transactions = Běžné transakce
|
||||
ecb-statements-title = Výpisy a rozhodující data
|
||||
ecb-dated-up-to = datované do včetně
|
||||
ecb-statements-title = Výpisy a zůstatky k datu
|
||||
ecb-dated-up-to = Do
|
||||
ecb-ordinary-rate-hint = Přepočteno kurzem zveřejněným v pracovní den před transakcí.
|
||||
ecb-statements-rate-hint = Přepočteno kurzem zveřejněným v ten den, nebo v poslední pracovní den před ním.
|
||||
ecb-postable-limit-hint = Cizoměnová částka datovaná po svém limitu se odmítá přímo, dokud importér nedoběhne — nepřepočítává se zastaralým kurzem.
|
||||
@@ -398,18 +395,20 @@ ecb-no-coverage = bez pokrytí
|
||||
ecb-should-reach = Má dosáhnout
|
||||
ecb-last-attempt = Poslední pokus
|
||||
ecb-none-recorded = žádný nezaznamenán
|
||||
ecb-last-success = Poslední úspěch
|
||||
ecb-last-success = Poslední úspěšná aktualizace
|
||||
ecb-none = žádný
|
||||
ecb-next-import = Další import
|
||||
ecb-next-import = Další automatická aktualizace
|
||||
ecb-ready-currencies = Připravené měny:
|
||||
ecb-latest-problem = Poslední problém:
|
||||
ecb-currencies-on = Měny k { $date }
|
||||
ecb-the-covered-day = pokrytý den
|
||||
ecb-most-recent-failure = Poslední neúspěch — dávka { $batch }, spuštěno { $started }:
|
||||
ecb-no-reason-recorded = nebyl zaznamenán žádný důvod.
|
||||
ecb-headline-current = Kurzy jsou aktuální
|
||||
ecb-headline-never-ran = Nikdy nebyly importovány žádné kurzy
|
||||
ecb-headline-behind = Kurzy se zpožďují
|
||||
ecb-explanation-current = Ověřen je každý publikační den až po nejnovější, takže konverze se zaúčtovávají normálně.
|
||||
ecb-explanation-never-ran = Dokud se jeden nepodaří, každá konverze v cizí měně se odmítá pro nedostatek pokrytí.
|
||||
ecb-headline-current = Účtování v cizí měně je dostupné
|
||||
ecb-headline-never-ran = Účtování v cizí měně není dostupné
|
||||
ecb-headline-behind = Některé cizoměnové záznamy mohou být zablokovány
|
||||
ecb-explanation-current = Potřebné kurzy jsou dostupné. Správce nemusí nic dělat.
|
||||
ecb-explanation-never-ran = Zatím neuspěla žádná aktualizace kurzů. Cizoměnové záznamy nelze zaúčtovat.
|
||||
ecb-explanation-behind = { $count ->
|
||||
[one] Chybí { $count } publikační den.
|
||||
[few] Chybí { $count } publikační dny.
|
||||
@@ -934,8 +933,8 @@ rates-tab-configuration = Konfigurace
|
||||
rates-tab-configuration-sub = Měny a poskytovatelé
|
||||
rates-tab-evidence = Důkazy
|
||||
rates-tab-evidence-sub = Kontrola uloženého výsledku
|
||||
rates-tab-providers = Poskytovatelé
|
||||
rates-tab-providers-sub = Pokrytí a importy
|
||||
rates-tab-providers = Dostupnost
|
||||
rates-tab-providers-sub = Stav a aktualizace
|
||||
rates-profile-configuration = Konfigurace profilu
|
||||
rates-no-profiles = Nejsou dostupné žádné účetní profily.
|
||||
rates-profile = Profil
|
||||
@@ -970,9 +969,8 @@ rates-revision = Revize řádku
|
||||
rates-conversion = Konverze
|
||||
rates-created = Zaznamenáno
|
||||
rates-more-evidence = Existují další důkazy; upřesněte vyhledávání nebo pokračujte kurzorem API.
|
||||
rates-provider-operations = Provoz
|
||||
rates-provider-health = Stav poskytovatele
|
||||
rates-provider-health-hint = Ověřené pokrytí, hranice účtování a nedávné pokusy o import oficiálního poskytovatele.
|
||||
rates-provider-health = Lze účtovat cizoměnové záznamy?
|
||||
rates-provider-health-hint = Aktuální dostupnost a poslední úspěšná automatická aktualizace.
|
||||
rates-unavailable-title = Konverzní kurzy nejsou dostupné
|
||||
rates-err-profile-missing = Vybraný profil již neexistuje. Zobrazuje se první dostupný profil.
|
||||
rates-err-record-id = ID záznamu musí být kladné celé číslo.
|
||||
|
||||
@@ -354,10 +354,8 @@ ecb-description = The importer fetches the ECB's published rates once a day and
|
||||
ecb-unavailable-title = Exchange rates unavailable
|
||||
ecb-forbidden = Reading exchange-rate data is required to open this page.
|
||||
ecb-import-attempts = Import attempts
|
||||
ecb-failed-count = { $count ->
|
||||
[one] { $count } failed
|
||||
*[other] { $count } failed
|
||||
}
|
||||
ecb-technical-history = Technical update history
|
||||
ecb-technical-history-hint = For troubleshooting only. Old failures remain in this audit log even after a later update succeeds.
|
||||
ecb-no-attempts-hint = The importer has not recorded an attempt. It runs on startup and then daily, so an empty log means the server has not completed a run since this table was created.
|
||||
ecb-th-result = Result
|
||||
ecb-th-started = Started
|
||||
@@ -371,11 +369,11 @@ ecb-batch-running = running
|
||||
ecb-batch-failed = failed
|
||||
ecb-still-running = still running
|
||||
ecb-audit-hint = Attempts are an audit record: they cannot be edited or deleted, and a batch that re-fetched a day an earlier one already owned inserts nothing, which is why the new count can be lower than the total.
|
||||
ecb-import-running = import running
|
||||
ecb-postable-lead = What can be posted right now
|
||||
ecb-ordinary-transactions = Ordinary transactions
|
||||
ecb-statements-title = Statements & decisive dates
|
||||
ecb-dated-up-to = dated up to and including
|
||||
ecb-import-running = updating now
|
||||
ecb-postable-lead = Accepted transaction dates
|
||||
ecb-ordinary-transactions = Regular transactions
|
||||
ecb-statements-title = Statements and dated balances
|
||||
ecb-dated-up-to = Through
|
||||
ecb-ordinary-rate-hint = Converted at the rate published the business day before the transaction.
|
||||
ecb-statements-rate-hint = Converted at the rate published on that day, or the last business day before it.
|
||||
ecb-postable-limit-hint = A foreign-currency amount dated after its limit is refused outright until the importer catches up — it is not converted at a stale rate.
|
||||
@@ -392,18 +390,20 @@ ecb-no-coverage = no coverage
|
||||
ecb-should-reach = Should reach
|
||||
ecb-last-attempt = Last attempt
|
||||
ecb-none-recorded = none recorded
|
||||
ecb-last-success = Last success
|
||||
ecb-last-success = Last successful update
|
||||
ecb-none = none
|
||||
ecb-next-import = Next import
|
||||
ecb-next-import = Next automatic update
|
||||
ecb-ready-currencies = Currencies ready:
|
||||
ecb-latest-problem = Latest problem:
|
||||
ecb-currencies-on = Currencies on { $date }
|
||||
ecb-the-covered-day = the covered day
|
||||
ecb-most-recent-failure = Most recent failure — batch { $batch }, started { $started }:
|
||||
ecb-no-reason-recorded = no reason was recorded.
|
||||
ecb-headline-current = Rates are current
|
||||
ecb-headline-never-ran = No rates have ever been imported
|
||||
ecb-headline-behind = Rates are behind
|
||||
ecb-explanation-current = Every publication day up to the latest one is verified, so conversions post normally.
|
||||
ecb-explanation-never-ran = Until one succeeds, every conversion in a foreign currency is refused for want of coverage.
|
||||
ecb-headline-current = Foreign-currency posting is available
|
||||
ecb-headline-never-ran = Foreign-currency posting is unavailable
|
||||
ecb-headline-behind = Some foreign-currency records may be blocked
|
||||
ecb-explanation-current = The required rates are available. No admin action is needed.
|
||||
ecb-explanation-never-ran = No rate update has succeeded yet. Foreign-currency records cannot be posted.
|
||||
ecb-explanation-behind = { $count ->
|
||||
[one] { $count } publication day is missing.
|
||||
*[other] { $count } publication days are missing.
|
||||
@@ -918,8 +918,8 @@ rates-tab-configuration = Configuration
|
||||
rates-tab-configuration-sub = Currencies and providers
|
||||
rates-tab-evidence = Evidence
|
||||
rates-tab-evidence-sub = Inspect a stored result
|
||||
rates-tab-providers = Providers
|
||||
rates-tab-providers-sub = Coverage and imports
|
||||
rates-tab-providers = Availability
|
||||
rates-tab-providers-sub = Status and updates
|
||||
rates-profile-configuration = Profile configuration
|
||||
rates-no-profiles = No accounting profiles are available.
|
||||
rates-profile = Profile
|
||||
@@ -954,9 +954,8 @@ rates-revision = Row revision
|
||||
rates-conversion = Conversion
|
||||
rates-created = Recorded at
|
||||
rates-more-evidence = More evidence exists; narrow the lookup or use the API cursor to continue.
|
||||
rates-provider-operations = Operations
|
||||
rates-provider-health = Provider health
|
||||
rates-provider-health-hint = Verified coverage, posting horizons, and recent import attempts for the official provider.
|
||||
rates-provider-health = Can foreign-currency records be posted?
|
||||
rates-provider-health-hint = Current availability and the latest successful automatic update.
|
||||
rates-unavailable-title = Conversion rates are unavailable
|
||||
rates-err-profile-missing = The selected profile no longer exists. The first available profile is shown instead.
|
||||
rates-err-record-id = Record ID must be a positive whole number.
|
||||
|
||||
@@ -358,11 +358,8 @@ ecb-description = Importér načítava zverejnené kurzy ECB raz denne a zazname
|
||||
ecb-unavailable-title = Devízové kurzy nie sú dostupné
|
||||
ecb-forbidden = Na otvorenie tejto stránky sa vyžaduje čítanie údajov o devízových kurzoch.
|
||||
ecb-import-attempts = Pokusy o import
|
||||
ecb-failed-count = { $count ->
|
||||
[one] { $count } zlyhaný
|
||||
[few] { $count } zlyhané
|
||||
*[other] { $count } zlyhaných
|
||||
}
|
||||
ecb-technical-history = Technická história aktualizácií
|
||||
ecb-technical-history-hint = Len na riešenie problémov. Staré zlyhania zostávajú v audítorskom zázname aj po úspešnejšej aktualizácii.
|
||||
ecb-no-attempts-hint = Importér nezaznamenal žiadny pokus. Beží pri štarte a potom denne, takže prázdny záznam znamená, že server od vytvorenia tejto tabuľky nedokončil žiadny beh.
|
||||
ecb-th-result = Výsledok
|
||||
ecb-th-started = Spustené
|
||||
@@ -376,11 +373,11 @@ ecb-batch-running = prebieha
|
||||
ecb-batch-failed = zlyhané
|
||||
ecb-still-running = stále beží
|
||||
ecb-audit-hint = Pokusy sú audítorský záznam: nemožno ich upravovať ani mazať a dávka, ktorá znovu načítala deň, ktorý už vlastnila staršia, nevloží nič — preto môže byť nový počet nižší ako celkový.
|
||||
ecb-import-running = import prebieha
|
||||
ecb-postable-lead = Čo možno zahlasovať práve teraz
|
||||
ecb-import-running = práve sa aktualizuje
|
||||
ecb-postable-lead = Povolené dátumy transakcií
|
||||
ecb-ordinary-transactions = Bežné transakcie
|
||||
ecb-statements-title = Výpisy a rozhodujúce dátumy
|
||||
ecb-dated-up-to = datované do vrátane
|
||||
ecb-statements-title = Výpisy a zostatky k dátumu
|
||||
ecb-dated-up-to = Do
|
||||
ecb-ordinary-rate-hint = Prepočítané kurzom zverejneným v pracovný deň pred transakciou.
|
||||
ecb-statements-rate-hint = Prepočítané kurzom zverejneným v ten deň, alebo v posledný pracovný deň pred ním.
|
||||
ecb-postable-limit-hint = Cudzomenová suma datovaná po svojom limite sa odmieta priamo, kým importér nedobehne — neprepočítava sa zastaraným kurzom.
|
||||
@@ -398,18 +395,20 @@ ecb-no-coverage = bez pokrytia
|
||||
ecb-should-reach = Má dosiahnuť
|
||||
ecb-last-attempt = Posledný pokus
|
||||
ecb-none-recorded = žiadny nezaznamenaný
|
||||
ecb-last-success = Posledný úspech
|
||||
ecb-last-success = Posledná úspešná aktualizácia
|
||||
ecb-none = žiadny
|
||||
ecb-next-import = Ďalší import
|
||||
ecb-next-import = Ďalšia automatická aktualizácia
|
||||
ecb-ready-currencies = Pripravené meny:
|
||||
ecb-latest-problem = Posledný problém:
|
||||
ecb-currencies-on = Meny k { $date }
|
||||
ecb-the-covered-day = pokrytý deň
|
||||
ecb-most-recent-failure = Posledné zlyhanie — dávka { $batch }, spustené { $started }:
|
||||
ecb-no-reason-recorded = nebol zaznamenaný žiadny dôvod.
|
||||
ecb-headline-current = Kurzy sú aktuálne
|
||||
ecb-headline-never-ran = Nikdy neboli importované žiadne kurzy
|
||||
ecb-headline-behind = Kurzy meškajú
|
||||
ecb-explanation-current = Overený je každý publikačný deň až po najnovší, takže konverzie sa hlasujú normálne.
|
||||
ecb-explanation-never-ran = Kým sa jeden nepodarí, každá konverzia v cudzej mene sa odmieta pre nedostatok pokrytia.
|
||||
ecb-headline-current = Účtovanie v cudzej mene je dostupné
|
||||
ecb-headline-never-ran = Účtovanie v cudzej mene nie je dostupné
|
||||
ecb-headline-behind = Niektoré cudzomenové záznamy môžu byť zablokované
|
||||
ecb-explanation-current = Potrebné kurzy sú dostupné. Správca nemusí nič robiť.
|
||||
ecb-explanation-never-ran = Zatiaľ neuspela žiadna aktualizácia kurzov. Cudzomenové záznamy nemožno zaúčtovať.
|
||||
ecb-explanation-behind = { $count ->
|
||||
[one] Chýba { $count } publikačný deň.
|
||||
[few] Chýbajú { $count } publikačné dni.
|
||||
@@ -932,8 +931,8 @@ rates-tab-configuration = Konfigurácia
|
||||
rates-tab-configuration-sub = Meny a poskytovatelia
|
||||
rates-tab-evidence = Dôkazy
|
||||
rates-tab-evidence-sub = Kontrola uloženého výsledku
|
||||
rates-tab-providers = Poskytovatelia
|
||||
rates-tab-providers-sub = Pokrytie a importy
|
||||
rates-tab-providers = Dostupnosť
|
||||
rates-tab-providers-sub = Stav a aktualizácie
|
||||
rates-profile-configuration = Konfigurácia profilu
|
||||
rates-no-profiles = Nie sú dostupné žiadne účtovné profily.
|
||||
rates-profile = Profil
|
||||
@@ -968,9 +967,8 @@ rates-revision = Revízia riadka
|
||||
rates-conversion = Konverzia
|
||||
rates-created = Zaznamenané
|
||||
rates-more-evidence = Existujú ďalšie dôkazy; spresnite vyhľadávanie alebo pokračujte kurzorom API.
|
||||
rates-provider-operations = Prevádzka
|
||||
rates-provider-health = Stav poskytovateľa
|
||||
rates-provider-health-hint = Overené pokrytie, hranice účtovania a nedávne pokusy o import oficiálneho poskytovateľa.
|
||||
rates-provider-health = Možno účtovať cudzomenové záznamy?
|
||||
rates-provider-health-hint = Aktuálna dostupnosť a posledná úspešná automatická aktualizácia.
|
||||
rates-unavailable-title = Konverzné kurzy nie sú dostupné
|
||||
rates-err-profile-missing = Vybraný profil už neexistuje. Zobrazuje sa prvý dostupný profil.
|
||||
rates-err-record-id = ID záznamu musí byť kladné celé číslo.
|
||||
|
||||
@@ -61,7 +61,6 @@ pub(crate) async fn load_ecb_page(
|
||||
Ok(EcbPageState {
|
||||
nav: crate::ui::Nav::from_authorization(headers, "ecb", &authorization),
|
||||
verified_through_date: status.verified_through_date,
|
||||
latest_verifiable_date: status.latest_verifiable_date,
|
||||
healthy: status.healthy,
|
||||
days_behind: status.days_behind,
|
||||
import_running: status.import_running,
|
||||
|
||||
@@ -147,7 +147,6 @@ impl ImportBatchView {
|
||||
pub(crate) struct EcbPageState {
|
||||
pub nav: crate::ui::Nav,
|
||||
pub verified_through_date: Option<String>,
|
||||
pub latest_verifiable_date: String,
|
||||
pub healthy: bool,
|
||||
pub days_behind: i32,
|
||||
pub import_running: bool,
|
||||
@@ -188,24 +187,6 @@ impl EcbPageState {
|
||||
}
|
||||
}
|
||||
|
||||
/// The "3 publication days behind" tag in the coverage row.
|
||||
pub(crate) fn behind_label(&self) -> String {
|
||||
tr!(
|
||||
self.nav.locale,
|
||||
"ecb-behind-count",
|
||||
"count" => self.days_behind as i64,
|
||||
)
|
||||
}
|
||||
|
||||
/// "2 failed" above the attempts table.
|
||||
pub(crate) fn failed_count_label(&self) -> String {
|
||||
tr!(
|
||||
self.nav.locale,
|
||||
"ecb-failed-count",
|
||||
"count" => self.failure_count() as i64,
|
||||
)
|
||||
}
|
||||
|
||||
/// The class the status card is painted with.
|
||||
pub(crate) fn health_class(&self) -> &'static str {
|
||||
if self.healthy { "healthy" } else { "unhealthy" }
|
||||
@@ -230,17 +211,6 @@ impl EcbPageState {
|
||||
}
|
||||
}
|
||||
|
||||
/// The newest attempt of any outcome, which is what "has the importer run
|
||||
/// at all lately" asks about.
|
||||
pub(crate) fn last_attempt(&self) -> Option<String> {
|
||||
let batch = self.batches.first()?;
|
||||
let when = batch.completed_at.as_deref().unwrap_or(&batch.started_at);
|
||||
Some(match from_now(self.nav.locale, when) {
|
||||
Some(relative) => format!("{} ({relative})", moment(when)),
|
||||
None => moment(when),
|
||||
})
|
||||
}
|
||||
|
||||
/// Successes are what move coverage; a run of failures on top of an old
|
||||
/// success is a different picture from no runs at all.
|
||||
pub(crate) fn last_success(&self) -> Option<String> {
|
||||
@@ -252,13 +222,6 @@ impl EcbPageState {
|
||||
})
|
||||
}
|
||||
|
||||
/// Failures among the attempts on the page. One is an incident; several in
|
||||
/// a row is a broken pipeline, and the count is the only thing that
|
||||
/// distinguishes them at a glance.
|
||||
pub(crate) fn failure_count(&self) -> usize {
|
||||
self.batches.iter().filter(|batch| batch.failed()).count()
|
||||
}
|
||||
|
||||
/// Alphabetical, because the reader is looking one up rather than reading
|
||||
/// the list through.
|
||||
pub(crate) fn currencies(&self) -> Vec<String> {
|
||||
|
||||
@@ -83,7 +83,6 @@ mod tests {
|
||||
EcbPageState {
|
||||
nav: Nav::default(),
|
||||
verified_through_date: Some("2026-08-12".to_string()),
|
||||
latest_verifiable_date: "2026-08-12".to_string(),
|
||||
healthy: true,
|
||||
days_behind: 0,
|
||||
import_running: false,
|
||||
@@ -102,7 +101,7 @@ mod tests {
|
||||
let html = render_page(&healthy_page());
|
||||
|
||||
assert!(!html.contains("Template error"), "{html}");
|
||||
assert!(html.contains("Rates are current"));
|
||||
assert!(html.contains("Foreign-currency posting is available"));
|
||||
assert!(html.contains("healthy"));
|
||||
assert!(html.contains("2026-08-12"));
|
||||
assert!(html.contains("CZK"));
|
||||
@@ -120,10 +119,9 @@ mod tests {
|
||||
let html = render_page(&page);
|
||||
|
||||
assert!(!html.contains("Template error"), "{html}");
|
||||
assert!(html.contains("Rates are behind"));
|
||||
assert!(html.contains("Some foreign-currency records may be blocked"));
|
||||
assert!(html.contains("unhealthy"));
|
||||
assert!(html.contains("3 publication days are missing"));
|
||||
assert!(html.contains("3 publication days behind"));
|
||||
}
|
||||
|
||||
/// Timestamps arrive as RFC 3339 instants and must not reach the page that
|
||||
@@ -140,17 +138,19 @@ mod tests {
|
||||
assert!(html.contains("4s"));
|
||||
}
|
||||
|
||||
/// The counts above the table are how a run of bad days is told apart from
|
||||
/// one bad day without reading every row.
|
||||
/// Historical failures are troubleshooting detail, not a contradictory
|
||||
/// headline beside a healthy current status.
|
||||
#[test]
|
||||
fn failed_attempts_are_counted_above_the_table() {
|
||||
fn historical_failures_are_collapsed_as_technical_history() {
|
||||
let mut page = healthy_page();
|
||||
page.batches.push(batch(8, "failed"));
|
||||
page.batches.push(batch(7, "failed"));
|
||||
|
||||
let html = render_page(&page);
|
||||
|
||||
assert!(html.contains("2 failed"), "{html}");
|
||||
assert!(html.contains("Technical update history"), "{html}");
|
||||
assert!(html.contains("<details class=\"panel\">"), "{html}");
|
||||
assert!(!html.contains("2 failed"), "{html}");
|
||||
}
|
||||
|
||||
/// Coverage is a publication date; the reader's question is which dates
|
||||
@@ -160,12 +160,12 @@ mod tests {
|
||||
fn the_card_says_which_dates_can_be_posted() {
|
||||
let html = render_page(&healthy_page());
|
||||
|
||||
assert!(html.contains("What can be posted right now"), "{html}");
|
||||
assert!(html.contains("Ordinary transactions"));
|
||||
assert!(html.contains("Accepted transaction dates"), "{html}");
|
||||
assert!(html.contains("Regular transactions"));
|
||||
assert!(html.contains("<strong>2026-08-13</strong>"), "{html}");
|
||||
// Askama escapes `&` numerically. The title now comes from the
|
||||
// catalogue as plain text, where it was pre-escaped markup before.
|
||||
assert!(html.contains("Statements & decisive dates"), "{html}");
|
||||
assert!(html.contains("Statements and dated balances"), "{html}");
|
||||
assert!(html.contains("<strong>2026-08-12</strong>"), "{html}");
|
||||
}
|
||||
|
||||
@@ -184,8 +184,8 @@ mod tests {
|
||||
let html = render_page(&page);
|
||||
|
||||
assert!(!html.contains("Template error"), "{html}");
|
||||
assert!(html.contains("No rates have ever been imported"));
|
||||
assert!(html.contains("every conversion in a foreign currency is refused"));
|
||||
assert!(html.contains("Foreign-currency posting is unavailable"));
|
||||
assert!(html.contains("Foreign-currency records cannot be posted"));
|
||||
// And the postable block says so too rather than showing an empty date.
|
||||
assert!(html.contains("<strong>Nothing.</strong>"), "{html}");
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ mod tests {
|
||||
EcbPageState {
|
||||
nav: Nav::default(),
|
||||
verified_through_date: Some("2026-08-23".to_string()),
|
||||
latest_verifiable_date: "2026-08-23".to_string(),
|
||||
healthy: true,
|
||||
days_behind: 0,
|
||||
import_running: false,
|
||||
@@ -115,7 +114,10 @@ mod tests {
|
||||
assert!(!html.contains("Template error"), "{html}");
|
||||
assert!(html.contains("Profile configuration"), "{html}");
|
||||
assert!(html.contains("Evidence lookup"), "{html}");
|
||||
assert!(html.contains("Provider health"), "{html}");
|
||||
assert!(
|
||||
html.contains("Can foreign-currency records be posted?"),
|
||||
"{html}"
|
||||
);
|
||||
assert!(html.contains("CZK"), "{html}");
|
||||
assert!(html.contains("ecb"), "{html}");
|
||||
assert!(html.contains("Ready"), "{html}");
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<section class="panel">
|
||||
<h2>
|
||||
{{ nav.tr("ecb-import-attempts") }} <span class="count">{{ page.batches.len() }}</span>
|
||||
{%- if page.failure_count() > 0 %}<span class="tag tag-bad">{{ page.failed_count_label() }}</span>{% endif -%}
|
||||
</h2>
|
||||
<details class="panel">
|
||||
<summary><strong>{{ nav.tr("ecb-technical-history") }}</strong> <span class="count">{{ page.batches.len() }}</span></summary>
|
||||
<p class="hint">{{ nav.tr("ecb-technical-history-hint") }}</p>
|
||||
{% if page.batches.is_empty() %}
|
||||
<p class="hint">{{ nav.tr("ecb-no-attempts-hint") }}</p>
|
||||
{% else %}
|
||||
@@ -55,4 +53,4 @@
|
||||
</div>
|
||||
<p class="hint">{{ nav.tr("ecb-audit-hint") }}</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
</details>
|
||||
|
||||
@@ -18,63 +18,6 @@
|
||||
|
||||
{% include "pages/admin/ecb/status.html" %}
|
||||
|
||||
<section class="panel">
|
||||
<h2>
|
||||
{{ nav.tr("ecb-import-attempts") }} <span class="count">{{ page.batches.len() }}</span>
|
||||
{%- if page.failure_count() > 0 %}<span class="tag tag-bad">{{ page.failed_count_label() }}</span>{% endif -%}
|
||||
</h2>
|
||||
{% if page.batches.is_empty() %}
|
||||
<p class="hint">{{ nav.tr("ecb-no-attempts-hint") }}</p>
|
||||
{% else %}
|
||||
<div class="table-scroll">
|
||||
<table class="builder-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="mark">#</th><th>{{ nav.tr("ecb-th-result") }}</th><th>{{ nav.tr("ecb-th-started") }}</th><th>{{ nav.tr("ecb-th-finished") }}</th>
|
||||
<th>{{ nav.tr("ecb-th-took") }}</th><th>{{ nav.tr("ecb-th-window") }}</th><th class="numeric">{{ nav.tr("ecb-th-observations") }}</th>
|
||||
<th>{{ nav.tr("ecb-th-verified-through") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for batch in page.batches %}
|
||||
<tr{% if batch.failed() %} class="attempt-failed"{% endif %}>
|
||||
<td class="mark">{{ batch.batch_id }}</td>
|
||||
<td>
|
||||
{%- if batch.succeeded() %}<span class="tag tag-ok">{{ nav.tr("ecb-batch-succeeded") }}</span>
|
||||
{%- else if batch.running() %}<span class="tag">{{ nav.tr("ecb-batch-running") }}</span>
|
||||
{%- else %}<span class="tag tag-bad">{{ nav.tr("ecb-batch-failed") }}</span>{% endif -%}
|
||||
</td>
|
||||
<td class="moment">{{ batch.started() }}</td>
|
||||
<td class="moment">
|
||||
{%- if let Some(finished) = batch.finished() %}{{ finished }}
|
||||
{%- else %}<span class="hint">{{ nav.tr("ecb-still-running") }}</span>{% endif -%}
|
||||
</td>
|
||||
<td class="numeric">
|
||||
{%- if let Some(took) = batch.took(nav.locale) %}{{ took }}
|
||||
{%- else %}<span class="hint">—</span>{% endif -%}
|
||||
</td>
|
||||
<td>
|
||||
{{ batch.window() }}
|
||||
<div class="hint endpoint" title="{{ batch.endpoint }}"><code>{{ batch.endpoint }}</code></div>
|
||||
</td>
|
||||
<td class="numeric">{{ batch.observations(nav.locale) }}</td>
|
||||
<td class="moment">
|
||||
{%- if let Some(date) = batch.verified_through_date %}{{ date }}
|
||||
{%- else %}<span class="hint">—</span>{% endif -%}
|
||||
</td>
|
||||
</tr>
|
||||
{% if let Some(message) = batch.error_message %}
|
||||
<tr class="attempt-error">
|
||||
<td class="mark"></td>
|
||||
<td colspan="7">{{ message }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="hint">{{ nav.tr("ecb-audit-hint") }}</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% include "pages/admin/ecb/attempts.html" %}
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
</h2>
|
||||
<p class="hint">{{ page.explanation() }}</p>
|
||||
|
||||
{# The question a reader came with. Coverage is a publication date, and
|
||||
turning it into "which transaction dates will post" means applying the
|
||||
rule the backend applies -- so the backend applies it and sends both
|
||||
bounds, rather than the page inviting the reader to do it in their head. #}
|
||||
<div class="postable">
|
||||
<p class="postable-lead">{{ nav.tr("ecb-postable-lead") }}</p>
|
||||
{% if let Some(through) = page.transactions_postable_through %}
|
||||
@@ -27,48 +23,21 @@
|
||||
<div>
|
||||
<dt>{{ nav.tr("ecb-ordinary-transactions") }}</dt>
|
||||
<dd>{{ nav.tr("ecb-dated-up-to") }} <strong>{{ through }}</strong></dd>
|
||||
<dd class="hint">{{ nav.tr("ecb-ordinary-rate-hint") }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ nav.tr("ecb-statements-title") }}</dt>
|
||||
<dd>{{ nav.tr("ecb-dated-up-to") }} <strong>{{ page.statements_postable_through.as_deref().unwrap_or("—") }}</strong></dd>
|
||||
<dd class="hint">{{ nav.tr("ecb-statements-rate-hint") }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="hint">{{ nav.tr("ecb-postable-limit-hint") }}</p>
|
||||
{% else %}
|
||||
<p>
|
||||
<strong>{{ nav.tr("ecb-nothing") }}</strong> {{ nav.tr("ecb-no-publication-hint") }}
|
||||
</p>
|
||||
<p><strong>{{ nav.tr("ecb-nothing") }}</strong> {{ nav.tr("ecb-no-publication-hint") }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Coverage first and on its own line: the two dates and the gap between
|
||||
them are the whole answer, and burying them in a four-column grid made
|
||||
them read as trivia. #}
|
||||
<div class="coverage">
|
||||
<div class="coverage-point">
|
||||
<span class="coverage-label">{{ nav.tr("ecb-verified-through") }}</span>
|
||||
<span class="coverage-date">
|
||||
{%- if let Some(date) = page.verified_through_date %}{{ date }}
|
||||
{%- else %}{{ nav.tr("ecb-never") }}{% endif -%}
|
||||
</span>
|
||||
</div>
|
||||
<div class="coverage-gap">
|
||||
{%- if page.healthy %}<span class="tag tag-ok">{{ nav.tr("ecb-up-to-date") }}</span>
|
||||
{%- else if page.days_behind > 0 %}<span class="tag tag-bad">{{ page.behind_label() }}</span>
|
||||
{%- else %}<span class="tag tag-bad">{{ nav.tr("ecb-no-coverage") }}</span>{% endif -%}
|
||||
</div>
|
||||
<div class="coverage-point">
|
||||
<span class="coverage-label">{{ nav.tr("ecb-should-reach") }}</span>
|
||||
<span class="coverage-date">{{ page.latest_verifiable_date }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dl class="status-grid">
|
||||
<div>
|
||||
<dt>{{ nav.tr("ecb-last-attempt") }}</dt>
|
||||
<dd>{% if let Some(when) = page.last_attempt() %}{{ when }}{% else %}<span class="hint">{{ nav.tr("ecb-none-recorded") }}</span>{% endif %}</dd>
|
||||
<dt>{{ nav.tr("ecb-verified-through") }}</dt>
|
||||
<dd>{% if let Some(date) = page.verified_through_date %}<strong>{{ date }}</strong>{% else %}<span class="hint">{{ nav.tr("ecb-never") }}</span>{% endif %}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ nav.tr("ecb-last-success") }}</dt>
|
||||
@@ -78,25 +47,21 @@
|
||||
<dt>{{ nav.tr("ecb-next-import") }}</dt>
|
||||
<dd>{{ page.next_import() }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{% if let Some(date) = page.verified_through_date %}{{ nav.tr_args("ecb-currencies-on", [("date", date.clone())]) }}{% else %}{{ nav.tr("ecb-the-covered-day") }}{% endif %}</dt>
|
||||
<dd>
|
||||
{%- if page.covered_currencies.is_empty() %}<span class="hint">{{ nav.tr("ecb-none") }}</span>
|
||||
{%- else %}{{ page.covered_currencies.len() }}{% endif -%}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
{% if !page.covered_currencies.is_empty() %}
|
||||
<div class="currency-list">
|
||||
<strong>{{ nav.tr("ecb-ready-currencies") }}</strong>
|
||||
{% for currency in page.currencies() %}<span class="tag">{{ currency }}</span>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if let Some(failure) = page.last_failure() %}
|
||||
<p class="hint failure-note">
|
||||
{{ nav.tr_args("ecb-most-recent-failure", [("batch", failure.batch_id.to_string()), ("started", failure.started())]) }}
|
||||
{% if let Some(message) = failure.error_message %}{{ message }}{% else %}{{ nav.tr("ecb-no-reason-recorded") }}{% endif %}
|
||||
</p>
|
||||
{% if !page.healthy %}
|
||||
{% if let Some(failure) = page.last_failure() %}
|
||||
<p class="failure-note">
|
||||
<strong>{{ nav.tr("ecb-latest-problem") }}</strong>
|
||||
{% if let Some(message) = failure.error_message %}{{ message }}{% else %}{{ nav.tr("ecb-no-reason-recorded") }}{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
</section>
|
||||
|
||||
<section id="providers">
|
||||
<div class="heading"><div><p class="eyebrow">{{ nav.tr("rates-provider-operations") }}</p><h2>{{ nav.tr("rates-provider-health") }}</h2><p>{{ nav.tr("rates-provider-health-hint") }}</p></div></div>
|
||||
<div class="heading"><div><h2>{{ nav.tr("rates-provider-health") }}</h2><p>{{ nav.tr("rates-provider-health-hint") }}</p></div></div>
|
||||
{{ provider_status|safe }}
|
||||
{{ provider_attempts|safe }}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user