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:
@@ -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' } },
|
||||||
|
|||||||
@@ -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,19 +201,99 @@ 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 {
|
||||||
const info = volume.volumeInfo ?? {}
|
try {
|
||||||
const title = (info.title ?? '').trim() || 'Sin título'
|
const c = (globalThis as any).crypto
|
||||||
const authors = Array.isArray(info.authors) ? info.authors : []
|
if (c && typeof c.randomUUID === 'function') return c.randomUUID()
|
||||||
const publisher = info.publisher
|
} catch {
|
||||||
const year = tryParseYear(info.publishedDate)
|
// ignore
|
||||||
const isbn =
|
}
|
||||||
info.industryIdentifiers?.find((x) => x.identifier)?.identifier ?? undefined
|
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 title = (info.title ?? '').trim() || 'Sin título'
|
||||||
|
const authors = Array.isArray(info.authors) ? info.authors : []
|
||||||
|
const publisher = typeof info.publisher === 'string' ? info.publisher : undefined
|
||||||
|
const year = tryParseYear(info.publishedDate)
|
||||||
|
const isbn =
|
||||||
|
info.industryIdentifiers?.find((x) => x?.identifier)?.identifier ?? undefined
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: getEndpointResultId(result),
|
||||||
|
source: 'BIBLIOTECA',
|
||||||
|
raw: volume,
|
||||||
|
title,
|
||||||
|
authors,
|
||||||
|
publisher,
|
||||||
|
year,
|
||||||
|
isbn,
|
||||||
|
tipo: 'BASICA',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
return {
|
||||||
id: volume.id,
|
id: getEndpointResultId(result),
|
||||||
source: 'MANUAL',
|
source: 'BIBLIOTECA',
|
||||||
raw: volume,
|
raw: doc,
|
||||||
title,
|
title,
|
||||||
authors,
|
authors,
|
||||||
publisher,
|
publisher,
|
||||||
@@ -162,6 +303,23 @@ function volumeToRef(volume: GoogleBooksVolume): BibliografiaRef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
@@ -506,20 +675,22 @@ export function NuevaBibliografiaModalContainer({
|
|||||||
const engine = new CSL.Engine(sys as any, xmlStyle)
|
const engine = new CSL.Engine(sys as any, xmlStyle)
|
||||||
engine.updateItems(Object.keys(cslItems))
|
engine.updateItems(Object.keys(cslItems))
|
||||||
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> = {}
|
||||||
|
|
||||||
// meta.entry_ids es un arreglo de arreglos: [["id-2"], ["id-1"], ...]
|
// meta.entry_ids es un arreglo de arreglos: [["id-2"], ["id-1"], ...]
|
||||||
const sortedIds = meta?.entry_ids ?? []
|
const sortedIds = meta?.entry_ids ?? []
|
||||||
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
for (let i = 0; i < entries.length; i++) {
|
||||||
const id = sortedIds[i]?.[0] // Sacamos el ID real de esta posición
|
const id = sortedIds[i]?.[0] // Sacamos el ID real de esta posición
|
||||||
if (!id) continue
|
if (!id) continue
|
||||||
|
|
||||||
const cita = citeprocHtmlToPlainText(entries[i] ?? '')
|
const cita = citeprocHtmlToPlainText(entries[i] ?? '')
|
||||||
citations[id] = cita
|
citations[id] = cita
|
||||||
}
|
}
|
||||||
@@ -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"
|
<SelectTrigger>
|
||||||
value={cantidad ?? ''}
|
<SelectValue placeholder="Selecciona" />
|
||||||
onKeyDown={(e) => {
|
</SelectTrigger>
|
||||||
if (['.', ',', '-', 'e', 'E', '+'].includes(e.key)) {
|
<SelectContent>
|
||||||
e.preventDefault()
|
{(Object.keys(IDIOMA_LABEL) as Array<IdiomaBibliografia>).map(
|
||||||
}
|
(k) => (
|
||||||
}}
|
<SelectItem key={k} value={k}>
|
||||||
onChange={(e) => {
|
{IDIOMA_LABEL[k]}
|
||||||
const raw = e.target.value
|
</SelectItem>
|
||||||
if (raw === '') {
|
),
|
||||||
onChange({ cantidadDeSugerencias: null })
|
)}
|
||||||
return
|
</SelectContent>
|
||||||
}
|
</Select>
|
||||||
const asNumber = Number(raw)
|
|
||||||
if (!Number.isFinite(asNumber)) return
|
|
||||||
const n = Math.floor(Math.abs(asNumber))
|
|
||||||
const capped = Math.min(Math.max(n >= 1 ? n : 1, 1), 40)
|
|
||||||
onChange({ cantidadDeSugerencias: capped })
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</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
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user