feat: Make naming of library items discoverable (#10041)

* updated library relevant strings

* fix: detect name changes

* clarify hashing function

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
zsviczian
2025-09-30 20:38:10 +02:00
committed by GitHub
parent 7c41944856
commit fde796a7a0
4 changed files with 24 additions and 6 deletions

View File

@@ -29,6 +29,9 @@ export const hashElementsVersion = (elements: ElementsMapOrArray): number => {
// string hash function (using djb2). Not cryptographically secure, use only
// for versioning and such.
// note: hashes individual code units (not code points),
// but for hashing purposes this is fine as it iterates through every code unit
// (as such, no need to encode to byte string first)
export const hashString = (s: string): number => {
let hash: number = 5381;
for (let i = 0; i < s.length; i++) {

View File

@@ -518,7 +518,7 @@ const PublishLibrary = ({
</div>
<div className="publish-library__buttons">
<DialogActionButton
label={t("buttons.cancel")}
label={t("buttons.saveLibNames")}
onClick={onDialogClose}
data-testid="cancel-clear-canvas-button"
/>

View File

@@ -62,6 +62,7 @@ type LibraryUpdate = {
deletedItems: Map<LibraryItem["id"], LibraryItem>;
/** newly added items in the library */
addedItems: Map<LibraryItem["id"], LibraryItem>;
updatedItems: Map<LibraryItem["id"], LibraryItem>;
};
// an object so that we can later add more properties to it without breaking,
@@ -170,6 +171,7 @@ const createLibraryUpdate = (
const update: LibraryUpdate = {
deletedItems: new Map<LibraryItem["id"], LibraryItem>(),
addedItems: new Map<LibraryItem["id"], LibraryItem>(),
updatedItems: new Map<LibraryItem["id"], LibraryItem>(),
};
for (const item of prevLibraryItems) {
@@ -181,8 +183,11 @@ const createLibraryUpdate = (
const prevItemsMap = arrayToMap(prevLibraryItems);
for (const item of nextLibraryItems) {
if (!prevItemsMap.has(item.id)) {
const prevItem = prevItemsMap.get(item.id);
if (!prevItem) {
update.addedItems.set(item.id, item);
} else if (getLibraryItemHash(prevItem) !== getLibraryItemHash(item)) {
update.updatedItems.set(item.id, item);
}
}
@@ -586,12 +591,14 @@ class AdapterTransaction {
let lastSavedLibraryItemsHash = 0;
let librarySaveCounter = 0;
const getLibraryItemHash = (item: LibraryItem) => {
return `${item.id}:${item.name || ""}:${hashElementsVersion(item.elements)}`;
};
export const getLibraryItemsHash = (items: LibraryItems) => {
return hashString(
items
.map((item) => {
return `${item.id}:${hashElementsVersion(item.elements)}`;
})
.map((item) => getLibraryItemHash(item))
.sort()
.join(),
);
@@ -641,6 +648,13 @@ const persistLibraryUpdate = async (
}
}
// replace existing items with their updated versions
if (update.updatedItems) {
for (const [id, item] of update.updatedItems) {
nextLibraryItemsMap.set(id, item);
}
}
const nextLibraryItems = addedItems.concat(
Array.from(nextLibraryItemsMap.values()),
);

View File

@@ -230,10 +230,11 @@
"objectsSnapMode": "Snap to objects",
"exitZenMode": "Exit zen mode",
"cancel": "Cancel",
"saveLibNames": "Save name(s) and exit",
"clear": "Clear",
"remove": "Remove",
"embed": "Toggle embedding",
"publishLibrary": "Publish selected",
"publishLibrary": "Rename or publish",
"submit": "Submit",
"confirm": "Confirm",
"embeddableInteractionButton": "Click to interact"