Massive performance improvments my more accurately leveraging async, and searchSimple. Resolved issue of cards on AdminBoard not displaying properly. version 0.63beta.
This commit is contained in:
@@ -173,9 +173,10 @@ const extractCardsMinterName = (cardIdentifier) => {
|
||||
if (parts.length < 3) {
|
||||
throw new Error('Invalid identifier format');
|
||||
}
|
||||
|
||||
if (parts.slice(2, -1).join('-') === 'TOPIC') {
|
||||
console.log(`TOPIC found in identifier: ${cardIdentifier} - not including in duplicatesList`)
|
||||
return
|
||||
return 'topic'
|
||||
}
|
||||
// Extract minterName (everything from the second part to the second-to-last part)
|
||||
const minterName = parts.slice(2, -1).join('-');
|
||||
@@ -186,73 +187,39 @@ const extractCardsMinterName = (cardIdentifier) => {
|
||||
const processCards = async (validEncryptedCards) => {
|
||||
const latestCardsMap = new Map()
|
||||
|
||||
// Step 1: Filter and keep the most recent card per identifier
|
||||
validEncryptedCards.forEach(card => {
|
||||
// Step 1: Process all cards in parallel
|
||||
await Promise.all(validEncryptedCards.map(async card => {
|
||||
const timestamp = card.updated || card.created || 0
|
||||
const existingCard = latestCardsMap.get(card.identifier)
|
||||
|
||||
if (!existingCard || timestamp > (existingCard.updated || existingCard.created || 0)) {
|
||||
latestCardsMap.set(card.identifier, card)
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
console.log(`latestCardsMap, by timestamp`, latestCardsMap)
|
||||
|
||||
// Step 2: Extract unique cards
|
||||
const uniqueValidCards = Array.from(latestCardsMap.values())
|
||||
|
||||
// Step 3: Group by minterName and select the most recent card per minterName
|
||||
const minterNameMap = new Map()
|
||||
|
||||
for (const card of validEncryptedCards) {
|
||||
const minterName = await extractCardsMinterName(card.identifier)
|
||||
const existingCard = minterNameMap.get(minterName)
|
||||
const cardTimestamp = card.updated || card.created || 0
|
||||
const existingTimestamp = existingCard?.updated || existingCard?.created || 0
|
||||
|
||||
if (!existingCardMinterNames.includes(minterName)) {
|
||||
existingCardMinterNames.push(minterName)
|
||||
console.log(`cardsMinterName: ${minterName} - added to list`)
|
||||
}
|
||||
|
||||
// Keep only the most recent card for each minterName
|
||||
if (!existingCard || cardTimestamp > existingTimestamp) {
|
||||
minterNameMap.set(minterName, card)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Filter cards to ensure each minterName is included only once
|
||||
const finalCards = []
|
||||
const seenMinterNames = new Set()
|
||||
|
||||
for (const [minterName, card] of minterNameMap.entries()) {
|
||||
if (!seenMinterNames.has(minterName)) {
|
||||
finalCards.push(card)
|
||||
seenMinterNames.add(minterName) // Mark the minterName as seen
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5: Sort by the most recent timestamp
|
||||
finalCards.sort((a, b) => {
|
||||
const timestampA = a.updated || a.created || 0
|
||||
const timestampB = b.updated || b.created || 0
|
||||
return timestampB - timestampA
|
||||
})
|
||||
|
||||
return finalCards
|
||||
return uniqueValidCards
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Main function to load the Minter Cards ----------------------------------------
|
||||
const fetchAllEncryptedCards = async () => {
|
||||
const encryptedCardsContainer = document.getElementById("encrypted-cards-container");
|
||||
encryptedCardsContainer.innerHTML = "<p>Loading cards...</p>";
|
||||
|
||||
try {
|
||||
const response = await qortalRequest({
|
||||
action: "SEARCH_QDN_RESOURCES",
|
||||
service: "MAIL_PRIVATE",
|
||||
query: encryptedCardIdentifierPrefix,
|
||||
mode: "ALL"
|
||||
});
|
||||
// const response = await qortalRequest({
|
||||
// action: "SEARCH_QDN_RESOURCES",
|
||||
// service: "MAIL_PRIVATE",
|
||||
// query: encryptedCardIdentifierPrefix,
|
||||
// mode: "ALL"
|
||||
// })
|
||||
const response = await searchSimple('MAIL_PRIVATE', `${encryptedCardIdentifierPrefix}`, '', 0)
|
||||
|
||||
if (!response || !Array.isArray(response) || response.length === 0) {
|
||||
encryptedCardsContainer.innerHTML = "<p>No cards found.</p>";
|
||||
@@ -262,19 +229,21 @@ const fetchAllEncryptedCards = async () => {
|
||||
// Validate cards and filter
|
||||
const validatedEncryptedCards = await Promise.all(
|
||||
response.map(async card => {
|
||||
const isValid = await validateEncryptedCardIdentifier(card);
|
||||
return isValid ? card : null;
|
||||
const isValid = await validateEncryptedCardIdentifier(card)
|
||||
return isValid ? card : null
|
||||
})
|
||||
);
|
||||
)
|
||||
console.log(`validatedEncryptedCards:`, validatedEncryptedCards, `... running next filter...`)
|
||||
|
||||
const validEncryptedCards = validatedEncryptedCards.filter(card => card !== null);
|
||||
console.log(`validEncryptedcards:`, validEncryptedCards)
|
||||
|
||||
if (validEncryptedCards.length === 0) {
|
||||
encryptedCardsContainer.innerHTML = "<p>No valid cards found.</p>";
|
||||
return;
|
||||
}
|
||||
const finalCards = await processCards(validEncryptedCards)
|
||||
|
||||
console.log(`finalCards:`,finalCards)
|
||||
// Display skeleton cards immediately
|
||||
encryptedCardsContainer.innerHTML = "";
|
||||
finalCards.forEach(card => {
|
||||
@@ -371,14 +340,16 @@ const createEncryptedSkeletonCardHTML = (cardIdentifier) => {
|
||||
// Function to check and fech an existing Minter Card if attempting to publish twice ----------------------------------------
|
||||
const fetchExistingEncryptedCard = async (minterName) => {
|
||||
try {
|
||||
// Step 1: Perform the search
|
||||
const response = await qortalRequest({
|
||||
action: "SEARCH_QDN_RESOURCES",
|
||||
service: "MAIL_PRIVATE",
|
||||
identifier: encryptedCardIdentifierPrefix,
|
||||
query: minterName,
|
||||
mode: "ALL",
|
||||
});
|
||||
// const response = await qortalRequest({
|
||||
// action: "SEARCH_QDN_RESOURCES",
|
||||
// service: "MAIL_PRIVATE",
|
||||
// identifier: encryptedCardIdentifierPrefix,
|
||||
// query: minterName,
|
||||
// mode: "ALL",
|
||||
// })
|
||||
|
||||
//CHANGED to searchSimple to speed up search results.
|
||||
const response = await searchSimple('MAIL_PRIVATE', `${encryptedCardIdentifierPrefix}`, '', 0)
|
||||
|
||||
console.log(`SEARCH_QDN_RESOURCES response: ${JSON.stringify(response, null, 2)}`);
|
||||
|
||||
@@ -598,17 +569,18 @@ const publishEncryptedCard = async (isTopicModePassed = false) => {
|
||||
|
||||
const getEncryptedCommentCount = async (cardIdentifier) => {
|
||||
try {
|
||||
const response = await qortalRequest({
|
||||
action: 'SEARCH_QDN_RESOURCES',
|
||||
service: 'MAIL_PRIVATE',
|
||||
query: `comment-${cardIdentifier}`,
|
||||
mode: "ALL"
|
||||
});
|
||||
// const response = await qortalRequest({
|
||||
// action: 'SEARCH_QDN_RESOURCES',
|
||||
// service: 'MAIL_PRIVATE',
|
||||
// query: `comment-${cardIdentifier}`,
|
||||
// mode: "ALL"
|
||||
// })
|
||||
const response = await searchSimple('MAIL_PRIVATE', `comment-${cardIdentifier}`, '', 0)
|
||||
// Just return the count; no need to decrypt each comment here
|
||||
return Array.isArray(response) ? response.length : 0;
|
||||
return Array.isArray(response) ? response.length : 0
|
||||
} catch (error) {
|
||||
console.error(`Error fetching comment count for ${cardIdentifier}:`, error);
|
||||
return 0;
|
||||
console.error(`Error fetching comment count for ${cardIdentifier}:`, error)
|
||||
return 0
|
||||
}
|
||||
};
|
||||
|
||||
@@ -666,14 +638,17 @@ const postEncryptedComment = async (cardIdentifier) => {
|
||||
//Fetch the comments for a card with passed card identifier ----------------------------
|
||||
const fetchEncryptedComments = async (cardIdentifier) => {
|
||||
try {
|
||||
const response = await qortalRequest({
|
||||
action: 'SEARCH_QDN_RESOURCES',
|
||||
service: 'MAIL_PRIVATE',
|
||||
query: `comment-${cardIdentifier}`,
|
||||
mode: "ALL"
|
||||
});
|
||||
// const response = await qortalRequest({
|
||||
// action: 'SEARCH_QDN_RESOURCES',
|
||||
// service: 'MAIL_PRIVATE',
|
||||
// query: `comment-${cardIdentifier}`,
|
||||
// mode: "ALL"
|
||||
// })
|
||||
const response = await searchSimple('MAIL_PRIVATE', `comment-${cardIdentifier}`, '', 0)
|
||||
|
||||
return response;
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error fetching comments for ${cardIdentifier}:`, error);
|
||||
return [];
|
||||
@@ -683,7 +658,9 @@ const fetchEncryptedComments = async (cardIdentifier) => {
|
||||
// display the comments on the card, with passed cardIdentifier to identify the card --------------
|
||||
const displayEncryptedComments = async (cardIdentifier) => {
|
||||
try {
|
||||
|
||||
const comments = await fetchEncryptedComments(cardIdentifier);
|
||||
|
||||
const commentsContainer = document.getElementById(`comments-container-${cardIdentifier}`);
|
||||
|
||||
// Fetch and display each comment
|
||||
@@ -712,8 +689,8 @@ const displayEncryptedComments = async (cardIdentifier) => {
|
||||
commentsContainer.insertAdjacentHTML('beforeend', commentHTML);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error displaying comments for ${cardIdentifier}:`, error);
|
||||
alert("Failed to load comments. Please try again.");
|
||||
console.error(`Error displaying comments (or no comments) for ${cardIdentifier}:`, error);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -757,7 +734,7 @@ const calculateAdminBoardPollResults = async (pollData, minterGroupMembers, mint
|
||||
// 4) Process votes
|
||||
for (const vote of pollData.votes) {
|
||||
const voterAddress = await getAddressFromPublicKey(vote.voterPublicKey);
|
||||
console.log(`voter address: ${voterAddress}, optionIndex: ${vote.optionIndex}`);
|
||||
// console.log(`voter address: ${voterAddress}, optionIndex: ${vote.optionIndex}`);
|
||||
|
||||
if (vote.optionIndex === 0) {
|
||||
if (adminAddresses.includes(voterAddress)) {
|
||||
|
@@ -120,17 +120,17 @@ const loadMinterBoardPage = async () => {
|
||||
const extractMinterCardsMinterName = async (cardIdentifier) => {
|
||||
// Ensure the identifier starts with the prefix
|
||||
if (!cardIdentifier.startsWith(`${cardIdentifierPrefix}-`)) {
|
||||
throw new Error('Invalid identifier format or prefix mismatch');
|
||||
throw new Error('Invalid identifier format or prefix mismatch')
|
||||
}
|
||||
// Split the identifier into parts
|
||||
const parts = cardIdentifier.split('-');
|
||||
const parts = cardIdentifier.split('-')
|
||||
// Ensure the format has at least 3 parts
|
||||
if (parts.length < 3) {
|
||||
throw new Error('Invalid identifier format');
|
||||
throw new Error('Invalid identifier format')
|
||||
}
|
||||
try {
|
||||
const nameFromIdentifier = await searchSimple('BLOG_POST', cardIdentifier, "", 1)
|
||||
const minterName = await nameFromIdentifier.name
|
||||
const searchSimpleResults = await searchSimple('BLOG_POST', `${cardIdentifier}`, '', 1)
|
||||
const minterName = await searchSimpleResults.name
|
||||
return minterName
|
||||
} catch (error) {
|
||||
throw error
|
||||
@@ -195,12 +195,14 @@ const loadCards = async () => {
|
||||
cardsContainer.innerHTML = "<p>Loading cards...</p>";
|
||||
|
||||
try {
|
||||
const response = await qortalRequest({
|
||||
action: "SEARCH_QDN_RESOURCES",
|
||||
service: "BLOG_POST",
|
||||
query: cardIdentifierPrefix,
|
||||
mode: "ALL"
|
||||
});
|
||||
// const response = await qortalRequest({
|
||||
// action: "SEARCH_QDN_RESOURCES",
|
||||
// service: "BLOG_POST",
|
||||
// query: cardIdentifierPrefix,
|
||||
// mode: "ALL"
|
||||
// })
|
||||
|
||||
const response = await searchSimple('BLOG_POST', `${cardIdentifierPrefix}`, '' , 0)
|
||||
|
||||
if (!response || !Array.isArray(response) || response.length === 0) {
|
||||
cardsContainer.innerHTML = "<p>No cards found.</p>";
|
||||
@@ -320,14 +322,16 @@ const createSkeletonCardHTML = (cardIdentifier) => {
|
||||
const fetchExistingCard = async () => {
|
||||
try {
|
||||
// Step 1: Perform the search
|
||||
const response = await qortalRequest({
|
||||
action: "SEARCH_QDN_RESOURCES",
|
||||
service: "BLOG_POST",
|
||||
identifier: cardIdentifierPrefix,
|
||||
name: userState.accountName,
|
||||
mode: "ALL",
|
||||
exactMatchNames: true // Search for the exact userName only when finding existing cards
|
||||
});
|
||||
// const response = await qortalRequest({
|
||||
// action: "SEARCH_QDN_RESOURCES",
|
||||
// service: "BLOG_POST",
|
||||
// identifier: cardIdentifierPrefix,
|
||||
// name: userState.accountName,
|
||||
// mode: "ALL",
|
||||
// exactMatchNames: true // Search for the exact userName only when finding existing cards
|
||||
// })
|
||||
// Changed to searchSimple to improve load times.
|
||||
const response = await searchSimple('BLOG_POST', `${cardIdentifierPrefix}`, `${userState.accountName}`, 0)
|
||||
|
||||
console.log(`SEARCH_QDN_RESOURCES response: ${JSON.stringify(response, null, 2)}`);
|
||||
|
||||
@@ -335,9 +339,11 @@ const fetchExistingCard = async () => {
|
||||
if (!response || !Array.isArray(response) || response.length === 0) {
|
||||
console.log("No cards found for the current user.");
|
||||
return null;
|
||||
} else if (response.length === 1) { // we don't need to go through all of the rest of the checks and filtering nonsense if there's only a single result, just return it.
|
||||
return response[0]
|
||||
}
|
||||
|
||||
// Step 3: Validate cards asynchronously
|
||||
// Validate cards asynchronously, check that they are not comments, etc.
|
||||
const validatedCards = await Promise.all(
|
||||
response.map(async card => {
|
||||
const isValid = await validateCardStructure(card);
|
||||
@@ -345,14 +351,14 @@ const fetchExistingCard = async () => {
|
||||
})
|
||||
);
|
||||
|
||||
// Step 4: Filter out invalid cards
|
||||
// Filter out invalid cards
|
||||
const validCards = validatedCards.filter(card => card !== null);
|
||||
|
||||
if (validCards.length > 0) {
|
||||
// Step 5: Sort by most recent timestamp
|
||||
// Sort by most recent timestamp
|
||||
const mostRecentCard = validCards.sort((a, b) => b.created - a.created)[0];
|
||||
|
||||
// Step 6: Fetch full card data
|
||||
// Fetch full card data
|
||||
const cardDataResponse = await qortalRequest({
|
||||
action: "FETCH_QDN_RESOURCE",
|
||||
name: userState.accountName, // User's account name
|
||||
@@ -490,7 +496,7 @@ const calculatePollResults = async (pollData, minterGroupMembers, minterAdmins)
|
||||
|
||||
for (const vote of pollData.votes) {
|
||||
const voterAddress = await getAddressFromPublicKey(vote.voterPublicKey)
|
||||
console.log(`voter address: ${voterAddress}`)
|
||||
// console.log(`voter address: ${voterAddress}`)
|
||||
|
||||
if (vote.optionIndex === 0) {
|
||||
adminAddresses.includes(voterAddress) ? adminYes++ : memberAddresses.includes(voterAddress) ? minterYes++ : console.log(`voter ${voterAddress} is not a minter nor an admin...Not including results...`)
|
||||
@@ -555,18 +561,19 @@ const postComment = async (cardIdentifier) => {
|
||||
//Fetch the comments for a card with passed card identifier ----------------------------
|
||||
const fetchCommentsForCard = async (cardIdentifier) => {
|
||||
try {
|
||||
const response = await qortalRequest({
|
||||
action: 'SEARCH_QDN_RESOURCES',
|
||||
service: 'BLOG_POST',
|
||||
query: `comment-${cardIdentifier}`,
|
||||
mode: "ALL"
|
||||
});
|
||||
return response;
|
||||
// const response = await qortalRequest({
|
||||
// action: 'SEARCH_QDN_RESOURCES',
|
||||
// service: 'BLOG_POST',
|
||||
// query: `comment-${cardIdentifier}`,
|
||||
// mode: "ALL"
|
||||
// })
|
||||
const response = await searchSimple('BLOG_POST',`comment-${cardIdentifier}`, '', 0)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error(`Error fetching comments for ${cardIdentifier}:`, error);
|
||||
return [];
|
||||
console.error(`Error fetching comments for ${cardIdentifier}:`, error)
|
||||
return []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// display the comments on the card, with passed cardIdentifier to identify the card --------------
|
||||
const displayComments = async (cardIdentifier) => {
|
||||
@@ -594,8 +601,7 @@ const displayComments = async (cardIdentifier) => {
|
||||
commentsContainer.insertAdjacentHTML('beforeend', commentHTML);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error displaying comments for ${cardIdentifier}:`, error);
|
||||
alert("Failed to load comments. Please try again.");
|
||||
console.error(`Error displaying comments (or no comments) for ${cardIdentifier}:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -624,12 +630,14 @@ const toggleComments = async (cardIdentifier) => {
|
||||
|
||||
const countComments = async (cardIdentifier) => {
|
||||
try {
|
||||
const response = await qortalRequest({
|
||||
action: 'SEARCH_QDN_RESOURCES',
|
||||
service: 'BLOG_POST',
|
||||
query: `comment-${cardIdentifier}`,
|
||||
mode: "ALL"
|
||||
});
|
||||
// const response = await qortalRequest({
|
||||
// action: 'SEARCH_QDN_RESOURCES',
|
||||
// service: 'BLOG_POST',
|
||||
// query: `comment-${cardIdentifier}`,
|
||||
// mode: "ALL"
|
||||
// })
|
||||
// Changed to searchSimple to hopefully improve load times...
|
||||
const response = await searchSimple('BLOG_POST', `comment-${cardIdentifier}`, '', 0)
|
||||
// Just return the count; no need to decrypt each comment here
|
||||
return Array.isArray(response) ? response.length : 0;
|
||||
} catch (error) {
|
||||
|
@@ -649,8 +649,8 @@ const generateAttachmentID = (room, fileIndex = null) => {
|
||||
|
||||
const findMessagePage = async (room, identifier, limit) => {
|
||||
const { service, query } = getServiceAndQuery(room)
|
||||
|
||||
const allMessages = await searchAllWithOffset(service, query, 0, 0, room)
|
||||
//TODO check that searchSimple change worked.
|
||||
const allMessages = await searchSimple(service, query, '', 0, 0, room, 'false')
|
||||
|
||||
const idx = allMessages.findIndex(msg => msg.identifier === identifier);
|
||||
if (idx === -1) {
|
||||
@@ -746,7 +746,8 @@ const getServiceAndQuery = (room) => {
|
||||
};
|
||||
|
||||
const fetchResourceList = async (service, query, limit, offset, room) => {
|
||||
return await searchAllWithOffset(service, query, limit, offset, room);
|
||||
//TODO check
|
||||
return await searchSimple(service, query, '', limit, offset, room, 'false');
|
||||
};
|
||||
|
||||
const handleNoMessagesScenario = (isPolling, page, response, messagesContainer) => {
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user