fmt
This commit is contained in:
parent
cf348c3ea4
commit
d1faad314b
14 changed files with 55 additions and 35 deletions
|
|
@ -18,7 +18,6 @@ from __future__ import annotations
|
||||||
|
|
||||||
import html
|
import html
|
||||||
import json
|
import json
|
||||||
import urllib.parse
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
ROOT = Path(".")
|
ROOT = Path(".")
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ def twin_kit(f: dict) -> str:
|
||||||
]
|
]
|
||||||
captions = [
|
captions = [
|
||||||
f"{pn} vs {wn}",
|
f"{pn} vs {wn}",
|
||||||
f"Same station. Same schools.",
|
"Same station. Same schools.",
|
||||||
f"{money} cheaper",
|
f"{money} cheaper",
|
||||||
f"Same {typ}, ~{s['build_year']}",
|
f"Same {typ}, ~{s['build_year']}",
|
||||||
f"{gap} less per m²",
|
f"{gap} less per m²",
|
||||||
|
|
@ -135,7 +135,7 @@ def twin_kit(f: dict) -> str:
|
||||||
"",
|
"",
|
||||||
f"**Page:** {SITE}{f['page_path']} · **Format:** faceless screen-record, ~45–60s long + a 9:16 Short cut",
|
f"**Page:** {SITE}{f['page_path']} · **Format:** faceless screen-record, ~45–60s long + a 9:16 Short cut",
|
||||||
"",
|
"",
|
||||||
f"## 🎬 Map URL to record (open this, hit record)",
|
"## 🎬 Map URL to record (open this, hit record)",
|
||||||
f"`{url}`",
|
f"`{url}`",
|
||||||
"*(filters are pre-applied so the value is on screen immediately)*",
|
"*(filters are pre-applied so the value is on screen immediately)*",
|
||||||
"",
|
"",
|
||||||
|
|
|
||||||
|
|
@ -139,9 +139,6 @@ def curate(tw: pl.DataFrame) -> list[dict]:
|
||||||
|
|
||||||
|
|
||||||
def national_findings(idx: pl.DataFrame, facts: dict) -> list[dict]:
|
def national_findings(idx: pl.DataFrame, facts: dict) -> list[dict]:
|
||||||
named = idx.with_columns(
|
|
||||||
pl.col("Sector").str.extract(r"^([A-Z]+[0-9][A-Z0-9]?)", 1).alias("outward")
|
|
||||||
)
|
|
||||||
best = facts["best_value_sector"]
|
best = facts["best_value_sector"]
|
||||||
dear = facts["dearest_sector"]
|
dear = facts["dearest_sector"]
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,8 @@
|
||||||
"ax1.plot(yr, piv[\"existing\"].to_numpy(), marker=\"o\", label=\"Existing houses\", color=\"#0f766e\")\n",
|
"ax1.plot(yr, piv[\"existing\"].to_numpy(), marker=\"o\", label=\"Existing houses\", color=\"#0f766e\")\n",
|
||||||
"ax1.plot(yr, piv[\"new\"].to_numpy(), marker=\"s\", label=\"New-build houses\", color=\"#d97706\")\n",
|
"ax1.plot(yr, piv[\"new\"].to_numpy(), marker=\"s\", label=\"New-build houses\", color=\"#d97706\")\n",
|
||||||
"ax1.set_title(\"Median £/sqm by sale year\")\n",
|
"ax1.set_title(\"Median £/sqm by sale year\")\n",
|
||||||
"ax1.set_xlabel(\"Year\"); ax1.set_ylabel(\"£/sqm\")\n",
|
"ax1.set_xlabel(\"Year\")\n",
|
||||||
|
"ax1.set_ylabel(\"£/sqm\")\n",
|
||||||
"ax1.yaxis.set_major_formatter(mticker.StrMethodFormatter(\"£{x:,.0f}\"))\n",
|
"ax1.yaxis.set_major_formatter(mticker.StrMethodFormatter(\"£{x:,.0f}\"))\n",
|
||||||
"ax1.legend()\n",
|
"ax1.legend()\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -323,9 +324,11 @@
|
||||||
"ax2.bar(yr, piv[\"premium_pct\"].to_numpy(), color=colors)\n",
|
"ax2.bar(yr, piv[\"premium_pct\"].to_numpy(), color=colors)\n",
|
||||||
"ax2.axhline(0, color=\"black\", lw=0.8)\n",
|
"ax2.axhline(0, color=\"black\", lw=0.8)\n",
|
||||||
"ax2.set_title(\"New-build premium (median £/sqm, new vs existing)\")\n",
|
"ax2.set_title(\"New-build premium (median £/sqm, new vs existing)\")\n",
|
||||||
"ax2.set_xlabel(\"Year\"); ax2.set_ylabel(\"Premium %\")\n",
|
"ax2.set_xlabel(\"Year\")\n",
|
||||||
|
"ax2.set_ylabel(\"Premium %\")\n",
|
||||||
"ax2.yaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
"ax2.yaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
||||||
"plt.tight_layout(); plt.show()\n",
|
"plt.tight_layout()\n",
|
||||||
|
"plt.show()\n",
|
||||||
"\n",
|
"\n",
|
||||||
"piv.select(\"year\", \"existing\", \"new\", \"premium_pct\", \"n_new\", \"n_existing\")"
|
"piv.select(\"year\", \"existing\", \"new\", \"premium_pct\", \"n_new\", \"n_existing\")"
|
||||||
]
|
]
|
||||||
|
|
@ -426,7 +429,8 @@
|
||||||
"for y, v, nnew in zip(range(len(labels)), vals, area_prem[\"n_new\"].to_list()):\n",
|
"for y, v, nnew in zip(range(len(labels)), vals, area_prem[\"n_new\"].to_list()):\n",
|
||||||
" ax.text(v + (0.4 if v >= 0 else -0.4), y, f\"n={nnew}\", va=\"center\",\n",
|
" ax.text(v + (0.4 if v >= 0 else -0.4), y, f\"n={nnew}\", va=\"center\",\n",
|
||||||
" ha=\"left\" if v >= 0 else \"right\", fontsize=8, color=\"#555\")\n",
|
" ha=\"left\" if v >= 0 else \"right\", fontsize=8, color=\"#555\")\n",
|
||||||
"plt.tight_layout(); plt.show()\n",
|
"plt.tight_layout()\n",
|
||||||
|
"plt.show()\n",
|
||||||
"area_prem"
|
"area_prem"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -523,10 +527,12 @@
|
||||||
"ax.axvline(np.median(old_cagr), color=\"#0f766e\", ls=\"--\", lw=1.2)\n",
|
"ax.axvline(np.median(old_cagr), color=\"#0f766e\", ls=\"--\", lw=1.2)\n",
|
||||||
"ax.axvline(np.median(new_cagr), color=\"#d97706\", ls=\"--\", lw=1.2)\n",
|
"ax.axvline(np.median(new_cagr), color=\"#d97706\", ls=\"--\", lw=1.2)\n",
|
||||||
"ax.set_title(\"Distribution of annualised resale growth (CAGR)\")\n",
|
"ax.set_title(\"Distribution of annualised resale growth (CAGR)\")\n",
|
||||||
"ax.set_xlabel(\"CAGR % per year\"); ax.set_ylabel(\"density\")\n",
|
"ax.set_xlabel(\"CAGR % per year\")\n",
|
||||||
|
"ax.set_ylabel(\"density\")\n",
|
||||||
"ax.xaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
"ax.xaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
||||||
"ax.legend()\n",
|
"ax.legend()\n",
|
||||||
"plt.tight_layout(); plt.show()"
|
"plt.tight_layout()\n",
|
||||||
|
"plt.show()"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -603,16 +609,19 @@
|
||||||
"\n",
|
"\n",
|
||||||
"area_cagr = cagr_by(\"area\")\n",
|
"area_cagr = cagr_by(\"area\")\n",
|
||||||
"labels = area_cagr[\"area\"].to_list()\n",
|
"labels = area_cagr[\"area\"].to_list()\n",
|
||||||
"x = np.arange(len(labels)); w = 0.4\n",
|
"x = np.arange(len(labels))\n",
|
||||||
|
"w = 0.4\n",
|
||||||
"fig, ax = plt.subplots(figsize=(10, 4.5))\n",
|
"fig, ax = plt.subplots(figsize=(10, 4.5))\n",
|
||||||
"ax.bar(x - w/2, area_cagr[\"existing_cagr\"].to_numpy(), w, label=\"Existing\", color=\"#0f766e\")\n",
|
"ax.bar(x - w/2, area_cagr[\"existing_cagr\"].to_numpy(), w, label=\"Existing\", color=\"#0f766e\")\n",
|
||||||
"ax.bar(x + w/2, area_cagr[\"newbuild_cagr\"].to_numpy(), w, label=\"New-build\", color=\"#d97706\")\n",
|
"ax.bar(x + w/2, area_cagr[\"newbuild_cagr\"].to_numpy(), w, label=\"New-build\", color=\"#d97706\")\n",
|
||||||
"ax.set_xticks(x); ax.set_xticklabels(labels)\n",
|
"ax.set_xticks(x)\n",
|
||||||
|
"ax.set_xticklabels(labels)\n",
|
||||||
"ax.set_title(\"Median resale CAGR by postal area\")\n",
|
"ax.set_title(\"Median resale CAGR by postal area\")\n",
|
||||||
"ax.set_ylabel(\"CAGR % per year\")\n",
|
"ax.set_ylabel(\"CAGR % per year\")\n",
|
||||||
"ax.yaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
"ax.yaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
||||||
"ax.legend()\n",
|
"ax.legend()\n",
|
||||||
"plt.tight_layout(); plt.show()\n",
|
"plt.tight_layout()\n",
|
||||||
|
"plt.show()\n",
|
||||||
"area_cagr"
|
"area_cagr"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -699,22 +708,25 @@
|
||||||
" area_cagr.select(\"area\", \"cagr_gap\", \"newbuild_cagr\", \"existing_cagr\"), on=\"area\", how=\"inner\"\n",
|
" area_cagr.select(\"area\", \"cagr_gap\", \"newbuild_cagr\", \"existing_cagr\"), on=\"area\", how=\"inner\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"fig, ax = plt.subplots(figsize=(8, 6))\n",
|
"fig, ax = plt.subplots(figsize=(8, 6))\n",
|
||||||
"xs = combined[\"premium_pct\"].to_numpy(); ys = combined[\"cagr_gap\"].to_numpy()\n",
|
"xs = combined[\"premium_pct\"].to_numpy()\n",
|
||||||
|
"ys = combined[\"cagr_gap\"].to_numpy()\n",
|
||||||
"ax.scatter(xs, ys, s=70, color=\"#d97706\", zorder=3)\n",
|
"ax.scatter(xs, ys, s=70, color=\"#d97706\", zorder=3)\n",
|
||||||
"for a, xv, yv in zip(combined[\"area\"].to_list(), xs, ys):\n",
|
"for a, xv, yv in zip(combined[\"area\"].to_list(), xs, ys):\n",
|
||||||
" ax.annotate(a, (xv, yv), textcoords=\"offset points\", xytext=(6, 4), fontsize=10)\n",
|
" ax.annotate(a, (xv, yv), textcoords=\"offset points\", xytext=(6, 4), fontsize=10)\n",
|
||||||
"ax.axhline(0, color=\"black\", lw=0.8); ax.axvline(0, color=\"black\", lw=0.8)\n",
|
"ax.axhline(0, color=\"black\", lw=0.8)\n",
|
||||||
|
"ax.axvline(0, color=\"black\", lw=0.8)\n",
|
||||||
"ax.set_xlabel(\"New-build £/sqm premium at purchase\")\n",
|
"ax.set_xlabel(\"New-build £/sqm premium at purchase\")\n",
|
||||||
"ax.set_ylabel(\"New-build CAGR minus existing CAGR (pp/yr)\")\n",
|
"ax.set_ylabel(\"New-build CAGR minus existing CAGR (pp/yr)\")\n",
|
||||||
"ax.xaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
"ax.xaxis.set_major_formatter(mticker.PercentFormatter(decimals=0))\n",
|
||||||
"ax.set_title(\"Premium paid vs appreciation gap, by London postal area\")\n",
|
"ax.set_title(\"Premium paid vs appreciation gap, by London postal area\")\n",
|
||||||
"plt.tight_layout(); plt.show()\n",
|
"plt.tight_layout()\n",
|
||||||
|
"plt.show()\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Headline numbers for the writeup.\n",
|
"# Headline numbers for the writeup.\n",
|
||||||
"hl = summary.to_dicts()\n",
|
"hl = summary.to_dicts()\n",
|
||||||
"new_row = next(r for r in hl if r[\"is_newbuild_prop\"])\n",
|
"new_row = next(r for r in hl if r[\"is_newbuild_prop\"])\n",
|
||||||
"old_row = next(r for r in hl if not r[\"is_newbuild_prop\"])\n",
|
"old_row = next(r for r in hl if not r[\"is_newbuild_prop\"])\n",
|
||||||
"print(f\"London terraced/detached, repeat sales:\")\n",
|
"print(\"London terraced/detached, repeat sales:\")\n",
|
||||||
"print(f\" existing median CAGR: {old_row['median_cagr_pct']}%/yr (n={old_row['n']:,})\")\n",
|
"print(f\" existing median CAGR: {old_row['median_cagr_pct']}%/yr (n={old_row['n']:,})\")\n",
|
||||||
"print(f\" new-build median CAGR: {new_row['median_cagr_pct']}%/yr (n={new_row['n']:,})\")\n",
|
"print(f\" new-build median CAGR: {new_row['median_cagr_pct']}%/yr (n={new_row['n']:,})\")\n",
|
||||||
"print(f\" appreciation gap: {round(new_row['median_cagr_pct']-old_row['median_cagr_pct'],2)} pp/yr\")\n",
|
"print(f\" appreciation gap: {round(new_row['median_cagr_pct']-old_row['median_cagr_pct'],2)} pp/yr\")\n",
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,7 @@ export default function ResetPasswordPage({
|
||||||
onClearError: () => void;
|
onClearError: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const token = useMemo(
|
const token = useMemo(() => new URLSearchParams(window.location.search).get('token') ?? '', []);
|
||||||
() => new URLSearchParams(window.location.search).get('token') ?? '',
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [done, setDone] = useState(false);
|
const [done, setDone] = useState(false);
|
||||||
|
|
@ -60,7 +57,9 @@ export default function ResetPasswordPage({
|
||||||
|
|
||||||
{!token ? (
|
{!token ? (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<p className="text-sm text-warm-600 dark:text-warm-300">{t('auth.resetMissingToken')}</p>
|
<p className="text-sm text-warm-600 dark:text-warm-300">
|
||||||
|
{t('auth.resetMissingToken')}
|
||||||
|
</p>
|
||||||
<button type="button" onClick={onLoginClick} className={loginButtonClass}>
|
<button type="button" onClick={onLoginClick} className={loginButtonClass}>
|
||||||
{t('auth.goToLogin')}
|
{t('auth.goToLogin')}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,9 @@ export function ActiveFilterList({
|
||||||
dragValue={dragValue}
|
dragValue={dragValue}
|
||||||
pinnedFeature={pinnedFeature}
|
pinnedFeature={pinnedFeature}
|
||||||
filterImpact={councilBackendName ? filterImpacts?.[councilBackendName] : undefined}
|
filterImpact={councilBackendName ? filterImpacts?.[councilBackendName] : undefined}
|
||||||
percentileScale={councilBackendName ? percentileScales.get(councilBackendName) : undefined}
|
percentileScale={
|
||||||
|
councilBackendName ? percentileScales.get(councilBackendName) : undefined
|
||||||
|
}
|
||||||
onFilterChange={onFilterChange}
|
onFilterChange={onFilterChange}
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
onDragChange={onDragChange}
|
onDragChange={onDragChange}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ const FOLDED_FILTER_RESOLVERS: Array<(name: string) => string | null> = [
|
||||||
(name) => (isQualificationFilterName(name) ? QUALIFICATIONS_FILTER_NAME : null),
|
(name) => (isQualificationFilterName(name) ? QUALIFICATIONS_FILTER_NAME : null),
|
||||||
(name) => (isTenureFilterName(name) ? TENURE_FILTER_NAME : null),
|
(name) => (isTenureFilterName(name) ? TENURE_FILTER_NAME : null),
|
||||||
(name) => (isCouncilFilterName(name) ? COUNCIL_FILTER_NAME : null),
|
(name) => (isCouncilFilterName(name) ? COUNCIL_FILTER_NAME : null),
|
||||||
(name) => (isPoiDistanceFilterName(name) ? (getPoiFilterName(name) ?? POI_DISTANCE_FILTER_NAME) : null),
|
(name) =>
|
||||||
|
isPoiDistanceFilterName(name) ? (getPoiFilterName(name) ?? POI_DISTANCE_FILTER_NAME) : null,
|
||||||
(name) => (isCrimeSeverityFilterName(name) ? (getCrimeSeverityFilterName(name) ?? name) : null),
|
(name) => (isCrimeSeverityFilterName(name) ? (getCrimeSeverityFilterName(name) ?? name) : null),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,10 @@ export function useFilters({
|
||||||
const normalizedOriginal = normalizeFilters(initialFilters);
|
const normalizedOriginal = normalizeFilters(initialFilters);
|
||||||
originalNormalizedRef.current = normalizedOriginal;
|
originalNormalizedRef.current = normalizedOriginal;
|
||||||
const budget = filterLimit != null ? Math.max(0, filterLimit - reservedFilterSlots) : null;
|
const budget = filterLimit != null ? Math.max(0, filterLimit - reservedFilterSlots) : null;
|
||||||
initialFiltersRef.current = clampToBudget(dropUnknownFilters(normalizedOriginal, features), budget);
|
initialFiltersRef.current = clampToBudget(
|
||||||
|
dropUnknownFilters(normalizedOriginal, features),
|
||||||
|
budget
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [filters, setFilters] = useState<FeatureFilters>(() => initialFiltersRef.current!);
|
const [filters, setFilters] = useState<FeatureFilters>(() => initialFiltersRef.current!);
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,10 @@ async function detectSessionRejection(
|
||||||
onSessionRejected?: () => void
|
onSessionRejected?: () => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (res.status !== 400 || !onSessionRejected || !pb.authStore.isValid) return;
|
if (res.status !== 400 || !onSessionRejected || !pb.authStore.isValid) return;
|
||||||
const body = await res.clone().json().catch(() => null);
|
const body = await res
|
||||||
|
.clone()
|
||||||
|
.json()
|
||||||
|
.catch(() => null);
|
||||||
if (body && (body as { error?: string }).error === 'filter_limit') {
|
if (body && (body as { error?: string }).error === 'filter_limit') {
|
||||||
onSessionRejected();
|
onSessionRejected();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,8 @@ const descriptions: Record<string, Record<string, string>> = {
|
||||||
'% Private rent': 'Part des ménages locataires dans le privé ou logés à titre gratuit',
|
'% Private rent': 'Part des ménages locataires dans le privé ou logés à titre gratuit',
|
||||||
'% Council housing':
|
'% Council housing':
|
||||||
'Part des logements du code postal déjà enregistrés comme logement municipal ou social',
|
'Part des logements du code postal déjà enregistrés comme logement municipal ou social',
|
||||||
'% Ex-council': 'Part des logements du code postal autrefois municipaux mais qui ne le sont plus',
|
'% Ex-council':
|
||||||
|
'Part des logements du code postal autrefois municipaux mais qui ne le sont plus',
|
||||||
'% White': 'Part de la population s’identifiant comme blanche',
|
'% White': 'Part de la population s’identifiant comme blanche',
|
||||||
'% South Asian': 'Part de la population s’identifiant comme sud-asiatique',
|
'% South Asian': 'Part de la population s’identifiant comme sud-asiatique',
|
||||||
'% Black': 'Part de la population s’identifiant comme noire',
|
'% Black': 'Part de la population s’identifiant comme noire',
|
||||||
|
|
|
||||||
|
|
@ -635,7 +635,8 @@ const hi: Translations = {
|
||||||
updatePassword: 'पासवर्ड अपडेट करें',
|
updatePassword: 'पासवर्ड अपडेट करें',
|
||||||
resetSuccessBody: 'आपका पासवर्ड बदल दिया गया है। अब आप अपने नए पासवर्ड से लॉग इन कर सकते हैं।',
|
resetSuccessBody: 'आपका पासवर्ड बदल दिया गया है। अब आप अपने नए पासवर्ड से लॉग इन कर सकते हैं।',
|
||||||
resetMissingToken: 'यह रीसेट लिंक अधूरा है। लॉग इन स्क्रीन से नया लिंक प्राप्त करें।',
|
resetMissingToken: 'यह रीसेट लिंक अधूरा है। लॉग इन स्क्रीन से नया लिंक प्राप्त करें।',
|
||||||
resetInvalidLink: 'यह रीसेट लिंक अमान्य है या समाप्त हो चुका है। लॉग इन स्क्रीन से नया लिंक प्राप्त करें।',
|
resetInvalidLink:
|
||||||
|
'यह रीसेट लिंक अमान्य है या समाप्त हो चुका है। लॉग इन स्क्रीन से नया लिंक प्राप्त करें।',
|
||||||
goToLogin: 'लॉग इन पर जाएँ',
|
goToLogin: 'लॉग इन पर जाएँ',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -651,8 +651,7 @@ const hu: Translations = {
|
||||||
newPassword: 'Új jelszó',
|
newPassword: 'Új jelszó',
|
||||||
newPasswordPlaceholder: 'Legalább 8 karakter',
|
newPasswordPlaceholder: 'Legalább 8 karakter',
|
||||||
updatePassword: 'Jelszó frissítése',
|
updatePassword: 'Jelszó frissítése',
|
||||||
resetSuccessBody:
|
resetSuccessBody: 'A jelszavad megváltozott. Mostantól bejelentkezhetsz az új jelszavaddal.',
|
||||||
'A jelszavad megváltozott. Mostantól bejelentkezhetsz az új jelszavaddal.',
|
|
||||||
resetMissingToken:
|
resetMissingToken:
|
||||||
'Ez a jelszó-visszaállító link hiányos. Kérj egy újat a bejelentkezési képernyőről.',
|
'Ez a jelszó-visszaállító link hiányos. Kérj egy újat a bejelentkezési képernyőről.',
|
||||||
resetInvalidLink:
|
resetInvalidLink:
|
||||||
|
|
|
||||||
|
|
@ -673,14 +673,18 @@ fn extract_price_history(df: &DataFrame) -> Result<Vec<Vec<PriceHistoryPoint>>>
|
||||||
let dates_s = structs
|
let dates_s = structs
|
||||||
.field_by_name("date")
|
.field_by_name("date")
|
||||||
.context("Missing 'date' field in price_history struct")?;
|
.context("Missing 'date' field in price_history struct")?;
|
||||||
let date_ca = dates_s.str().context("price_history.date is not a string")?;
|
let date_ca = dates_s
|
||||||
|
.str()
|
||||||
|
.context("price_history.date is not a string")?;
|
||||||
let prices_s = structs
|
let prices_s = structs
|
||||||
.field_by_name("price")
|
.field_by_name("price")
|
||||||
.context("Missing 'price' field in price_history struct")?;
|
.context("Missing 'price' field in price_history struct")?;
|
||||||
let prices_i64 = prices_s
|
let prices_i64 = prices_s
|
||||||
.cast(&DataType::Int64)
|
.cast(&DataType::Int64)
|
||||||
.context("price_history.price is not castable to Int64")?;
|
.context("price_history.price is not castable to Int64")?;
|
||||||
let price_ca = prices_i64.i64().context("price_history.price is not Int64")?;
|
let price_ca = prices_i64
|
||||||
|
.i64()
|
||||||
|
.context("price_history.price is not Int64")?;
|
||||||
let reasons_s = structs
|
let reasons_s = structs
|
||||||
.field_by_name("reason")
|
.field_by_name("reason")
|
||||||
.context("Missing 'reason' field in price_history struct")?;
|
.context("Missing 'reason' field in price_history struct")?;
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,6 @@ async fn static_cache_headers(
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn security_headers(
|
async fn security_headers(
|
||||||
request: axum::extract::Request,
|
request: axum::extract::Request,
|
||||||
next: middleware::Next,
|
next: middleware::Next,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue