Skip to content

Commit 1fe0664

Browse files
committed
review and lint
1 parent 568a782 commit 1fe0664

File tree

5 files changed

+53
-24
lines changed

5 files changed

+53
-24
lines changed

src/dashboard/Data/Views/Views.react.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ class Views extends TableView {
695695
await this.viewPreferencesManager.saveViews(this.context.applicationId, this.state.views);
696696
} catch (error) {
697697
console.error('Failed to save views:', error);
698+
this.showNote('Failed to save view changes', true);
698699
}
699700
}
700701
this.loadViews(this.context);
@@ -729,6 +730,7 @@ class Views extends TableView {
729730
await this.viewPreferencesManager.saveViews(this.context.applicationId, this.state.views);
730731
} catch (error) {
731732
console.error('Failed to save views:', error);
733+
this.showNote('Failed to save view changes', true);
732734
}
733735
}
734736
this.loadViews(this.context);
@@ -755,6 +757,7 @@ class Views extends TableView {
755757
await this.viewPreferencesManager.saveViews(this.context.applicationId, this.state.views);
756758
} catch (error) {
757759
console.error('Failed to save views:', error);
760+
this.showNote('Failed to save view changes', true);
758761
}
759762
}
760763
if (this.props.params.name === name) {

src/dashboard/Settings/DashboardSettings/DashboardSettings.react.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export default class DashboardSettings extends DashboardView {
7878
if (this.viewPreferencesManager) {
7979
this.viewPreferencesManager.setStoragePreference(this.context.applicationId, preference);
8080
this.setState({ storagePreference: preference });
81-
81+
8282
// Show a notification about the change
8383
this.showNote(`Storage preference changed to ${preference === 'server' ? 'server' : 'browser'}`);
8484
}
@@ -90,7 +90,7 @@ export default class DashboardSettings extends DashboardView {
9090
return;
9191
}
9292

93-
if (!this.viewPreferencesManager.serverStorage.isServerConfigEnabled()) {
93+
if (!this.viewPreferencesManager.isServerConfigEnabled()) {
9494
this.showNote('Server configuration is not enabled for this app. Please add a "config" section to your app configuration.');
9595
return;
9696
}
@@ -114,6 +114,10 @@ export default class DashboardSettings extends DashboardView {
114114
}
115115

116116
async deleteFromBrowser() {
117+
if (!window.confirm('Are you sure you want to delete all dashboard settings from browser storage? This action cannot be undone.')) {
118+
return;
119+
}
120+
117121
if (!this.viewPreferencesManager) {
118122
this.showNote('ViewPreferencesManager not initialized');
119123
return;
@@ -457,7 +461,7 @@ export default class DashboardSettings extends DashboardView {
457461
}
458462
/>
459463
</Fieldset>
460-
{this.viewPreferencesManager && this.viewPreferencesManager.serverStorage.isServerConfigEnabled() && (
464+
{this.viewPreferencesManager && this.viewPreferencesManager.isServerConfigEnabled() && (
461465
<Fieldset legend="Settings Storage">
462466
<Field
463467
label={

src/lib/ServerConfigStorage.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export default class ServerConfigStorage {
1515
constructor(app) {
1616
this.app = app;
1717
this.className = app.config?.className || 'DashboardConfig';
18+
19+
// Validate className is a non-empty string
20+
if (typeof this.className !== 'string' || !this.className.trim()) {
21+
throw new Error('Invalid className for ServerConfigStorage');
22+
}
1823
}
1924

2025
/**
@@ -30,15 +35,15 @@ export default class ServerConfigStorage {
3035
const query = new Parse.Query(this.className);
3136
query.equalTo('appId', appId);
3237
query.equalTo('key', key);
33-
38+
3439
if (userId) {
3540
query.equalTo('user', new Parse.User({ objectId: userId }));
3641
} else {
3742
query.doesNotExist('user');
3843
}
3944

4045
let configObject = await query.first({ useMasterKey: true });
41-
46+
4247
// If no existing object found, create a new one
4348
if (!configObject) {
4449
configObject = new Parse.Object(this.className);
@@ -69,7 +74,7 @@ export default class ServerConfigStorage {
6974
const query = new Parse.Query(this.className);
7075
query.equalTo('appId', appId);
7176
query.equalTo('key', key);
72-
77+
7378
if (userId) {
7479
query.equalTo('user', new Parse.User({ objectId: userId }));
7580
} else {
@@ -95,7 +100,7 @@ export default class ServerConfigStorage {
95100
const query = new Parse.Query(this.className);
96101
query.equalTo('appId', appId);
97102
query.startsWith('key', keyPrefix);
98-
103+
99104
if (userId) {
100105
query.equalTo('user', new Parse.User({ objectId: userId }));
101106
} else {
@@ -104,7 +109,7 @@ export default class ServerConfigStorage {
104109

105110
const results = await query.find({ useMasterKey: true });
106111
const configs = {};
107-
112+
108113
results.forEach(result => {
109114
const key = result.get('key');
110115
const value = this._extractValue(result);
@@ -125,7 +130,7 @@ export default class ServerConfigStorage {
125130
const query = new Parse.Query(this.className);
126131
query.equalTo('appId', appId);
127132
query.equalTo('key', key);
128-
133+
129134
if (userId) {
130135
query.equalTo('user', new Parse.User({ objectId: userId }));
131136
} else {
@@ -143,7 +148,7 @@ export default class ServerConfigStorage {
143148
* @returns {boolean}
144149
*/
145150
isServerConfigEnabled() {
146-
return !!(this.app.config && this.app.config.className);
151+
return !!(this.app && this.app.config && this.app.config.className);
147152
}
148153

149154
/**

src/lib/StoragePreferences.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,19 @@ export function getStoragePreference(appId) {
4444
* @param {string} preference - The storage preference ('local' or 'server')
4545
*/
4646
export function setStoragePreference(appId, preference) {
47+
// Validate preference value
48+
if (!Object.values(STORAGE_TYPES).includes(preference)) {
49+
console.warn('Invalid storage preference:', preference);
50+
return;
51+
}
52+
4753
try {
4854
let preferences = {};
4955
const existing = localStorage.getItem(STORAGE_PREFERENCE_KEY);
5056
if (existing) {
5157
preferences = JSON.parse(existing);
5258
}
53-
59+
5460
preferences[appId] = preference;
5561
localStorage.setItem(STORAGE_PREFERENCE_KEY, JSON.stringify(preferences));
5662
} catch (error) {

src/lib/ViewPreferencesManager.js

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default class ViewPreferencesManager {
3838
return [];
3939
}
4040
}
41-
41+
4242
// Use local storage when server storage is not preferred
4343
return this._getViewsFromLocal(appId);
4444
}
@@ -59,7 +59,7 @@ export default class ViewPreferencesManager {
5959
// On error, fallback to local storage
6060
}
6161
}
62-
62+
6363
// Use local storage (either by preference or as fallback)
6464
return this._saveViewsToLocal(appId, views);
6565
}
@@ -121,6 +121,14 @@ export default class ViewPreferencesManager {
121121
return prefersServerStorage(appId) ? 'server' : 'local';
122122
}
123123

124+
/**
125+
* Checks if server configuration is enabled for this app
126+
* @returns {boolean} True if server config is enabled
127+
*/
128+
isServerConfigEnabled() {
129+
return this.serverStorage.isServerConfigEnabled();
130+
}
131+
124132
/**
125133
* Gets views from server storage
126134
* @private
@@ -129,30 +137,32 @@ export default class ViewPreferencesManager {
129137
try {
130138
const viewConfigs = await this.serverStorage.getConfigsByPrefix('views.view.', appId);
131139
const views = [];
132-
140+
133141
Object.entries(viewConfigs).forEach(([key, config]) => {
134142
if (config && typeof config === 'object') {
135143
// Extract view ID from key (views.view.{VIEW_ID})
136144
const viewId = key.replace('views.view.', '');
137-
145+
138146
// Parse the query if it's a string (it was stringified for storage)
139147
const viewConfig = { ...config };
140148
if (viewConfig.query && typeof viewConfig.query === 'string') {
141149
try {
142150
viewConfig.query = JSON.parse(viewConfig.query);
143151
} catch (e) {
144152
console.warn('Failed to parse view query from server storage:', e);
145-
// Keep as string if parsing fails
153+
console.error(`Skipping view ${viewId} due to corrupted query`);
154+
// Skip views with corrupted queries instead of keeping them as strings
155+
return;
146156
}
147157
}
148-
158+
149159
views.push({
150160
id: viewId,
151161
...viewConfig
152162
});
153163
}
154164
});
155-
165+
156166
return views;
157167
} catch (error) {
158168
console.error('Failed to get views from server:', error);
@@ -175,7 +185,7 @@ export default class ViewPreferencesManager {
175185
// Delete views that are no longer in the new views array
176186
const newViewIds = views.map(view => view.id || this._generateViewId(view));
177187
const viewsToDelete = existingViewIds.filter(id => !newViewIds.includes(id));
178-
188+
179189
await Promise.all(
180190
viewsToDelete.map(id =>
181191
this.serverStorage.deleteConfig(`views.view.${id}`, appId)
@@ -188,19 +198,19 @@ export default class ViewPreferencesManager {
188198
const viewId = view.id || this._generateViewId(view);
189199
const viewConfig = { ...view };
190200
delete viewConfig.id; // Don't store ID in the config itself
191-
201+
192202
// Remove null and undefined values to keep the storage clean
193203
Object.keys(viewConfig).forEach(key => {
194204
if (viewConfig[key] === null || viewConfig[key] === undefined) {
195205
delete viewConfig[key];
196206
}
197207
});
198-
208+
199209
// Stringify the query if it exists and is an array/object
200210
if (viewConfig.query && (Array.isArray(viewConfig.query) || typeof viewConfig.query === 'object')) {
201211
viewConfig.query = JSON.stringify(viewConfig.query);
202212
}
203-
213+
204214
return this.serverStorage.setConfig(
205215
`views.view.${viewId}`,
206216
viewConfig,
@@ -260,10 +270,11 @@ export default class ViewPreferencesManager {
260270
if (view.id) {
261271
return view.id;
262272
}
263-
// Generate a unique ID based on view name and timestamp
273+
// Generate a unique ID based on view name, timestamp, and random component
264274
const timestamp = Date.now().toString(36);
275+
const random = Math.random().toString(36).substr(2, 5);
265276
const nameHash = view.name ? view.name.replace(/[^a-zA-Z0-9]/g, '').toLowerCase() : 'view';
266-
return `${nameHash}_${timestamp}`;
277+
return `${nameHash}_${timestamp}_${random}`;
267278
}
268279
}
269280

0 commit comments

Comments
 (0)