Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 13 additions & 22 deletions components/create-column/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import TPEN from "../../api/TPEN.js"
import CheckPermissions from "../check-permissions/checkPermissions.js"
import { onProjectReady } from "../../utilities/projectReady.js"
import { CleanupRegistry } from "../../utilities/CleanupRegistry.js"
import vault from '../../js/vault.js'

/**
* TpenCreateColumn - Interface for creating and managing columns on annotation pages.
Expand Down Expand Up @@ -563,27 +564,14 @@ class TpenCreateColumn extends HTMLElement {
return { x: xywh[0], y: xywh[1], w: xywh[2], h: xywh[3] }
}

isValidUrl(str) {
try {
new URL(str)
return true
} catch {
return false
}
}

async getSpecificTypeData(type) {
if (!type) throw new Error("No IIIF resource provided")
if (typeof type === "string" && this.isValidUrl(type)) {
const res = await fetch(type, { cache: "no-store" })
if (!res.ok) throw new Error(`Fetch failed: ${res.status}`)
return await res.json()
}
}

async fetchPageViewerData(pageID = null) {
const annotationPageData = pageID ? await this.getSpecificTypeData(pageID) : null
const canvasData = await this.getSpecificTypeData(annotationPageData.target)
if (!pageID) throw new Error("No page ID provided")
const annotationPageData = await vault.getWithFallback(pageID, 'annotationpage', TPEN.activeProject?.manifest, true)
if (!annotationPageData) throw new Error("Failed to load annotation page")
const canvasData = await vault.getWithFallback(
annotationPageData.target, 'canvas', TPEN.activeProject?.manifest
)
if (!canvasData) throw new Error("Failed to load canvas data")
return await this.processDirectCanvasData(canvasData, annotationPageData)
}

Expand All @@ -597,8 +585,11 @@ class TpenCreateColumn extends HTMLElement {
if (!annotationPageData?.items) return []
const results = await Promise.all(annotationPageData.items.map(async anno => {
try {
const res = await fetch(anno.id, { cache: "no-store" })
const data = await res.json()
let data = anno
if (!data?.target) {
data = await vault.get(anno.id ?? anno, 'annotation', true)
}
if (!data) return null
return { target: data?.target?.selector?.value ?? data?.target, lineId: data?.id }
} catch { return null }
}))
Expand Down
35 changes: 13 additions & 22 deletions interfaces/manage-columns/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import CheckPermissions from "../../components/check-permissions/checkPermission
import { renderPermissionError } from "../../utilities/renderPermissionError.js"
import { onProjectReady } from "../../utilities/projectReady.js"
import { CleanupRegistry } from '../../utilities/CleanupRegistry.js'
import vault from '../../js/vault.js'

/**
* TpenManageColumns - Interface for managing column assignments on annotation pages.
Expand Down Expand Up @@ -633,27 +634,14 @@ class TpenManageColumns extends HTMLElement {
return { x: xywh[0], y: xywh[1], w: xywh[2], h: xywh[3] }
}

isValidUrl(str) {
try {
new URL(str)
return true
} catch {
return false
}
}

async getSpecificTypeData(type) {
if (!type) throw new Error("No IIIF resource provided")
if (typeof type === "string" && this.isValidUrl(type)) {
const res = await fetch(type, { cache: "no-store" })
if (!res.ok) throw new Error(`Fetch failed: ${res.status}`)
return await res.json()
}
}

async fetchPageViewerData(pageID = null) {
const annotationPageData = pageID ? await this.getSpecificTypeData(pageID) : null
const canvasData = await this.getSpecificTypeData(annotationPageData.target)
if (!pageID) throw new Error("No page ID provided")
const annotationPageData = await vault.getWithFallback(pageID, 'annotationpage', TPEN.activeProject?.manifest, true)
if (!annotationPageData) throw new Error("Failed to load annotation page")
const canvasData = await vault.getWithFallback(
annotationPageData.target, 'canvas', TPEN.activeProject?.manifest
)
if (!canvasData) throw new Error("Failed to load canvas data")
Comment on lines +638 to +644
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same vault.getWithFallback page/canvas loading flow appears in both interfaces/manage-columns/index.js and components/create-column/index.js. To prevent drift (e.g., different error handling, fallback behavior, or resource typing over time), consider extracting this into a shared utility (e.g., loadAnnotationPageAndCanvas(pageID, manifest)), used by both components.

Copilot uses AI. Check for mistakes.
return await this.processDirectCanvasData(canvasData, annotationPageData)
}

Expand All @@ -667,8 +655,11 @@ class TpenManageColumns extends HTMLElement {
if (!annotationPageData?.items) return []
const results = await Promise.all(annotationPageData.items.map(async anno => {
try {
const res = await fetch(anno.id, { cache: "no-store" })
const data = await res.json()
let data = anno
if (!data?.target) {
data = await vault.get(anno.id ?? anno, 'annotation', true)
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vault.get(anno.id ?? anno, ...) can end up passing a non-string object into vault.get when anno is an object without an id (since anno.id is undefined, the ?? falls back to the whole object). If vault.get expects an ID/URI, this will fail at runtime. Consider normalizing to an ID first (e.g., only call vault.get when you have a string ID), and return null (or throw) when no ID is available.

Suggested change
data = await vault.get(anno.id ?? anno, 'annotation', true)
const annotationId =
typeof anno === 'string'
? anno
: (typeof anno?.id === 'string' ? anno.id : null)
if (!annotationId) return null
data = await vault.get(annotationId, 'annotation', true)

Copilot uses AI. Check for mistakes.
}
if (!data) return null
return { target: data?.target?.selector?.value ?? data?.target, lineId: data?.id }
} catch { return null }
}))
Expand Down
Loading