Integrada la búsqueda de bibliografía ahora también con Open Library y permitiendo obtener resultados de un idioma

- Se actualizó el contrato de búsqueda para enviar términos y parámetros por endpoint (Google y Open Library), y se consumió una respuesta unificada con origen por resultado.
- Se reemplazó el control de cantidad por un selector de idioma, y se mapearon los códigos a ISO 639-1 (Google) e ISO 639-2 (Open Library).
- Se forzó la obtención de resultados más recientes (orderBy="newest" y sort="new") y se ordenaron los resultados en frontend por año de publicación descendente, sin importar el endpoint.
- Se etiquetó cada sugerencia con un badge de origen (Google u Open Library).
This commit is contained in:
2026-03-09 17:03:47 -06:00
parent 203e8608a2
commit ab2510ba1c
4 changed files with 777 additions and 518 deletions

View File

@@ -42,8 +42,19 @@ const EDGE = {
export type BuscarBibliografiaRequest = { export type BuscarBibliografiaRequest = {
searchTerms: { searchTerms: {
q: string q: string
maxResults: number }
google: {
orderBy?: 'newest' | 'relevance' orderBy?: 'newest' | 'relevance'
langRestrict?: string
startIndex?: number
[k: string]: unknown
}
openLibrary: {
language?: string
page?: number
sort?: string
[k: string]: unknown [k: string]: unknown
} }
} }
@@ -82,20 +93,22 @@ export type GoogleBooksVolume = {
[k: string]: unknown [k: string]: unknown
} }
export type OpenLibraryDoc = Record<string, unknown>
export type EndpointResult =
| { endpoint: 'google'; item: GoogleBooksVolume }
| { endpoint: 'open_library'; item: OpenLibraryDoc }
export async function buscar_bibliografia( export async function buscar_bibliografia(
input: BuscarBibliografiaRequest, input: BuscarBibliografiaRequest,
): Promise<Array<GoogleBooksVolume>> { ): Promise<Array<EndpointResult>> {
const q = input.searchTerms.q const q = input.searchTerms.q
const maxResults = input.searchTerms.maxResults
if (typeof q !== 'string' || q.trim().length < 1) { if (typeof q !== 'string' || q.trim().length < 1) {
throw new Error('q es requerido') throw new Error('q es requerido')
} }
if (!Number.isInteger(maxResults) || maxResults < 0 || maxResults > 40) {
throw new Error('maxResults debe ser entero entre 0 y 40')
}
return await invokeEdge<Array<GoogleBooksVolume>>( return await invokeEdge<Array<EndpointResult>>(
EDGE.buscar_bibliografia, EDGE.buscar_bibliografia,
input, input,
{ headers: { 'Content-Type': 'application/json' } }, { headers: { 'Content-Type': 'application/json' } },

View File

@@ -4,10 +4,15 @@ import { Globe, Loader2, Plus, RefreshCw, X } from 'lucide-react'
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
import type { BuscarBibliografiaRequest } from '@/data' import type { BuscarBibliografiaRequest } from '@/data'
import type { GoogleBooksVolume } from '@/data/api/subjects.api' import type {
EndpointResult,
GoogleBooksVolume,
OpenLibraryDoc,
} from '@/data/api/subjects.api'
import type { TablesInsert } from '@/types/supabase' import type { TablesInsert } from '@/types/supabase'
import { defineStepper } from '@/components/stepper' import { defineStepper } from '@/components/stepper'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { import {
Card, Card,
@@ -41,6 +46,54 @@ import { cn } from '@/lib/utils'
type MetodoBibliografia = 'MANUAL' | 'IA' | null type MetodoBibliografia = 'MANUAL' | 'IA' | null
export type FormatoCita = 'apa' | 'ieee' | 'vancouver' | 'chicago' export type FormatoCita = 'apa' | 'ieee' | 'vancouver' | 'chicago'
type IdiomaBibliografia =
| 'ALL'
| 'ES'
| 'EN'
| 'DE'
| 'ZH'
| 'FR'
| 'IT'
| 'JA'
| 'RU'
const IDIOMA_LABEL: Record<IdiomaBibliografia, string> = {
ALL: 'Todos',
ES: 'Español',
EN: 'Inglés',
DE: 'Alemán',
ZH: 'Chino',
FR: 'Francés',
IT: 'Italiano',
JA: 'Japonés',
RU: 'Ruso',
}
const IDIOMA_TO_GOOGLE: Record<IdiomaBibliografia, string | undefined> = {
ALL: undefined,
ES: 'es',
EN: 'en',
DE: 'de',
ZH: 'zh',
FR: 'fr',
IT: 'it',
JA: 'ja',
RU: 'ru',
}
// ISO 639-2 (bibliographic codes) commonly used by Open Library.
const IDIOMA_TO_OPEN_LIBRARY: Record<IdiomaBibliografia, string | undefined> = {
ALL: undefined,
ES: 'spa',
EN: 'eng',
DE: 'ger',
ZH: 'chi',
FR: 'fre',
IT: 'ita',
JA: 'jpn',
RU: 'rus',
}
type CSLAuthor = { type CSLAuthor = {
family: string family: string
given: string given: string
@@ -65,7 +118,7 @@ type BibliografiaTipoFuente = NonNullable<
type BibliografiaRef = { type BibliografiaRef = {
id: string id: string
source: BibliografiaTipoFuente source: BibliografiaTipoFuente
raw?: GoogleBooksVolume raw?: GoogleBooksVolume | OpenLibraryDoc
title: string title: string
authors: Array<string> authors: Array<string>
publisher?: string publisher?: string
@@ -79,12 +132,13 @@ type WizardState = {
metodo: MetodoBibliografia metodo: MetodoBibliografia
ia: { ia: {
q: string q: string
cantidadDeSugerencias: number | null idioma: IdiomaBibliografia
showConservacionTooltip: boolean showConservacionTooltip: boolean
sugerencias: Array<{ sugerencias: Array<{
id: string id: string
selected: boolean selected: boolean
volume: GoogleBooksVolume endpoint: EndpointResult['endpoint']
item: GoogleBooksVolume | OpenLibraryDoc
}> }>
isLoading: boolean isLoading: boolean
errorMessage: string | null errorMessage: string | null
@@ -107,6 +161,13 @@ type WizardState = {
errorMessage: string | null errorMessage: string | null
} }
type IASugerencia = WizardState['ia']['sugerencias'][number]
function iaSugerenciaToEndpointResult(s: IASugerencia): EndpointResult {
return s.endpoint === 'google'
? { endpoint: 'google', item: s.item as GoogleBooksVolume }
: { endpoint: 'open_library', item: s.item as OpenLibraryDoc }
}
const Wizard = defineStepper( const Wizard = defineStepper(
{ id: 'metodo', title: 'Método', description: 'Manual o Buscar en línea' }, { id: 'metodo', title: 'Método', description: 'Manual o Buscar en línea' },
{ {
@@ -140,18 +201,67 @@ function tryParseYear(publishedDate?: string): number | undefined {
return Number.isFinite(year) ? year : undefined return Number.isFinite(year) ? year : undefined
} }
function volumeToRef(volume: GoogleBooksVolume): BibliografiaRef { function randomUUID(): string {
try {
const c = (globalThis as any).crypto
if (c && typeof c.randomUUID === 'function') return c.randomUUID()
} catch {
// ignore
}
return `${Date.now()}-${Math.random().toString(16).slice(2)}`
}
function tryParseYearFromOpenLibrary(doc: OpenLibraryDoc): number | undefined {
const y1 = doc['first_publish_year']
if (typeof y1 === 'number' && Number.isFinite(y1)) return y1
const years = doc['publish_year']
if (Array.isArray(years)) {
const numeric = years
.map((x) => (typeof x === 'number' ? x : Number(x)))
.filter((n) => Number.isFinite(n))
if (numeric.length > 0) return Math.max(...numeric)
}
const published = doc['publish_date']
if (typeof published === 'string') return tryParseYear(published)
return undefined
}
function getEndpointResultId(result: EndpointResult): string {
if (result.endpoint === 'google') {
return `google:${result.item.id}`
}
const doc = result.item
const key = doc['key']
if (typeof key === 'string' && key.trim()) return `open_library:${key}`
const cover = doc['cover_edition_key']
if (typeof cover === 'string' && cover.trim()) return `open_library:${cover}`
const editionKey = doc['edition_key']
if (Array.isArray(editionKey) && typeof editionKey[0] === 'string') {
return `open_library:${editionKey[0]}`
}
return `open_library:${randomUUID()}`
}
function endpointResultToRef(result: EndpointResult): BibliografiaRef {
if (result.endpoint === 'google') {
const volume = result.item
const info = volume.volumeInfo ?? {} const info = volume.volumeInfo ?? {}
const title = (info.title ?? '').trim() || 'Sin título' const title = (info.title ?? '').trim() || 'Sin título'
const authors = Array.isArray(info.authors) ? info.authors : [] const authors = Array.isArray(info.authors) ? info.authors : []
const publisher = info.publisher const publisher = typeof info.publisher === 'string' ? info.publisher : undefined
const year = tryParseYear(info.publishedDate) const year = tryParseYear(info.publishedDate)
const isbn = const isbn =
info.industryIdentifiers?.find((x) => x.identifier)?.identifier ?? undefined info.industryIdentifiers?.find((x) => x?.identifier)?.identifier ?? undefined
return { return {
id: volume.id, id: getEndpointResultId(result),
source: 'MANUAL', source: 'BIBLIOTECA',
raw: volume, raw: volume,
title, title,
authors, authors,
@@ -162,6 +272,54 @@ function volumeToRef(volume: GoogleBooksVolume): BibliografiaRef {
} }
} }
const doc = result.item
const title = (typeof doc['title'] === 'string' ? doc['title'] : '').trim() ||
'Sin título'
const authors = Array.isArray(doc['author_name'])
? (doc['author_name'] as Array<unknown>).filter((a): a is string => typeof a === 'string')
: []
const publisher = Array.isArray(doc['publisher'])
? (doc['publisher'] as Array<unknown>).find(
(p): p is string => typeof p === 'string',
)
: typeof doc['publisher'] === 'string'
? doc['publisher']
: undefined
const year = tryParseYearFromOpenLibrary(doc)
const isbn = Array.isArray(doc['isbn'])
? (doc['isbn'] as Array<unknown>).find((x): x is string => typeof x === 'string')
: undefined
return {
id: getEndpointResultId(result),
source: 'BIBLIOTECA',
raw: doc,
title,
authors,
publisher,
year,
isbn,
tipo: 'BASICA',
}
}
function getResultYear(result: EndpointResult): number | undefined {
if (result.endpoint === 'google') {
const info = result.item.volumeInfo ?? {}
return tryParseYear(info.publishedDate)
}
return tryParseYearFromOpenLibrary(result.item)
}
function sortResultsByMostRecent(a: EndpointResult, b: EndpointResult) {
const ya = getResultYear(a)
const yb = getResultYear(b)
if (typeof ya === 'number' && typeof yb === 'number') return yb - ya
if (typeof ya === 'number') return -1
if (typeof yb === 'number') return 1
return 0
}
function AutoSizeTextarea({ function AutoSizeTextarea({
value, value,
disabled, disabled,
@@ -294,7 +452,7 @@ export function NuevaBibliografiaModalContainer({
metodo: null, metodo: null,
ia: { ia: {
q: '', q: '',
cantidadDeSugerencias: 10, idioma: 'ALL',
showConservacionTooltip: false, showConservacionTooltip: false,
sugerencias: [], sugerencias: [],
isLoading: false, isLoading: false,
@@ -342,7 +500,7 @@ export function NuevaBibliografiaModalContainer({
wizard.metodo === 'IA' wizard.metodo === 'IA'
? wizard.ia.sugerencias ? wizard.ia.sugerencias
.filter((s) => s.selected) .filter((s) => s.selected)
.map((s) => volumeToRef(s.volume)) .map((s) => endpointResultToRef(iaSugerenciaToEndpointResult(s)))
: wizard.manual.refs : wizard.manual.refs
// Mantener `wizard.refs` como snapshot para pasos 3/4. // Mantener `wizard.refs` como snapshot para pasos 3/4.
@@ -378,25 +536,8 @@ export function NuevaBibliografiaModalContainer({
async function handleBuscarSugerencias() { async function handleBuscarSugerencias() {
const hadNoSugerenciasBefore = wizard.ia.sugerencias.length === 0 const hadNoSugerenciasBefore = wizard.ia.sugerencias.length === 0
const cantidad = wizard.ia.cantidadDeSugerencias const q = wizard.ia.q.trim()
if ( if (!q) return
!Number.isFinite(cantidad ?? Number.NaN) ||
(cantidad as number) < 1 ||
(cantidad as number) > 40
) {
setWizard((w) => ({
...w,
ia: {
...w.ia,
errorMessage:
'La cantidad de sugerencias debe ser un entero entre 1 y 40 (o vacío).',
},
errorMessage: null,
}))
return
}
const selected = wizard.ia.sugerencias.filter((s) => s.selected)
setWizard((w) => ({ setWizard((w) => ({
...w, ...w,
@@ -412,30 +553,58 @@ export function NuevaBibliografiaModalContainer({
})) }))
try { try {
const selectedCount = selected.length const idioma = wizard.ia.idioma
const googleLangRestrict = IDIOMA_TO_GOOGLE[idioma]
const openLibraryLanguage = IDIOMA_TO_OPEN_LIBRARY[idioma]
const google: BuscarBibliografiaRequest['google'] = {
orderBy: 'newest',
startIndex: 0,
}
if (googleLangRestrict) google.langRestrict = googleLangRestrict
const openLibrary: BuscarBibliografiaRequest['openLibrary'] = {
sort: 'new',
page: 1,
}
if (openLibraryLanguage) openLibrary.language = openLibraryLanguage
const req: BuscarBibliografiaRequest = { const req: BuscarBibliografiaRequest = {
searchTerms: { searchTerms: { q },
q: wizard.ia.q, google,
maxResults: (cantidad as number) + selectedCount, openLibrary,
// orderBy: ignorado por ahora
},
} }
const items = await buscar_bibliografia(req) const items = (await buscar_bibliografia(req))
.slice()
.sort(sortResultsByMostRecent)
setWizard((w) => { setWizard((w) => {
const existingById = new Map(w.ia.sugerencias.map((s) => [s.id, s])) const existingById = new Map(w.ia.sugerencias.map((s) => [s.id, s]))
const newOnes = items const newOnes = items
.map((r) => ({
id: getEndpointResultId(r),
selected: false,
endpoint: r.endpoint,
item: r.item,
}))
.filter((it) => !existingById.has(it.id)) .filter((it) => !existingById.has(it.id))
.slice(0, cantidad as number)
.map((it) => ({ id: it.id, selected: false, volume: it })) const merged = [...w.ia.sugerencias, ...newOnes].slice()
merged.sort(
(a, b) =>
sortResultsByMostRecent(
iaSugerenciaToEndpointResult(a),
iaSugerenciaToEndpointResult(b),
) || a.id.localeCompare(b.id),
)
return { return {
...w, ...w,
ia: { ia: {
...w.ia, ...w.ia,
sugerencias: [...w.ia.sugerencias, ...newOnes], sugerencias: merged,
showConservacionTooltip: showConservacionTooltip:
hadNoSugerenciasBefore && newOnes.length > 0, hadNoSugerenciasBefore && newOnes.length > 0,
isLoading: false, isLoading: false,
@@ -508,7 +677,9 @@ export function NuevaBibliografiaModalContainer({
const result = engine.makeBibliography() const result = engine.makeBibliography()
// result[0] contiene los metadatos, result[1] las citas formateadas // result[0] contiene los metadatos, result[1] las citas formateadas
const meta = result?.[0] as { entry_ids?: string[][] } | undefined const meta = result?.[0] as
| { entry_ids?: Array<Array<string>> }
| undefined
const entries = (result?.[1] ?? []) as Array<string> const entries = (result?.[1] ?? []) as Array<string>
const citations: Record<string, string> = {} const citations: Record<string, string> = {}
@@ -697,7 +868,7 @@ export function NuevaBibliografiaModalContainer({
{wizard.metodo === 'IA' ? ( {wizard.metodo === 'IA' ? (
<SugerenciasStep <SugerenciasStep
q={wizard.ia.q} q={wizard.ia.q}
cantidad={wizard.ia.cantidadDeSugerencias} idioma={wizard.ia.idioma}
isLoading={wizard.ia.isLoading} isLoading={wizard.ia.isLoading}
errorMessage={wizard.ia.errorMessage} errorMessage={wizard.ia.errorMessage}
sugerencias={wizard.ia.sugerencias} sugerencias={wizard.ia.sugerencias}
@@ -879,7 +1050,7 @@ function MetodoStep({
function SugerenciasStep({ function SugerenciasStep({
q, q,
cantidad, idioma,
isLoading, isLoading,
errorMessage, errorMessage,
sugerencias, sugerencias,
@@ -889,20 +1060,21 @@ function SugerenciasStep({
onGenerate, onGenerate,
}: { }: {
q: string q: string
cantidad: number | null idioma: IdiomaBibliografia
isLoading: boolean isLoading: boolean
errorMessage: string | null errorMessage: string | null
sugerencias: Array<{ sugerencias: Array<{
id: string id: string
selected: boolean selected: boolean
volume: GoogleBooksVolume endpoint: EndpointResult['endpoint']
item: GoogleBooksVolume | OpenLibraryDoc
}> }>
showConservacionTooltip: boolean showConservacionTooltip: boolean
onDismissConservacionTooltip: () => void onDismissConservacionTooltip: () => void
onChange: ( onChange: (
patch: Partial<{ patch: Partial<{
q: string q: string
cantidadDeSugerencias: number | null idioma: IdiomaBibliografia
sugerencias: any sugerencias: any
}>, }>,
) => void ) => void
@@ -910,12 +1082,6 @@ function SugerenciasStep({
}) { }) {
const selectedCount = sugerencias.filter((s) => s.selected).length const selectedCount = sugerencias.filter((s) => s.selected).length
const cantidadIsValid =
typeof cantidad === 'number' &&
Number.isFinite(cantidad) &&
cantidad >= 1 &&
cantidad <= 40
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<Card> <Card>
@@ -936,41 +1102,34 @@ function SugerenciasStep({
</div> </div>
<div className="mt-3 flex w-full flex-col items-end justify-between gap-3 sm:flex-row"> <div className="mt-3 flex w-full flex-col items-end justify-between gap-3 sm:flex-row">
<div className="w-full sm:w-44"> <div className="w-full sm:w-56">
<Label className="mb-2 block">Cantidad de sugerencias</Label> <Label className="mb-2 block">Idioma</Label>
<Input <Select
type="number" value={idioma}
min={1} onValueChange={(v) =>
max={40} onChange({ idioma: v as IdiomaBibliografia })
step={1}
inputMode="numeric"
placeholder="Ej. 10"
value={cantidad ?? ''}
onKeyDown={(e) => {
if (['.', ',', '-', 'e', 'E', '+'].includes(e.key)) {
e.preventDefault()
} }
}} >
onChange={(e) => { <SelectTrigger>
const raw = e.target.value <SelectValue placeholder="Selecciona" />
if (raw === '') { </SelectTrigger>
onChange({ cantidadDeSugerencias: null }) <SelectContent>
return {(Object.keys(IDIOMA_LABEL) as Array<IdiomaBibliografia>).map(
} (k) => (
const asNumber = Number(raw) <SelectItem key={k} value={k}>
if (!Number.isFinite(asNumber)) return {IDIOMA_LABEL[k]}
const n = Math.floor(Math.abs(asNumber)) </SelectItem>
const capped = Math.min(Math.max(n >= 1 ? n : 1, 1), 40) ),
onChange({ cantidadDeSugerencias: capped }) )}
}} </SelectContent>
/> </Select>
</div> </div>
<Button <Button
type="button" type="button"
variant="outline" variant="outline"
onClick={onGenerate} onClick={onGenerate}
disabled={isLoading || q.trim().length === 0 || !cantidadIsValid} disabled={isLoading || q.trim().length === 0}
className="gap-2" className="gap-2"
> >
{isLoading ? ( {isLoading ? (
@@ -1021,12 +1180,35 @@ function SugerenciasStep({
</div> </div>
<div className="max-h-96 space-y-1 overflow-y-auto pr-1"> <div className="max-h-96 space-y-1 overflow-y-auto pr-1">
{sugerencias.map((s) => { {sugerencias.map((s) => {
const info = s.volume.volumeInfo ?? {}
const title = (info.title ?? 'Sin título').trim()
const authors = (info.authors ?? []).join(', ')
const year = tryParseYear(info.publishedDate)
const selected = s.selected const selected = s.selected
const badgeLabel = s.endpoint === 'google' ? 'Google' : 'Open Library'
const title =
s.endpoint === 'google'
? (((s.item as GoogleBooksVolume).volumeInfo?.title ??
'Sin título')).trim()
: (typeof (s.item as OpenLibraryDoc)['title'] === 'string'
? ((s.item as OpenLibraryDoc)['title'] as string)
: 'Sin título'
).trim()
const authors =
s.endpoint === 'google'
? ((s.item as GoogleBooksVolume).volumeInfo?.authors ?? []).join(', ')
: Array.isArray((s.item as OpenLibraryDoc)['author_name'])
? ((s.item as OpenLibraryDoc)['author_name'] as Array<unknown>)
.filter((a): a is string => typeof a === 'string')
.join(', ')
: ''
const year =
s.endpoint === 'google'
? tryParseYear(
(s.item as GoogleBooksVolume).volumeInfo?.publishedDate,
)
: tryParseYearFromOpenLibrary(s.item as OpenLibraryDoc)
return ( return (
<Label <Label
key={s.id} key={s.id}
@@ -1046,7 +1228,14 @@ function SugerenciasStep({
} }
/> />
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="text-sm font-medium">{title}</div> <div className="flex min-w-0 items-center gap-2">
<div className="min-w-0 truncate text-sm font-medium">
{title}
</div>
<Badge variant="secondary" className="shrink-0">
{badgeLabel}
</Badge>
</div>
<div className="text-muted-foreground text-xs"> <div className="text-muted-foreground text-xs">
{authors || '—'} {authors || '—'}
{year ? `${year}` : ''} {year ? `${year}` : ''}
@@ -1145,7 +1334,7 @@ function DatosBasicosManualStep({
onClick={() => { onClick={() => {
const year = Number.parseInt(draft.yearText.trim(), 10) const year = Number.parseInt(draft.yearText.trim(), 10)
const ref: BibliografiaRef = { const ref: BibliografiaRef = {
id: `manual-${crypto.randomUUID()}`, id: `manual-${randomUUID()}`,
source: 'MANUAL', source: 'MANUAL',
title: draft.title.trim(), title: draft.title.trim(),
authors: draft.authorsText authors: draft.authorsText

View File

@@ -31,6 +31,8 @@ import { Route as PlanesPlanIdAsignaturasAsignaturaIdDocumentoRouteImport } from
import { Route as PlanesPlanIdAsignaturasAsignaturaIdContenidoRouteImport } from './routes/planes/$planId/asignaturas/$asignaturaId/contenido' import { Route as PlanesPlanIdAsignaturasAsignaturaIdContenidoRouteImport } from './routes/planes/$planId/asignaturas/$asignaturaId/contenido'
import { Route as PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteImport } from './routes/planes/$planId/asignaturas/$asignaturaId/bibliografia' import { Route as PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteImport } from './routes/planes/$planId/asignaturas/$asignaturaId/bibliografia'
import { Route as PlanesPlanIdDetalleAsignaturasNuevaRouteImport } from './routes/planes/$planId/_detalle/asignaturas/nueva' import { Route as PlanesPlanIdDetalleAsignaturasNuevaRouteImport } from './routes/planes/$planId/_detalle/asignaturas/nueva'
import { Route as PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRouteImport } from './routes/planes/$planId/asignaturas/$asignaturaId/bibliografia/index'
import { Route as PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRouteImport } from './routes/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva'
const LoginRoute = LoginRouteImport.update({ const LoginRoute = LoginRouteImport.update({
id: '/login', id: '/login',
@@ -156,6 +158,18 @@ const PlanesPlanIdDetalleAsignaturasNuevaRoute =
path: '/nueva', path: '/nueva',
getParentRoute: () => PlanesPlanIdDetalleAsignaturasRoute, getParentRoute: () => PlanesPlanIdDetalleAsignaturasRoute,
} as any) } as any)
const PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute =
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRouteImport.update({
id: '/',
path: '/',
getParentRoute: () => PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute,
} as any)
const PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute =
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRouteImport.update({
id: '/nueva',
path: '/nueva',
getParentRoute: () => PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute,
} as any)
export interface FileRoutesByFullPath { export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
@@ -174,12 +188,14 @@ export interface FileRoutesByFullPath {
'/planes/$planId/mapa': typeof PlanesPlanIdDetalleMapaRoute '/planes/$planId/mapa': typeof PlanesPlanIdDetalleMapaRoute
'/planes/$planId/': typeof PlanesPlanIdDetalleIndexRoute '/planes/$planId/': typeof PlanesPlanIdDetalleIndexRoute
'/planes/$planId/asignaturas/nueva': typeof PlanesPlanIdDetalleAsignaturasNuevaRoute '/planes/$planId/asignaturas/nueva': typeof PlanesPlanIdDetalleAsignaturasNuevaRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute '/planes/$planId/asignaturas/$asignaturaId/bibliografia': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteWithChildren
'/planes/$planId/asignaturas/$asignaturaId/contenido': typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute '/planes/$planId/asignaturas/$asignaturaId/contenido': typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute
'/planes/$planId/asignaturas/$asignaturaId/documento': typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute '/planes/$planId/asignaturas/$asignaturaId/documento': typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute
'/planes/$planId/asignaturas/$asignaturaId/historial': typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute '/planes/$planId/asignaturas/$asignaturaId/historial': typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute
'/planes/$planId/asignaturas/$asignaturaId/iaasignatura': typeof PlanesPlanIdAsignaturasAsignaturaIdIaasignaturaRoute '/planes/$planId/asignaturas/$asignaturaId/iaasignatura': typeof PlanesPlanIdAsignaturasAsignaturaIdIaasignaturaRoute
'/planes/$planId/asignaturas/$asignaturaId/': typeof PlanesPlanIdAsignaturasAsignaturaIdIndexRoute '/planes/$planId/asignaturas/$asignaturaId/': typeof PlanesPlanIdAsignaturasAsignaturaIdIndexRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia/': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
@@ -196,12 +212,13 @@ export interface FileRoutesByTo {
'/planes/$planId/mapa': typeof PlanesPlanIdDetalleMapaRoute '/planes/$planId/mapa': typeof PlanesPlanIdDetalleMapaRoute
'/planes/$planId': typeof PlanesPlanIdDetalleIndexRoute '/planes/$planId': typeof PlanesPlanIdDetalleIndexRoute
'/planes/$planId/asignaturas/nueva': typeof PlanesPlanIdDetalleAsignaturasNuevaRoute '/planes/$planId/asignaturas/nueva': typeof PlanesPlanIdDetalleAsignaturasNuevaRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute
'/planes/$planId/asignaturas/$asignaturaId/contenido': typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute '/planes/$planId/asignaturas/$asignaturaId/contenido': typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute
'/planes/$planId/asignaturas/$asignaturaId/documento': typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute '/planes/$planId/asignaturas/$asignaturaId/documento': typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute
'/planes/$planId/asignaturas/$asignaturaId/historial': typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute '/planes/$planId/asignaturas/$asignaturaId/historial': typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute
'/planes/$planId/asignaturas/$asignaturaId/iaasignatura': typeof PlanesPlanIdAsignaturasAsignaturaIdIaasignaturaRoute '/planes/$planId/asignaturas/$asignaturaId/iaasignatura': typeof PlanesPlanIdAsignaturasAsignaturaIdIaasignaturaRoute
'/planes/$planId/asignaturas/$asignaturaId': typeof PlanesPlanIdAsignaturasAsignaturaIdIndexRoute '/planes/$planId/asignaturas/$asignaturaId': typeof PlanesPlanIdAsignaturasAsignaturaIdIndexRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
__root__: typeof rootRouteImport __root__: typeof rootRouteImport
@@ -221,12 +238,14 @@ export interface FileRoutesById {
'/planes/$planId/_detalle/mapa': typeof PlanesPlanIdDetalleMapaRoute '/planes/$planId/_detalle/mapa': typeof PlanesPlanIdDetalleMapaRoute
'/planes/$planId/_detalle/': typeof PlanesPlanIdDetalleIndexRoute '/planes/$planId/_detalle/': typeof PlanesPlanIdDetalleIndexRoute
'/planes/$planId/_detalle/asignaturas/nueva': typeof PlanesPlanIdDetalleAsignaturasNuevaRoute '/planes/$planId/_detalle/asignaturas/nueva': typeof PlanesPlanIdDetalleAsignaturasNuevaRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute '/planes/$planId/asignaturas/$asignaturaId/bibliografia': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteWithChildren
'/planes/$planId/asignaturas/$asignaturaId/contenido': typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute '/planes/$planId/asignaturas/$asignaturaId/contenido': typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute
'/planes/$planId/asignaturas/$asignaturaId/documento': typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute '/planes/$planId/asignaturas/$asignaturaId/documento': typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute
'/planes/$planId/asignaturas/$asignaturaId/historial': typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute '/planes/$planId/asignaturas/$asignaturaId/historial': typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute
'/planes/$planId/asignaturas/$asignaturaId/iaasignatura': typeof PlanesPlanIdAsignaturasAsignaturaIdIaasignaturaRoute '/planes/$planId/asignaturas/$asignaturaId/iaasignatura': typeof PlanesPlanIdAsignaturasAsignaturaIdIaasignaturaRoute
'/planes/$planId/asignaturas/$asignaturaId/': typeof PlanesPlanIdAsignaturasAsignaturaIdIndexRoute '/planes/$planId/asignaturas/$asignaturaId/': typeof PlanesPlanIdAsignaturasAsignaturaIdIndexRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute
'/planes/$planId/asignaturas/$asignaturaId/bibliografia/': typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
@@ -253,6 +272,8 @@ export interface FileRouteTypes {
| '/planes/$planId/asignaturas/$asignaturaId/historial' | '/planes/$planId/asignaturas/$asignaturaId/historial'
| '/planes/$planId/asignaturas/$asignaturaId/iaasignatura' | '/planes/$planId/asignaturas/$asignaturaId/iaasignatura'
| '/planes/$planId/asignaturas/$asignaturaId/' | '/planes/$planId/asignaturas/$asignaturaId/'
| '/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva'
| '/planes/$planId/asignaturas/$asignaturaId/bibliografia/'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: to:
| '/' | '/'
@@ -269,12 +290,13 @@ export interface FileRouteTypes {
| '/planes/$planId/mapa' | '/planes/$planId/mapa'
| '/planes/$planId' | '/planes/$planId'
| '/planes/$planId/asignaturas/nueva' | '/planes/$planId/asignaturas/nueva'
| '/planes/$planId/asignaturas/$asignaturaId/bibliografia'
| '/planes/$planId/asignaturas/$asignaturaId/contenido' | '/planes/$planId/asignaturas/$asignaturaId/contenido'
| '/planes/$planId/asignaturas/$asignaturaId/documento' | '/planes/$planId/asignaturas/$asignaturaId/documento'
| '/planes/$planId/asignaturas/$asignaturaId/historial' | '/planes/$planId/asignaturas/$asignaturaId/historial'
| '/planes/$planId/asignaturas/$asignaturaId/iaasignatura' | '/planes/$planId/asignaturas/$asignaturaId/iaasignatura'
| '/planes/$planId/asignaturas/$asignaturaId' | '/planes/$planId/asignaturas/$asignaturaId'
| '/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva'
| '/planes/$planId/asignaturas/$asignaturaId/bibliografia'
id: id:
| '__root__' | '__root__'
| '/' | '/'
@@ -299,6 +321,8 @@ export interface FileRouteTypes {
| '/planes/$planId/asignaturas/$asignaturaId/historial' | '/planes/$planId/asignaturas/$asignaturaId/historial'
| '/planes/$planId/asignaturas/$asignaturaId/iaasignatura' | '/planes/$planId/asignaturas/$asignaturaId/iaasignatura'
| '/planes/$planId/asignaturas/$asignaturaId/' | '/planes/$planId/asignaturas/$asignaturaId/'
| '/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva'
| '/planes/$planId/asignaturas/$asignaturaId/bibliografia/'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
export interface RootRouteChildren { export interface RootRouteChildren {
@@ -467,6 +491,20 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof PlanesPlanIdDetalleAsignaturasNuevaRouteImport preLoaderRoute: typeof PlanesPlanIdDetalleAsignaturasNuevaRouteImport
parentRoute: typeof PlanesPlanIdDetalleAsignaturasRoute parentRoute: typeof PlanesPlanIdDetalleAsignaturasRoute
} }
'/planes/$planId/asignaturas/$asignaturaId/bibliografia/': {
id: '/planes/$planId/asignaturas/$asignaturaId/bibliografia/'
path: '/'
fullPath: '/planes/$planId/asignaturas/$asignaturaId/bibliografia/'
preLoaderRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRouteImport
parentRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute
}
'/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva': {
id: '/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva'
path: '/nueva'
fullPath: '/planes/$planId/asignaturas/$asignaturaId/bibliografia/nueva'
preLoaderRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRouteImport
parentRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute
}
} }
} }
@@ -521,8 +559,26 @@ const PlanesPlanIdDetalleRouteChildren: PlanesPlanIdDetalleRouteChildren = {
const PlanesPlanIdDetalleRouteWithChildren = const PlanesPlanIdDetalleRouteWithChildren =
PlanesPlanIdDetalleRoute._addFileChildren(PlanesPlanIdDetalleRouteChildren) PlanesPlanIdDetalleRoute._addFileChildren(PlanesPlanIdDetalleRouteChildren)
interface PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteChildren {
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute
}
const PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteChildren: PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteChildren =
{
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute:
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaNuevaRoute,
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute:
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaIndexRoute,
}
const PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteWithChildren =
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute._addFileChildren(
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteChildren,
)
interface PlanesPlanIdAsignaturasAsignaturaIdRouteRouteChildren { interface PlanesPlanIdAsignaturasAsignaturaIdRouteRouteChildren {
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteWithChildren
PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute
PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute
PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute: typeof PlanesPlanIdAsignaturasAsignaturaIdHistorialRoute
@@ -533,7 +589,7 @@ interface PlanesPlanIdAsignaturasAsignaturaIdRouteRouteChildren {
const PlanesPlanIdAsignaturasAsignaturaIdRouteRouteChildren: PlanesPlanIdAsignaturasAsignaturaIdRouteRouteChildren = const PlanesPlanIdAsignaturasAsignaturaIdRouteRouteChildren: PlanesPlanIdAsignaturasAsignaturaIdRouteRouteChildren =
{ {
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute: PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute:
PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRoute, PlanesPlanIdAsignaturasAsignaturaIdBibliografiaRouteWithChildren,
PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute: PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute:
PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute, PlanesPlanIdAsignaturasAsignaturaIdContenidoRoute,
PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute: PlanesPlanIdAsignaturasAsignaturaIdDocumentoRoute:

File diff suppressed because it is too large Load Diff