Compare commits
No commits in common. "cef242e173d3ba3c70c0ab18d2fd8874f02c49ac" and "e42eec5dc1f81d166fc50a911b6cbd6d629a45e3" have entirely different histories.
cef242e173
...
e42eec5dc1
2 changed files with 51 additions and 105 deletions
|
@ -44,7 +44,17 @@ async function loadItemsFromDb(url: string): Promise<ItemsResponse> {
|
||||||
const selectedProperties = await propertiesResponse.json();
|
const selectedProperties = await propertiesResponse.json();
|
||||||
console.log('[DEBUG] Successfully received selected properties');
|
console.log('[DEBUG] Successfully received selected properties');
|
||||||
|
|
||||||
return { items, selectedProperties };
|
// Filter items to only include selected properties
|
||||||
|
const filteredItems = items.map((item: Item) => ({
|
||||||
|
...item,
|
||||||
|
customProperties: Object.fromEntries(
|
||||||
|
Object.entries(item.customProperties).filter(([key]) =>
|
||||||
|
selectedProperties.includes(key)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
|
||||||
|
return { items: filteredItems, selectedProperties };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveItemToDb(url: string, item: Item): Promise<void> {
|
async function saveItemToDb(url: string, item: Item): Promise<void> {
|
||||||
|
@ -451,10 +461,8 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// THIRD: Add to all items with auto-population from propertyCache AND save immediately
|
// THIRD: Add to all items with auto-population from propertyCache
|
||||||
const itemsToSave: Item[] = [];
|
setItems(prev => prev.map(item => {
|
||||||
|
|
||||||
const updatedItems = items.map(item => {
|
|
||||||
const existingValue = item.customProperties[normalizedProperty] || '';
|
const existingValue = item.customProperties[normalizedProperty] || '';
|
||||||
let autoPopulatedValue = existingValue;
|
let autoPopulatedValue = existingValue;
|
||||||
|
|
||||||
|
@ -464,56 +472,25 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
console.log(`Auto-populating ${normalizedProperty} for ${item.wikidataId} with value:`, autoPopulatedValue);
|
console.log(`Auto-populating ${normalizedProperty} for ${item.wikidataId} with value:`, autoPopulatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedItem = {
|
return {
|
||||||
...item,
|
...item,
|
||||||
customProperties: {
|
customProperties: {
|
||||||
...item.customProperties,
|
...item.customProperties,
|
||||||
[normalizedProperty]: autoPopulatedValue
|
[normalizedProperty]: autoPopulatedValue
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
// If we auto-populated a value, save it immediately
|
// FOURTH: Save to database and refresh data
|
||||||
if (autoPopulatedValue && autoPopulatedValue !== existingValue) {
|
|
||||||
console.log(`Adding item to save queue: ${item.id} with ${normalizedProperty}=${autoPopulatedValue}`);
|
|
||||||
itemsToSave.push(updatedItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return updatedItem;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update state with all items at once
|
|
||||||
setItems(updatedItems);
|
|
||||||
|
|
||||||
// Save all auto-populated items immediately
|
|
||||||
console.log('Items to save from cache population:', itemsToSave.length);
|
|
||||||
if (itemsToSave.length > 0) {
|
|
||||||
console.log('Saving auto-populated items:', itemsToSave.map(item => ({ id: item.id, name: item.name })));
|
|
||||||
}
|
|
||||||
|
|
||||||
const cachePopulationPromises = itemsToSave.map(item => {
|
|
||||||
console.log(`Saving item ${item.id} with auto-populated value`);
|
|
||||||
return saveItemToDb(url, item);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Items to save from cache population:', itemsToSave.length);
|
|
||||||
if (itemsToSave.length > 0) {
|
|
||||||
console.log('Items being saved:', itemsToSave.map(item => ({ id: item.id, name: item.name, properties: item.customProperties })));
|
|
||||||
}
|
|
||||||
|
|
||||||
// FOURTH: Save property to database
|
|
||||||
try {
|
try {
|
||||||
if (cachePopulationPromises.length > 0) {
|
|
||||||
console.log(`Waiting for ${cachePopulationPromises.length} auto-populated items to save...`);
|
|
||||||
await Promise.all(cachePopulationPromises);
|
|
||||||
console.log('All cache-populated items saved successfully');
|
|
||||||
} else {
|
|
||||||
console.log('No auto-populated items to save');
|
|
||||||
}
|
|
||||||
|
|
||||||
await addPropertyToDb(url, normalizedProperty);
|
await addPropertyToDb(url, normalizedProperty);
|
||||||
console.log('Property successfully saved to database:', normalizedProperty);
|
console.log('Property successfully saved to database:', normalizedProperty);
|
||||||
|
|
||||||
|
// Invalidate queries to refresh data from database
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['items', url] });
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in property addition process:', error);
|
console.error('Error saving property to database:', error);
|
||||||
// Revert optimistic updates on error
|
// Revert optimistic updates on error
|
||||||
setSelectedProperties(prev => {
|
setSelectedProperties(prev => {
|
||||||
const newSelected = { ...prev };
|
const newSelected = { ...prev };
|
||||||
|
@ -533,9 +510,6 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
// FIFTH: Fetch Wikidata properties for items with wikidata_id that don't have cached data
|
// FIFTH: Fetch Wikidata properties for items with wikidata_id that don't have cached data
|
||||||
const itemsWithWikidataId = items.filter(item => item.wikidataId && !propertyCache[item.wikidataId]);
|
const itemsWithWikidataId = items.filter(item => item.wikidataId && !propertyCache[item.wikidataId]);
|
||||||
|
|
||||||
// Create array to store all save promises
|
|
||||||
const savePromises: Promise<void>[] = [];
|
|
||||||
|
|
||||||
for (const item of itemsWithWikidataId) {
|
for (const item of itemsWithWikidataId) {
|
||||||
if (item.wikidataId) {
|
if (item.wikidataId) {
|
||||||
try {
|
try {
|
||||||
|
@ -560,9 +534,8 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
: prevItem
|
: prevItem
|
||||||
));
|
));
|
||||||
|
|
||||||
// Get current items state and save the updated item to database
|
// Save the updated item to database to persist the auto-populated value
|
||||||
setItems(currentItems => {
|
const updatedItem = items.find(i => i.wikidataId === item.wikidataId);
|
||||||
const updatedItem = currentItems.find(i => i.wikidataId === item.wikidataId);
|
|
||||||
if (updatedItem) {
|
if (updatedItem) {
|
||||||
const itemToSave = {
|
const itemToSave = {
|
||||||
...updatedItem,
|
...updatedItem,
|
||||||
|
@ -571,33 +544,19 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
[normalizedProperty]: properties[normalizedProperty]
|
[normalizedProperty]: properties[normalizedProperty]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Add save promise to array instead of awaiting immediately
|
saveItemToDb(url, itemToSave).catch(error => {
|
||||||
savePromises.push(saveItemToDb(url, itemToSave));
|
console.error('Error saving auto-populated value:', error);
|
||||||
}
|
|
||||||
return currentItems; // Return unchanged state since we already updated it above
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error fetching Wikidata properties for ${item.wikidataId}:`, error);
|
console.error(`Error fetching Wikidata properties for ${item.wikidataId}:`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WAIT for all saves to complete before invalidating queries
|
console.log('Property addition completed:', normalizedProperty);
|
||||||
if (savePromises.length > 0) {
|
}, [customProperties, propertyLabels, items, propertyCache, url]);
|
||||||
try {
|
|
||||||
await Promise.all(savePromises);
|
|
||||||
console.log('All auto-populated items saved successfully');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error saving some auto-populated items:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SIXTH: Only invalidate queries after ALL operations are complete
|
|
||||||
console.log('Property addition completed, refreshing data:', normalizedProperty);
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['items', url] });
|
|
||||||
|
|
||||||
}, [customProperties, propertyLabels, items, propertyCache, url, queryClient, saveItemToDb]);
|
|
||||||
|
|
||||||
const handleWikidataSelect = useCallback(async (suggestion: WikidataSuggestion, itemId: string) => {
|
const handleWikidataSelect = useCallback(async (suggestion: WikidataSuggestion, itemId: string) => {
|
||||||
console.log('Wikidata selection for item:', itemId, suggestion);
|
console.log('Wikidata selection for item:', itemId, suggestion);
|
||||||
|
|
|
@ -165,31 +165,18 @@ export function PropertyInput({
|
||||||
|
|
||||||
// Handle blur
|
// Handle blur
|
||||||
const handleBlur = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
|
const handleBlur = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
// Delay and more robust checking
|
// Delay hiding suggestions to allow for clicks on suggestions
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Check if the active element is within our suggestions dropdown
|
const relatedTarget = e.relatedTarget as HTMLElement;
|
||||||
const activeElement = document.activeElement;
|
if (!suggestionsRef.current?.contains(relatedTarget)) {
|
||||||
const isClickingOnSuggestion = suggestionsRef.current?.contains(activeElement) ||
|
|
||||||
suggestionsRef.current?.contains(e.relatedTarget as HTMLElement);
|
|
||||||
|
|
||||||
if (!isClickingOnSuggestion) {
|
|
||||||
setShowSuggestions(false);
|
setShowSuggestions(false);
|
||||||
setSelectedIndex(-1);
|
setSelectedIndex(-1);
|
||||||
}
|
}
|
||||||
}, 200);
|
}, 150);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Handle suggestion click
|
// Handle suggestion click
|
||||||
const handleSuggestionClick = useCallback((property: PropertySuggestion, event: React.MouseEvent) => {
|
const handleSuggestionClick = useCallback((property: PropertySuggestion) => {
|
||||||
// Prevent the blur event from interfering
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
// Immediately hide suggestions and process selection
|
|
||||||
setShowSuggestions(false);
|
|
||||||
setSelectedIndex(-1);
|
|
||||||
|
|
||||||
// Process the selection
|
|
||||||
handlePropertySelect(property);
|
handlePropertySelect(property);
|
||||||
}, [handlePropertySelect]);
|
}, [handlePropertySelect]);
|
||||||
|
|
||||||
|
@ -259,7 +246,7 @@ export function PropertyInput({
|
||||||
: 'hover:bg-gray-50 border-l-4 border-transparent'
|
: 'hover:bg-gray-50 border-l-4 border-transparent'
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
onClick={(event) => handleSuggestionClick(suggestion, event)}
|
onClick={() => handleSuggestionClick(suggestion)}
|
||||||
onMouseEnter={() => setSelectedIndex(index)}
|
onMouseEnter={() => setSelectedIndex(index)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|
Loading…
Add table
Reference in a new issue