Implement atomic collection item creation API with unified content engine approach
Updates collection creation to use database-first atomic operations for reliable collection item management. Replaces manual database calls with unified content engine methods that handle content extraction, storage, and structural template generation consistently. Key changes: - Replace manual database operations in CreateCollectionItem handler with DatabaseClient.CreateCollectionItemAtomic() - Implement unified content engine approach for API-based collection item creation - Add atomic collection item creation methods across all content clients - Enhance reconstruction to use stored structural templates with content ID hydration - Add comprehensive collection management API methods in JavaScript client - Implement collection manager UI with create, delete, and reorder functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -141,6 +141,172 @@ export class ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Collection API Methods
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Create a new collection item
|
||||
* @param {string} collectionId - Collection ID
|
||||
* @param {number} templateId - Template ID to use (defaults to 1)
|
||||
* @param {string} htmlContent - Optional initial HTML content
|
||||
* @returns {Promise<Object>} Created collection item
|
||||
*/
|
||||
async createCollectionItem(collectionId, templateId = 1, htmlContent = '') {
|
||||
try {
|
||||
const collectionsUrl = this.baseUrl.replace('/api/content', '/api/collections');
|
||||
const payload = {
|
||||
site_id: this.siteId,
|
||||
template_id: templateId,
|
||||
html_content: htmlContent
|
||||
};
|
||||
|
||||
const response = await fetch(`${collectionsUrl}/${collectionId}/items`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.getAuthToken()}`
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
console.log(`✅ Collection item created: ${result.item_id}`);
|
||||
return result;
|
||||
} else {
|
||||
const errorText = await response.text();
|
||||
console.error(`❌ Failed to create collection item (${response.status}): ${errorText}`);
|
||||
throw new Error(`Failed to create collection item: ${response.status} ${errorText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error creating collection item:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a collection item
|
||||
* @param {string} collectionId - Collection ID
|
||||
* @param {string} itemId - Item ID to delete
|
||||
* @returns {Promise<boolean>} Success status
|
||||
*/
|
||||
async deleteCollectionItem(collectionId, itemId) {
|
||||
try {
|
||||
const collectionsUrl = this.baseUrl.replace('/api/content', '/api/collections');
|
||||
|
||||
const response = await fetch(`${collectionsUrl}/${collectionId}/items/${itemId}?site_id=${this.siteId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.getAuthToken()}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`✅ Collection item deleted: ${itemId}`);
|
||||
return true;
|
||||
} else {
|
||||
const errorText = await response.text();
|
||||
console.error(`❌ Failed to delete collection item (${response.status}): ${errorText}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error deleting collection item:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all collection items
|
||||
* @param {string} collectionId - Collection ID
|
||||
* @returns {Promise<Array>} Array of collection items
|
||||
*/
|
||||
async getCollectionItems(collectionId) {
|
||||
try {
|
||||
const collectionsUrl = this.baseUrl.replace('/api/content', '/api/collections');
|
||||
const response = await fetch(`${collectionsUrl}/${collectionId}/items?site_id=${this.siteId}`);
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
return result.items || [];
|
||||
} else {
|
||||
console.warn(`⚠️ Failed to fetch collection items (${response.status}): ${collectionId}`);
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch collection items:', collectionId, error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update collection item position (for reordering)
|
||||
* @param {string} collectionId - Collection ID
|
||||
* @param {string} itemId - Item ID to update
|
||||
* @param {number} newPosition - New position index
|
||||
* @returns {Promise<boolean>} Success status
|
||||
*/
|
||||
async updateCollectionItemPosition(collectionId, itemId, newPosition) {
|
||||
try {
|
||||
const collectionsUrl = this.baseUrl.replace('/api/content', '/api/collections');
|
||||
const payload = {
|
||||
site_id: this.siteId,
|
||||
position: newPosition
|
||||
};
|
||||
|
||||
const response = await fetch(`${collectionsUrl}/${collectionId}/items/${itemId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.getAuthToken()}`
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`✅ Collection item position updated: ${itemId} → position ${newPosition}`);
|
||||
return true;
|
||||
} else {
|
||||
const errorText = await response.text();
|
||||
console.error(`❌ Failed to update collection item position (${response.status}): ${errorText}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error updating collection item position:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger site enhancement after collection changes
|
||||
* @returns {Promise<boolean>} Success status
|
||||
*/
|
||||
async enhanceSite() {
|
||||
try {
|
||||
const enhanceUrl = this.baseUrl.replace('/api/content', '/api/enhance');
|
||||
const response = await fetch(`${enhanceUrl}?site_id=${this.siteId}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.getAuthToken()}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
console.log('✅ Files enhanced successfully:', result);
|
||||
return true;
|
||||
} else {
|
||||
console.error(`❌ Failed to enhance files (${response.status})`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error enhancing files:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Get authentication token for API requests
|
||||
* @returns {string} JWT token or mock token for development
|
||||
|
||||
Reference in New Issue
Block a user