Handle quota exceeded and running low on disk space errors while saving a key in localStorage (#2947)
This commit is contained in:
parent
a973d779fd
commit
2e72be0f8a
|
|
@ -1,3 +1,5 @@
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
|
|
||||||
export const CANVAS_DEFAULT_WIDTH_PX = 1242;
|
export const CANVAS_DEFAULT_WIDTH_PX = 1242;
|
||||||
export const CANVAS_DEFAULT_HEIGHT_PX = 1292;
|
export const CANVAS_DEFAULT_HEIGHT_PX = 1292;
|
||||||
export const CANVAS_DEFAULT_GRID_HEIGHT_PX = 1;
|
export const CANVAS_DEFAULT_GRID_HEIGHT_PX = 1;
|
||||||
|
|
@ -13,7 +15,7 @@ export const getAppStore = (appId: string) => {
|
||||||
const appStoreName = getAppStoreName(appId);
|
const appStoreName = getAppStoreName(appId);
|
||||||
let storeString = "{}";
|
let storeString = "{}";
|
||||||
// Check if localStorage exists
|
// Check if localStorage exists
|
||||||
if (localStorage) {
|
if (localStorage.isSupported()) {
|
||||||
const appStore = localStorage.getItem(appStoreName);
|
const appStore = localStorage.getItem(appStoreName);
|
||||||
if (appStore) storeString = appStore;
|
if (appStore) storeString = appStore;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,3 +177,8 @@ export const GOOGLE_RECAPTCHA_DOMAIN_ERROR =
|
||||||
export const SERVER_API_TIMEOUT_ERROR =
|
export const SERVER_API_TIMEOUT_ERROR =
|
||||||
"Appsmith server is taking too long to respond. Please try again after some time";
|
"Appsmith server is taking too long to respond. Please try again after some time";
|
||||||
export const DEFAULT_ERROR_MESSAGE = "There was an unexpected error";
|
export const DEFAULT_ERROR_MESSAGE = "There was an unexpected error";
|
||||||
|
|
||||||
|
export const LOCAL_STORAGE_QUOTA_EXCEEDED_MESSAGE =
|
||||||
|
"Error saving a key in localStorage. You have exceeded the allowed storage size limit";
|
||||||
|
export const LOCAL_STORAGE_NO_SPACE_LEFT_ON_DEVICE_MESSAGE =
|
||||||
|
"Error saving a key in localStorage. You have run out of disk space";
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import { connect } from "react-redux";
|
||||||
import { AppState } from "reducers";
|
import { AppState } from "reducers";
|
||||||
import { setThemeMode } from "actions/themeActions";
|
import { setThemeMode } from "actions/themeActions";
|
||||||
import { StyledToastContainer } from "components/ads/Toast";
|
import { StyledToastContainer } from "components/ads/Toast";
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
|
|
||||||
// enable autofreeze only in development
|
// enable autofreeze only in development
|
||||||
import { setAutoFreeze } from "immer";
|
import { setAutoFreeze } from "immer";
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,8 @@ import {
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import { EMPTY_RESPONSE } from "../components/editorComponents/ApiResponseView";
|
import { EMPTY_RESPONSE } from "../components/editorComponents/ApiResponseView";
|
||||||
|
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
|
|
||||||
export enum NavigationTargetType {
|
export enum NavigationTargetType {
|
||||||
SAME_WINDOW = "SAME_WINDOW",
|
SAME_WINDOW = "SAME_WINDOW",
|
||||||
NEW_WINDOW = "NEW_WINDOW",
|
NEW_WINDOW = "NEW_WINDOW",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { ReduxActionTypes, ReduxAction } from "constants/ReduxActionConstants";
|
import { ReduxActionTypes, ReduxAction } from "constants/ReduxActionConstants";
|
||||||
import { takeLatest } from "redux-saga/effects";
|
import { takeLatest } from "redux-saga/effects";
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
import { ThemeMode } from "../selectors/themeSelectors";
|
import { ThemeMode } from "../selectors/themeSelectors";
|
||||||
|
|
||||||
export function* setThemeSaga(actionPayload: ReduxAction<ThemeMode>) {
|
export function* setThemeSaga(actionPayload: ReduxAction<ThemeMode>) {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import PerformanceTracker, {
|
||||||
import { ERROR_CODES } from "constants/ApiConstants";
|
import { ERROR_CODES } from "constants/ApiConstants";
|
||||||
import { ANONYMOUS_USERNAME } from "constants/userConstants";
|
import { ANONYMOUS_USERNAME } from "constants/userConstants";
|
||||||
import { flushErrorsAndRedirect } from "actions/errorActions";
|
import { flushErrorsAndRedirect } from "actions/errorActions";
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
|
|
||||||
export function* createUserSaga(
|
export function* createUserSaga(
|
||||||
action: ReduxActionWithPromise<CreateUserRequest>,
|
action: ReduxActionWithPromise<CreateUserRequest>,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import produce from "immer";
|
||||||
import { AppIconCollection, AppIconName } from "components/ads/AppIcon";
|
import { AppIconCollection, AppIconName } from "components/ads/AppIcon";
|
||||||
import { ERROR_CODES } from "constants/ApiConstants";
|
import { ERROR_CODES } from "constants/ApiConstants";
|
||||||
import { ERROR_500 } from "../constants/messages";
|
import { ERROR_500 } from "../constants/messages";
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
|
|
||||||
export const createReducer = (
|
export const createReducer = (
|
||||||
initialState: any,
|
initialState: any,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { FeatureFlagConfig, FeatureFlagsEnum } from "configs/types";
|
import { FeatureFlagConfig, FeatureFlagsEnum } from "configs/types";
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
const optimizelySDK = require("@optimizely/optimizely-sdk");
|
const optimizelySDK = require("@optimizely/optimizely-sdk");
|
||||||
|
|
||||||
class FeatureFlag {
|
class FeatureFlag {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import localStorage from "utils/localStorage";
|
||||||
|
|
||||||
export function useLocalStorage(key: string, initialValue: string) {
|
export function useLocalStorage(key: string, initialValue: string) {
|
||||||
// State to store our value
|
// State to store our value
|
||||||
|
|
@ -6,7 +7,7 @@ export function useLocalStorage(key: string, initialValue: string) {
|
||||||
const [storedValue, setStoredValue] = useState(() => {
|
const [storedValue, setStoredValue] = useState(() => {
|
||||||
try {
|
try {
|
||||||
// Get from local storage by key
|
// Get from local storage by key
|
||||||
const item = window.localStorage.getItem(key);
|
const item = localStorage.getItem(key);
|
||||||
// Parse stored json or if none return initialValue
|
// Parse stored json or if none return initialValue
|
||||||
return item ? JSON.parse(item) : initialValue;
|
return item ? JSON.parse(item) : initialValue;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -26,7 +27,7 @@ export function useLocalStorage(key: string, initialValue: string) {
|
||||||
// Save state
|
// Save state
|
||||||
setStoredValue(valueToStore);
|
setStoredValue(valueToStore);
|
||||||
// Save to local storage
|
// Save to local storage
|
||||||
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// A more advanced implementation would handle the error case
|
// A more advanced implementation would handle the error case
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
|
||||||
66
app/client/src/utils/localStorage.tsx
Normal file
66
app/client/src/utils/localStorage.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { Variant } from "components/ads/common";
|
||||||
|
import { Toaster } from "components/ads/Toast";
|
||||||
|
import {
|
||||||
|
LOCAL_STORAGE_QUOTA_EXCEEDED_MESSAGE,
|
||||||
|
LOCAL_STORAGE_NO_SPACE_LEFT_ON_DEVICE_MESSAGE,
|
||||||
|
} from "constants/messages";
|
||||||
|
|
||||||
|
const getLocalStorage = () => {
|
||||||
|
const storage = window.localStorage;
|
||||||
|
|
||||||
|
const handleError = (e: Error) => {
|
||||||
|
let message;
|
||||||
|
if (e.name === "QuotaExceededError") {
|
||||||
|
message = LOCAL_STORAGE_QUOTA_EXCEEDED_MESSAGE;
|
||||||
|
} else if (e.name === "NS_ERROR_FILE_NO_DEVICE_SPACE") {
|
||||||
|
message = LOCAL_STORAGE_NO_SPACE_LEFT_ON_DEVICE_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message) {
|
||||||
|
Toaster.show({
|
||||||
|
text: message,
|
||||||
|
variant: Variant.danger,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getItem = (key: string): string | null => {
|
||||||
|
try {
|
||||||
|
return storage.getItem(key);
|
||||||
|
} catch (e) {
|
||||||
|
handleError(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setItem = (key: string, value: string) => {
|
||||||
|
try {
|
||||||
|
storage.setItem(key, value);
|
||||||
|
} catch (e) {
|
||||||
|
handleError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeItem = (key: string) => {
|
||||||
|
try {
|
||||||
|
storage.removeItem(key);
|
||||||
|
} catch (e) {
|
||||||
|
handleError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSupported = () => !!window.localStorage;
|
||||||
|
|
||||||
|
return {
|
||||||
|
getItem,
|
||||||
|
setItem,
|
||||||
|
removeItem,
|
||||||
|
isSupported,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const localStorage = getLocalStorage();
|
||||||
|
|
||||||
|
export default localStorage;
|
||||||
Loading…
Reference in New Issue
Block a user