feat(library-desk): fetch page ID via GraphQL in wikijs-integration.js
Use pages.singleByPath(path, locale) GraphQL query to get page ID during initialization instead of searching through page list. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Store page ID globally once fetched
|
||||
let CACHED_PAGE_ID = null;
|
||||
let CACHED_PAGE_PATH = null;
|
||||
|
||||
// Initialize when DOM is ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
@@ -39,11 +43,11 @@
|
||||
log('Initializing Library Desk integration...');
|
||||
log('Library Desk URL:', CONFIG.libraryDeskUrl);
|
||||
|
||||
// Wait for Wiki.js to fully render
|
||||
// Wait for page to be ready, then add buttons
|
||||
setTimeout(addButtons, 1500);
|
||||
}
|
||||
|
||||
function addButtons() {
|
||||
async function addButtons() {
|
||||
const pagePath = getPagePath();
|
||||
if (!pagePath) {
|
||||
log('Skipping buttons - not on a content page');
|
||||
@@ -58,6 +62,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch and cache page ID during initialization
|
||||
CACHED_PAGE_PATH = pagePath;
|
||||
CACHED_PAGE_ID = await getPageIdFromPath(pagePath);
|
||||
log('Cached page ID for this session:', CACHED_PAGE_ID);
|
||||
|
||||
if (CONFIG.buttonPosition === 'floating') {
|
||||
addFloatingButtons(pagePath);
|
||||
} else {
|
||||
@@ -210,33 +219,15 @@
|
||||
}
|
||||
|
||||
try {
|
||||
log('Fetching page list...');
|
||||
|
||||
const listUrl = CONFIG.libraryDeskUrl + '/wiki/pages?user=' + CONFIG.user + '&limit=200';
|
||||
const listResponse = await fetch(listUrl, {
|
||||
headers: { 'Authorization': 'Bearer ' + CONFIG.apiKey }
|
||||
});
|
||||
|
||||
if (!listResponse.ok) {
|
||||
throw new Error('Failed to fetch page list: ' + listResponse.status);
|
||||
// Use cached page ID from initialization
|
||||
if (!CACHED_PAGE_ID) {
|
||||
throw new Error('Page ID not available - was not fetched during initialization');
|
||||
}
|
||||
|
||||
const pageList = await listResponse.json();
|
||||
log('Fetched', pageList.pages.length, 'pages');
|
||||
log('Re-indexing page', CACHED_PAGE_ID, '...');
|
||||
|
||||
// Find matching page
|
||||
const page = findMatchingPage(pageList.pages, pagePath);
|
||||
|
||||
if (!page) {
|
||||
log('Available pages:', pageList.pages.map(p => p.path));
|
||||
throw new Error('Page not found in Library Desk. Check console for available pages.');
|
||||
}
|
||||
|
||||
log('Matched page:', page.id, page.path, page.title);
|
||||
log('Re-indexing...');
|
||||
|
||||
// Re-index
|
||||
const response = await fetch(CONFIG.libraryDeskUrl + '/ingest/batch', {
|
||||
// Re-index directly
|
||||
const response = await fetch(CONFIG.libraryDeskUrl + '/ingest/page', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + CONFIG.apiKey,
|
||||
@@ -244,15 +235,14 @@
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user: CONFIG.user,
|
||||
page_ids: [page.id]
|
||||
page_id: CACHED_PAGE_ID,
|
||||
force_refresh: true
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.successful > 0) {
|
||||
const pageResult = result.results[0];
|
||||
|
||||
if (response.ok && result.success) {
|
||||
if (isFloating) {
|
||||
button.innerHTML = '✓ Done!';
|
||||
button.style.background = '#4caf50';
|
||||
@@ -261,11 +251,11 @@
|
||||
icon.style.color = '#4caf50';
|
||||
}
|
||||
|
||||
const message = 'Re-indexed: ' + page.title + '\n\n' +
|
||||
'✓ Vectors: ' + pageResult.vector_chunks_created + ' chunks\n' +
|
||||
'✓ Entities: ' + pageResult.graph_entities_extracted + '\n' +
|
||||
'✓ Relationships: ' + pageResult.graph_relationships_created + '\n' +
|
||||
'⏱ Time: ' + Math.round(pageResult.processing_time_ms) + 'ms';
|
||||
const message = 'Re-indexed: ' + result.page_title + '\n\n' +
|
||||
'✓ Vectors: ' + result.vector_chunks_created + ' chunks\n' +
|
||||
'✓ Entities: ' + result.graph_entities_extracted + '\n' +
|
||||
'✓ Relationships: ' + result.graph_relationships_created + '\n' +
|
||||
'⏱ Time: ' + Math.round(result.processing_time_ms) + 'ms';
|
||||
|
||||
log('Success:', message);
|
||||
|
||||
@@ -333,28 +323,15 @@
|
||||
}
|
||||
|
||||
try {
|
||||
log('Fetching page list...');
|
||||
|
||||
// Step 1: Get page ID
|
||||
const listUrl = CONFIG.libraryDeskUrl + '/wiki/pages?user=' + CONFIG.user + '&limit=200';
|
||||
const listResponse = await fetch(listUrl, {
|
||||
headers: { 'Authorization': 'Bearer ' + CONFIG.apiKey }
|
||||
});
|
||||
|
||||
if (!listResponse.ok) {
|
||||
throw new Error('Failed to fetch page list');
|
||||
// Get page ID from Wiki.js GraphQL API
|
||||
const pageId = await getPageIdFromPath(pagePath);
|
||||
if (!pageId) {
|
||||
throw new Error('Could not get page ID from Wiki.js');
|
||||
}
|
||||
|
||||
const pageList = await listResponse.json();
|
||||
const page = findMatchingPage(pageList.pages, pagePath);
|
||||
log('Linking entities for page', pageId, '...');
|
||||
|
||||
if (!page) {
|
||||
throw new Error('Page not found in Library Desk');
|
||||
}
|
||||
|
||||
log('Found page:', page.id, page.title);
|
||||
|
||||
// Step 2: Call entity linking endpoint
|
||||
// Call entity linking endpoint
|
||||
const response = await fetch(CONFIG.libraryDeskUrl + '/entity-linking/link-page', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -363,7 +340,7 @@
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user: CONFIG.user,
|
||||
page_id: page.id,
|
||||
page_id: pageId,
|
||||
create_relationships: true,
|
||||
re_index_if_changed: true
|
||||
})
|
||||
@@ -447,29 +424,94 @@
|
||||
// SHARED UTILITIES
|
||||
// ============================================================================
|
||||
|
||||
function findMatchingPage(pages, pagePath) {
|
||||
const possiblePaths = [
|
||||
pagePath,
|
||||
'users/' + CONFIG.user + '/' + pagePath,
|
||||
pagePath.replace(/^\//, ''),
|
||||
CONFIG.user + '/' + pagePath
|
||||
];
|
||||
async function getPageIdFromPath(pagePath) {
|
||||
/**
|
||||
* Query Wiki.js GraphQL API to get page ID from path.
|
||||
* Uses singleByPath query which requires path and locale.
|
||||
*/
|
||||
try {
|
||||
// Get locale from URL or default to 'en'
|
||||
const urlLocaleMatch = window.location.pathname.match(/^\/([a-z]{2})\//);
|
||||
const locale = urlLocaleMatch ? urlLocaleMatch[1] : 'en';
|
||||
|
||||
log('Looking for page matching:', possiblePaths);
|
||||
log('Querying Wiki.js GraphQL for page:', pagePath, 'locale:', locale);
|
||||
|
||||
for (var i = 0; i < pages.length; i++) {
|
||||
var page = pages[i];
|
||||
for (var j = 0; j < possiblePaths.length; j++) {
|
||||
var testPath = possiblePaths[j];
|
||||
if (page.path === testPath ||
|
||||
page.path.endsWith('/' + testPath) ||
|
||||
('users/' + CONFIG.user + '/' + testPath) === page.path) {
|
||||
return page;
|
||||
const query = `
|
||||
query ($path: String!, $locale: String!) {
|
||||
pages {
|
||||
singleByPath(path: $path, locale: $locale) {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const response = await fetch('/graphql', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: { path: pagePath, locale: locale }
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
log('GraphQL response:', result);
|
||||
|
||||
if (result.data && result.data.pages && result.data.pages.singleByPath) {
|
||||
const pageId = result.data.pages.singleByPath.id;
|
||||
log('Found page ID from GraphQL:', pageId);
|
||||
return parseInt(pageId, 10);
|
||||
}
|
||||
|
||||
if (result.errors) {
|
||||
log('GraphQL errors:', result.errors.map(e => e.message).join(', '));
|
||||
}
|
||||
|
||||
log('GraphQL query returned no page');
|
||||
return null;
|
||||
} catch (error) {
|
||||
log('GraphQL query failed:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getPageId() {
|
||||
/**
|
||||
* Synchronous wrapper - returns null and triggers async fetch.
|
||||
* Actual buttons will need to call getPageIdFromPath() directly.
|
||||
*/
|
||||
log('getPageId() called - page ID must be fetched asynchronously via getPageIdFromPath()');
|
||||
return null;
|
||||
}
|
||||
|
||||
function waitForPageElement(callback, maxAttempts = 10, interval = 500) {
|
||||
/**
|
||||
* Wait for Vue store to be available, then call callback.
|
||||
*/
|
||||
let attempts = 0;
|
||||
|
||||
function check() {
|
||||
attempts++;
|
||||
|
||||
// Check if Vue store or page data is available
|
||||
const hasVueStore = window.$store && (window.$store.state || window.$store.get);
|
||||
const hasPageData = window.$page || window.pageId;
|
||||
|
||||
if (hasVueStore || hasPageData) {
|
||||
log('Vue/page data available after', attempts, 'attempts');
|
||||
callback();
|
||||
} else if (attempts < maxAttempts) {
|
||||
log('Waiting for Vue/page data... attempt', attempts);
|
||||
setTimeout(check, interval);
|
||||
} else {
|
||||
log('Vue/page data never appeared after', maxAttempts, 'attempts - adding buttons anyway');
|
||||
callback(); // Add buttons anyway, they just won't work
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
check();
|
||||
}
|
||||
|
||||
function findToolbar() {
|
||||
|
||||
Reference in New Issue
Block a user