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
|
// Initialize when DOM is ready
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
@@ -39,11 +43,11 @@
|
|||||||
log('Initializing Library Desk integration...');
|
log('Initializing Library Desk integration...');
|
||||||
log('Library Desk URL:', CONFIG.libraryDeskUrl);
|
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);
|
setTimeout(addButtons, 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addButtons() {
|
async function addButtons() {
|
||||||
const pagePath = getPagePath();
|
const pagePath = getPagePath();
|
||||||
if (!pagePath) {
|
if (!pagePath) {
|
||||||
log('Skipping buttons - not on a content page');
|
log('Skipping buttons - not on a content page');
|
||||||
@@ -58,6 +62,11 @@
|
|||||||
return;
|
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') {
|
if (CONFIG.buttonPosition === 'floating') {
|
||||||
addFloatingButtons(pagePath);
|
addFloatingButtons(pagePath);
|
||||||
} else {
|
} else {
|
||||||
@@ -210,33 +219,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log('Fetching page list...');
|
// Use cached page ID from initialization
|
||||||
|
if (!CACHED_PAGE_ID) {
|
||||||
const listUrl = CONFIG.libraryDeskUrl + '/wiki/pages?user=' + CONFIG.user + '&limit=200';
|
throw new Error('Page ID not available - was not fetched during initialization');
|
||||||
const listResponse = await fetch(listUrl, {
|
|
||||||
headers: { 'Authorization': 'Bearer ' + CONFIG.apiKey }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!listResponse.ok) {
|
|
||||||
throw new Error('Failed to fetch page list: ' + listResponse.status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageList = await listResponse.json();
|
log('Re-indexing page', CACHED_PAGE_ID, '...');
|
||||||
log('Fetched', pageList.pages.length, 'pages');
|
|
||||||
|
|
||||||
// Find matching page
|
// Re-index directly
|
||||||
const page = findMatchingPage(pageList.pages, pagePath);
|
const response = await fetch(CONFIG.libraryDeskUrl + '/ingest/page', {
|
||||||
|
|
||||||
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', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer ' + CONFIG.apiKey,
|
'Authorization': 'Bearer ' + CONFIG.apiKey,
|
||||||
@@ -244,15 +235,14 @@
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
user: CONFIG.user,
|
user: CONFIG.user,
|
||||||
page_ids: [page.id]
|
page_id: CACHED_PAGE_ID,
|
||||||
|
force_refresh: true
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok && result.successful > 0) {
|
if (response.ok && result.success) {
|
||||||
const pageResult = result.results[0];
|
|
||||||
|
|
||||||
if (isFloating) {
|
if (isFloating) {
|
||||||
button.innerHTML = '✓ Done!';
|
button.innerHTML = '✓ Done!';
|
||||||
button.style.background = '#4caf50';
|
button.style.background = '#4caf50';
|
||||||
@@ -261,11 +251,11 @@
|
|||||||
icon.style.color = '#4caf50';
|
icon.style.color = '#4caf50';
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = 'Re-indexed: ' + page.title + '\n\n' +
|
const message = 'Re-indexed: ' + result.page_title + '\n\n' +
|
||||||
'✓ Vectors: ' + pageResult.vector_chunks_created + ' chunks\n' +
|
'✓ Vectors: ' + result.vector_chunks_created + ' chunks\n' +
|
||||||
'✓ Entities: ' + pageResult.graph_entities_extracted + '\n' +
|
'✓ Entities: ' + result.graph_entities_extracted + '\n' +
|
||||||
'✓ Relationships: ' + pageResult.graph_relationships_created + '\n' +
|
'✓ Relationships: ' + result.graph_relationships_created + '\n' +
|
||||||
'⏱ Time: ' + Math.round(pageResult.processing_time_ms) + 'ms';
|
'⏱ Time: ' + Math.round(result.processing_time_ms) + 'ms';
|
||||||
|
|
||||||
log('Success:', message);
|
log('Success:', message);
|
||||||
|
|
||||||
@@ -333,28 +323,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log('Fetching page list...');
|
// Get page ID from Wiki.js GraphQL API
|
||||||
|
const pageId = await getPageIdFromPath(pagePath);
|
||||||
// Step 1: Get page ID
|
if (!pageId) {
|
||||||
const listUrl = CONFIG.libraryDeskUrl + '/wiki/pages?user=' + CONFIG.user + '&limit=200';
|
throw new Error('Could not get page ID from Wiki.js');
|
||||||
const listResponse = await fetch(listUrl, {
|
|
||||||
headers: { 'Authorization': 'Bearer ' + CONFIG.apiKey }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!listResponse.ok) {
|
|
||||||
throw new Error('Failed to fetch page list');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageList = await listResponse.json();
|
log('Linking entities for page', pageId, '...');
|
||||||
const page = findMatchingPage(pageList.pages, pagePath);
|
|
||||||
|
|
||||||
if (!page) {
|
// Call entity linking endpoint
|
||||||
throw new Error('Page not found in Library Desk');
|
|
||||||
}
|
|
||||||
|
|
||||||
log('Found page:', page.id, page.title);
|
|
||||||
|
|
||||||
// Step 2: Call entity linking endpoint
|
|
||||||
const response = await fetch(CONFIG.libraryDeskUrl + '/entity-linking/link-page', {
|
const response = await fetch(CONFIG.libraryDeskUrl + '/entity-linking/link-page', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -363,7 +340,7 @@
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
user: CONFIG.user,
|
user: CONFIG.user,
|
||||||
page_id: page.id,
|
page_id: pageId,
|
||||||
create_relationships: true,
|
create_relationships: true,
|
||||||
re_index_if_changed: true
|
re_index_if_changed: true
|
||||||
})
|
})
|
||||||
@@ -447,29 +424,94 @@
|
|||||||
// SHARED UTILITIES
|
// SHARED UTILITIES
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
function findMatchingPage(pages, pagePath) {
|
async function getPageIdFromPath(pagePath) {
|
||||||
const possiblePaths = [
|
/**
|
||||||
pagePath,
|
* Query Wiki.js GraphQL API to get page ID from path.
|
||||||
'users/' + CONFIG.user + '/' + pagePath,
|
* Uses singleByPath query which requires path and locale.
|
||||||
pagePath.replace(/^\//, ''),
|
*/
|
||||||
CONFIG.user + '/' + pagePath
|
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++) {
|
const query = `
|
||||||
var page = pages[i];
|
query ($path: String!, $locale: String!) {
|
||||||
for (var j = 0; j < possiblePaths.length; j++) {
|
pages {
|
||||||
var testPath = possiblePaths[j];
|
singleByPath(path: $path, locale: $locale) {
|
||||||
if (page.path === testPath ||
|
id
|
||||||
page.path.endsWith('/' + testPath) ||
|
}
|
||||||
('users/' + CONFIG.user + '/' + testPath) === page.path) {
|
}
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
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() {
|
function findToolbar() {
|
||||||
|
|||||||
Reference in New Issue
Block a user