Claude commited on
Commit
ed62931
·
unverified ·
1 Parent(s): 3aa2ed4

fix: page IDs with trailing dots, Reader profile handling, Editor 404 UX

Browse files

Three bugs reported by user fixed:

1. Page IDs ending with a dot (e.g., "beatest-plat_sup."): _sanitize_label
now strips leading/trailing dots from canvas labels before generating
page IDs. IIIF manifests from Gallica can have labels like "plat sup."
which produced invalid IDs breaking URL routing and file paths.

2. Reader shows no image when profile query param is missing: fetchProfile
is now optional — if profileId is empty or the fetch fails, the Reader
loads pages anyway without layer filtering. Previously, the entire
Reader showed an error if the profile couldn't be loaded.

3. Editor shows raw "HTTP 404" for unanalyzed pages: now shows a
user-friendly message "Cette page n'a pas encore ete analysee par l'IA.
Lancez le pipeline depuis Administration."

https://claude.ai/code/session_01UB4he7RdRPHLvNjky4X8Sw

backend/app/api/v1/ingest.py CHANGED
@@ -40,8 +40,13 @@ _ALLOWED_MIME_PREFIXES = ("image/",)
40
 
41
 
42
  def _sanitize_label(label: str) -> str:
43
- """Nettoie un folio_label : garde uniquement alphanum, -, _, ."""
 
 
 
 
44
  clean = Path(label).name # retire tout chemin
 
45
  if not _SAFE_LABEL_RE.match(clean) or not clean:
46
  clean = re.sub(r"[^\w\-\.]", "_", clean) or "page"
47
  return clean
 
40
 
41
 
42
  def _sanitize_label(label: str) -> str:
43
+ """Nettoie un folio_label : garde uniquement alphanum, -, _, .
44
+
45
+ Les points en début/fin sont supprimés pour éviter des IDs de page
46
+ se terminant par un point (problèmes de routing et de chemins fichier).
47
+ """
48
  clean = Path(label).name # retire tout chemin
49
+ clean = clean.strip(".") # supprimer les points en début/fin
50
  if not _SAFE_LABEL_RE.match(clean) or not clean:
51
  clean = re.sub(r"[^\w\-\.]", "_", clean) or "page"
52
  return clean
frontend/src/pages/Editor.tsx CHANGED
@@ -67,7 +67,12 @@ export default function Editor() {
67
  const ext = m.extensions as { region_validations?: Record<string, string> } | undefined
68
  setRegionValidations(ext?.region_validations ?? {})
69
  } catch (e: unknown) {
70
- setError((e as Error).message)
 
 
 
 
 
71
  } finally {
72
  setLoading(false)
73
  }
 
67
  const ext = m.extensions as { region_validations?: Record<string, string> } | undefined
68
  setRegionValidations(ext?.region_validations ?? {})
69
  } catch (e: unknown) {
70
+ const msg = (e as Error).message ?? ''
71
+ if (msg.includes('404')) {
72
+ setError('Cette page n\'a pas encore ete analysee par l\'IA. Lancez le pipeline depuis Administration.')
73
+ } else {
74
+ setError(msg)
75
+ }
76
  } finally {
77
  setLoading(false)
78
  }
frontend/src/pages/Reader.tsx CHANGED
@@ -34,12 +34,19 @@ export default function Reader() {
34
  const [error, setError] = useState<string | null>(null)
35
 
36
  useEffect(() => {
37
- Promise.all([fetchPages(manuscriptId), fetchProfile(profileId)])
 
 
 
 
 
38
  .then(([pgs, prof]) => {
39
  const sorted = [...pgs].sort((a, b) => a.sequence - b.sequence)
40
  setPages(sorted)
41
- setProfile(prof)
42
- setVisibleLayers(new Set(prof.active_layers))
 
 
43
  })
44
  .catch((e: Error) => setError(e.message))
45
  .finally(() => setLoading(false))
 
34
  const [error, setError] = useState<string | null>(null)
35
 
36
  useEffect(() => {
37
+ const loadPages = fetchPages(manuscriptId)
38
+ const loadProfile = profileId
39
+ ? fetchProfile(profileId).catch(() => null)
40
+ : Promise.resolve(null)
41
+
42
+ Promise.all([loadPages, loadProfile])
43
  .then(([pgs, prof]) => {
44
  const sorted = [...pgs].sort((a, b) => a.sequence - b.sequence)
45
  setPages(sorted)
46
+ if (prof) {
47
+ setProfile(prof)
48
+ setVisibleLayers(new Set(prof.active_layers))
49
+ }
50
  })
51
  .catch((e: Error) => setError(e.message))
52
  .finally(() => setLoading(false))