Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix storage quota bug #489

Merged
merged 20 commits into from
Apr 4, 2024
Merged

Fix storage quota bug #489

merged 20 commits into from
Apr 4, 2024

Conversation

Pete-Y-CS
Copy link
Contributor

No description provided.

@Pete-Y-CS
Copy link
Contributor Author

Ahh just remembered you wanted us to display the amount of memory used, let me add that now

@dabreegster
Copy link
Contributor

And is a playwright test possible?

@Pete-Y-CS
Copy link
Contributor Author

image
image

I tried to add a breaking length string in playwright and it timed out. Maybe there's another way but I think it would be easier with unit rather than functional tests.

Peter York and others added 2 commits March 28, 2024 14:59
window.alert doesn't seem to reliably appear, so try a Modal instead
@dabreegster
Copy link
Contributor

Not sure why a 1MB file is necessary for a test when we can do "x".repeat(123). Also don't think we need to force a browser to deal with 5MB in a form. We can just set some unused local storage key directly. I started a test in 7168bab. But the window.alerts appear to be quite flaky both in playwright and manually; they mostly haven't appeared for me, which is weird, because I thought window.alert is supposed to be blocking. What if we try a Modal instead and just have this handling in the sketch tool for now?

@robinlovelace-ate
Copy link
Contributor

Looks like a tricky one, happy to test locally if you guys want a second pair of eyes on it.

} catch (error: any) {
// Unfortunately it looks like we can't use typeof or instanceof to determine this one:
// all we get is that it's an object so if someone changess the wording we may have to add new checks
const isStorageQuotaError =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd vote for getting rid of all of this logic entirely to simplify things. Catch any exception and assume it's a quota problem. What other exceptions might be thrown? In Firefox, the message is different:
image

export function clearLocalStorage() {
window.localStorage.clear();
}
export function clearLocalStorageItem(key: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return type here. But actually, it might be simpler to not try and return this here. Export getStoredStrings and call it from the modal. After clicking a button to clear something, over in the modal code, call the function again to refresh the list.

Then we don't need getEmptySetStorageErrorObject or maybe even the setLocalStorageItem wrapper at all. Just call the regular API, catch any error, launch the modal

@@ -0,0 +1,77 @@
const storageQuotaErrorMessage =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The screenfull of text is a bit overwhelming:
image
I'm going to make some wording suggestions below

@@ -0,0 +1,77 @@
const storageQuotaErrorMessage =
"Unable to save because the local storage quota has been exceeded: you may need to clear out your web browser's local storage for this app, or run in private mode before you can save again. Specific error here: ";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd vote to move this to the modal. We don't need to console.log it, it's user-facing

{#if storedStringDescriptor.key === currentAuthority}
<p><WarningIcon text={"warning icon"} />This is the current sketch.</p>
{/if}
<SecondaryButton on:click={removeStorageItem(storedStringDescriptor.key)}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you do () => removeStorageItem(key) then we don't need the weird indirection of returning a closure. Most Svelte examples make the closure here in the event handler

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an obvious trick I'm sure I've learned before that slipped my brain, thanks

Be sure that you're not losing anything important before doing this!
</p>
<WarningButton on:click={clearLocalStorageAndCloseModal}>
Delete All Sketch Data From Browser
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't capitalize every word

<p>Stored object: {storedStringDescriptor.key}</p>
<p>
Storage used (rounded to nearest 0.01MB): {storedStringDescriptor.storageUsedInMB
.toString()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slice is weird -- toFixed(2)?

Otherwise here is a breakdown of what is currently stored locally. You can
delete individual items (normally storage quota is 5mb or 10mb):
</p>
{#each setStorageError.storedStrings as storedStringDescriptor}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be useful to show these from largest to smallest

return results;
}

function getLengthInMB(text: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return type, and you don't need the intermediate variable. Every intermediate var is something that needs a name and takes mental overhead to understand when reading

}

function getStoredStrings(): StoredStringDescriptor[] {
const itemsObject = { ...localStorage };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete individual items (normally storage quota is 5mb or 10mb):
</p>
{#each setStorageError.storedStrings as storedStringDescriptor}
<p>Stored object: {storedStringDescriptor.key}</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is repetitive and visually confusing with a bunch of keys. Why not just have a bunch of buttons, keep the key in there, and add (123MB) at the end or something?

Copy link
Contributor

@dabreegster dabreegster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorted buttons feel much nicer, thanks! Still some open comments about simplifying the wording

<SecondaryButton
on:click={() => removeStorageItem(storedStringDescriptor.key)}
>
Remove stored item for {storedStringDescriptor.key}({storedStringDescriptor.storageUsedInMB}MB)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.toFixed(2) on the number would look nicer and I think match the old slice previously

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, did this at first then it got lost in refactor of how we're displaying this! Good spot!

window.localStorage.setItem("huge", "x".repeat(4.999 * 1024 * 1024)),
);

await page.goto("/index.html?schema=pipeline");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could just go directly to the scheme page with the right query, to speed up the test. We test navigating from the homepage in other test cases, and local storage shouldn't really affect that

const storageQuotaErrorMessage =
"Unable to save because the local storage quota has been exceeded: you may need to clear out your web browser's local storage for this app, or run in private mode before you can save again. Specific error here: ";

export interface SetStorageErrorObject {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We maybe don't really need this, the empty object method, or setLocalStorageItem. The caller in FileManagement could call localStorage.setItem directly, catch the exception, and trigger the modal when appropriate. We could export the method to summarize current local storage items, and make the modal call it again after clearing/removing an item. But up to you

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in teams, I think it's plasuible we'd want to share this in the future and I prefer smaller files so I'd prefer to leave it this way.

@Pete-Y-CS Pete-Y-CS merged commit b70cd47 into main Apr 4, 2024
2 checks passed
@Pete-Y-CS Pete-Y-CS deleted the fix-storage-quota-bug branch April 4, 2024 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants