mirror of
https://github.com/fleetbase/fleetbase.git
synced 2026-02-14 20:54:09 +00:00
Compare commits
3 Commits
cloud
...
dev-v0.7.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dccd1b6883 | ||
|
|
5e69a7d443 | ||
|
|
3dc5b9b015 |
@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { isArray } from '@ember/array';
|
||||
import { debug } from '@ember/debug';
|
||||
import { storageFor } from 'ember-local-storage';
|
||||
import { add, isPast } from 'date-fns';
|
||||
import { task } from 'ember-concurrency';
|
||||
|
||||
@@ -6,20 +6,110 @@ const KEYS_INDEX = `${CONTEXT_PREFIX}__keys__`;
|
||||
|
||||
export default class OnboardingContextService extends Service {
|
||||
@service appCache;
|
||||
@service notifications;
|
||||
@tracked data = {};
|
||||
@tracked quotaExceeded = false;
|
||||
@tracked usingMemoryFallback = false;
|
||||
|
||||
// In-memory fallback storage for when localStorage is full
|
||||
_memoryCache = new Map();
|
||||
|
||||
/**
|
||||
* Safe wrapper for appCache.set with quota error handling
|
||||
*
|
||||
* @param {string} key - The key to set
|
||||
* @param {*} value - The value to store
|
||||
* @returns {Object} Result object with success status and storage type
|
||||
*/
|
||||
_safeSet(key, value) {
|
||||
try {
|
||||
this.appCache.set(key, value);
|
||||
return { success: true, storage: 'localStorage' };
|
||||
} catch (error) {
|
||||
if (this._isQuotaError(error)) {
|
||||
console.warn(`[OnboardingContext] localStorage quota exceeded, using memory fallback for key: ${key}`);
|
||||
|
||||
// Store in memory as fallback
|
||||
this._memoryCache.set(key, value);
|
||||
|
||||
// Mark that we're using fallback and notify user (only once)
|
||||
if (!this.quotaExceeded) {
|
||||
this.quotaExceeded = true;
|
||||
this.usingMemoryFallback = true;
|
||||
this._notifyUser();
|
||||
}
|
||||
|
||||
return { success: true, storage: 'memory', warning: 'Using memory fallback' };
|
||||
}
|
||||
|
||||
// Re-throw non-quota errors
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe wrapper for appCache.get with memory fallback
|
||||
*
|
||||
* @param {string} key - The key to retrieve
|
||||
* @returns {*} The stored value or undefined
|
||||
*/
|
||||
_safeGet(key) {
|
||||
try {
|
||||
const value = this.appCache.get(key);
|
||||
if (value !== undefined) {
|
||||
return value;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`[OnboardingContext] Error reading from appCache: ${error.message}`);
|
||||
}
|
||||
|
||||
// Fallback to memory cache
|
||||
return this._memoryCache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if error is a quota exceeded error
|
||||
*
|
||||
* @param {Error} error - The error to check
|
||||
* @returns {boolean} True if it's a quota error
|
||||
*/
|
||||
_isQuotaError(error) {
|
||||
return (
|
||||
error instanceof DOMException &&
|
||||
(error.code === 22 ||
|
||||
error.code === 1014 ||
|
||||
error.name === 'QuotaExceededError' ||
|
||||
error.name === 'NS_ERROR_DOM_QUOTA_REACHED')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify user about storage issues (only called once)
|
||||
*/
|
||||
_notifyUser() {
|
||||
if (this.notifications) {
|
||||
this.notifications.warning(
|
||||
'Your browser storage is full. Your onboarding progress will be saved temporarily but may be lost if you close this tab. Please complete the onboarding process in this session.',
|
||||
{
|
||||
timeout: 10000,
|
||||
clearDuration: 300
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from in-memory state first, then fallback to cache
|
||||
*/
|
||||
get(key) {
|
||||
return this.data[key] ?? this.appCache.get(`${CONTEXT_PREFIX}${key}`);
|
||||
return this.data[key] ?? this._safeGet(`${CONTEXT_PREFIX}${key}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value directly from cache
|
||||
*/
|
||||
getFromCache(key) {
|
||||
return this.appCache.get(`${CONTEXT_PREFIX}${key}`);
|
||||
return this._safeGet(`${CONTEXT_PREFIX}${key}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,11 +118,11 @@ export default class OnboardingContextService extends Service {
|
||||
* @returns {Object}
|
||||
*/
|
||||
restore() {
|
||||
const keys = this.appCache.get(KEYS_INDEX) ?? [];
|
||||
const keys = this._safeGet(KEYS_INDEX) ?? [];
|
||||
const persisted = {};
|
||||
|
||||
for (const key of keys) {
|
||||
const value = this.appCache.get(`${CONTEXT_PREFIX}${key}`);
|
||||
const value = this._safeGet(`${CONTEXT_PREFIX}${key}`);
|
||||
if (value !== undefined) {
|
||||
persisted[key] = value;
|
||||
}
|
||||
@@ -63,14 +153,14 @@ export default class OnboardingContextService extends Service {
|
||||
this.data = { ...this.data, ...filteredData };
|
||||
|
||||
if (options.persist === true) {
|
||||
const keys = new Set(this.appCache.get(KEYS_INDEX) ?? []);
|
||||
const keys = new Set(this._safeGet(KEYS_INDEX) ?? []);
|
||||
|
||||
for (const key of Object.keys(filteredData)) {
|
||||
keys.add(key);
|
||||
this.appCache.set(`${CONTEXT_PREFIX}${key}`, this.data[key]);
|
||||
this._safeSet(`${CONTEXT_PREFIX}${key}`, this.data[key]);
|
||||
}
|
||||
|
||||
this.appCache.set(KEYS_INDEX, [...keys]);
|
||||
this._safeSet(KEYS_INDEX, [...keys]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,11 +178,11 @@ export default class OnboardingContextService extends Service {
|
||||
this.data = { ...this.data, [key]: value };
|
||||
|
||||
if (options.persist === true) {
|
||||
const keys = new Set(this.appCache.get(KEYS_INDEX) ?? []);
|
||||
const keys = new Set(this._safeGet(KEYS_INDEX) ?? []);
|
||||
keys.add(key);
|
||||
|
||||
this.appCache.set(`${CONTEXT_PREFIX}${key}`, value);
|
||||
this.appCache.set(KEYS_INDEX, [...keys]);
|
||||
this._safeSet(`${CONTEXT_PREFIX}${key}`, value);
|
||||
this._safeSet(KEYS_INDEX, [...keys]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,24 +200,44 @@ export default class OnboardingContextService extends Service {
|
||||
const { [key]: _removed, ...rest } = this.data; // eslint-disable-line no-unused-vars
|
||||
this.data = rest;
|
||||
|
||||
const keys = new Set(this.appCache.get(KEYS_INDEX) ?? []);
|
||||
const keys = new Set(this._safeGet(KEYS_INDEX) ?? []);
|
||||
keys.delete(key);
|
||||
|
||||
this.appCache.set(`${CONTEXT_PREFIX}${key}`, undefined);
|
||||
this.appCache.set(KEYS_INDEX, [...keys]);
|
||||
this._safeSet(`${CONTEXT_PREFIX}${key}`, undefined);
|
||||
this._safeSet(KEYS_INDEX, [...keys]);
|
||||
|
||||
// Also remove from memory cache
|
||||
this._memoryCache.delete(`${CONTEXT_PREFIX}${key}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully reset onboarding context (memory + persistence)
|
||||
*/
|
||||
reset() {
|
||||
const keys = this.appCache.get(KEYS_INDEX) ?? [];
|
||||
const keys = this._safeGet(KEYS_INDEX) ?? [];
|
||||
|
||||
for (const key of keys) {
|
||||
this.appCache.set(`${CONTEXT_PREFIX}${key}`, undefined);
|
||||
this._safeSet(`${CONTEXT_PREFIX}${key}`, undefined);
|
||||
this._memoryCache.delete(`${CONTEXT_PREFIX}${key}`);
|
||||
}
|
||||
|
||||
this.appCache.set(KEYS_INDEX, []);
|
||||
this._safeSet(KEYS_INDEX, []);
|
||||
this._memoryCache.clear();
|
||||
this.data = {};
|
||||
this.quotaExceeded = false;
|
||||
this.usingMemoryFallback = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage status for debugging
|
||||
*
|
||||
* @returns {Object} Storage status information
|
||||
*/
|
||||
getStorageStatus() {
|
||||
return {
|
||||
quotaExceeded: this.quotaExceeded,
|
||||
usingMemoryFallback: this.usingMemoryFallback,
|
||||
memoryItemCount: this._memoryCache.size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Submodule packages/ember-core updated: f7d8e3a754...c0c1941b98
Submodule packages/ember-ui updated: ddabb466c2...379d0a7921
Reference in New Issue
Block a user