@@ -109,6 +109,28 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
109109 // Data
110110 // ---------------------------------------------------------------------------
111111
112+ /**
113+ * Normalize an API response to an array.
114+ * Chronicle endpoints may return a plain array or an object wrapping
115+ * the array under common keys like `data`, `entity_types`, `entities`,
116+ * `maps`, etc. This helper unwraps whichever shape we get.
117+ * @param {* } raw - The raw parsed JSON from the API.
118+ * @param {...string } keys - Object keys to try (in order) if raw is not an array.
119+ * @returns {Array }
120+ * @private
121+ */
122+ _normalizeArray ( raw , ...keys ) {
123+ if ( Array . isArray ( raw ) ) return raw ;
124+ if ( raw && typeof raw === 'object' ) {
125+ for ( const key of keys ) {
126+ if ( Array . isArray ( raw [ key ] ) ) return raw [ key ] ;
127+ }
128+ // Last resort: try the generic `data` wrapper.
129+ if ( Array . isArray ( raw . data ) ) return raw . data ;
130+ }
131+ return [ ] ;
132+ }
133+
112134 /** @override */
113135 async _prepareContext ( options = { } ) {
114136 if ( ! this . _syncManager || ! this . api ) {
@@ -117,6 +139,7 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
117139
118140 this . _loading = true ;
119141 const exclusions = this . _getExclusions ( ) ;
142+ const loadErrors = [ ] ;
120143
121144 // Build entity tab data.
122145 let entityGroups = [ ] ;
@@ -126,6 +149,7 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
126149 foundryOnlyJournals = this . _getFoundryOnlyJournals ( ) ;
127150 } catch ( err ) {
128151 console . error ( 'Chronicle Dashboard: Failed to load entities' , err ) ;
152+ loadErrors . push ( { tab : 'entities' , message : err . message || 'Failed to load entities' } ) ;
129153 }
130154
131155 // Build map tab data.
@@ -134,6 +158,7 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
134158 mapData = await this . _buildMapData ( ) ;
135159 } catch ( err ) {
136160 console . error ( 'Chronicle Dashboard: Failed to load maps' , err ) ;
161+ loadErrors . push ( { tab : 'maps' , message : err . message || 'Failed to load maps' } ) ;
137162 }
138163
139164 // Build shops tab data.
@@ -142,6 +167,7 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
142167 shopData = await this . _buildShopData ( ) ;
143168 } catch ( err ) {
144169 console . error ( 'Chronicle Dashboard: Failed to load shops' , err ) ;
170+ loadErrors . push ( { tab : 'shops' , message : err . message || 'Failed to load shops' } ) ;
145171 }
146172
147173 // Build calendar tab data.
@@ -150,6 +176,7 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
150176 calendarData = await this . _buildCalendarData ( ) ;
151177 } catch ( err ) {
152178 console . error ( 'Chronicle Dashboard: Failed to load calendar' , err ) ;
179+ loadErrors . push ( { tab : 'calendar' , message : err . message || 'Failed to load calendar' } ) ;
153180 }
154181
155182 // Build status tab data.
@@ -168,6 +195,8 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
168195 loading : false ,
169196 searchFilter : this . _searchFilter ,
170197 activeTab : this . _activeTab ,
198+ loadErrors,
199+ hasLoadErrors : loadErrors . length > 0 ,
171200
172201 // Config tab.
173202 config : configData ,
@@ -209,7 +238,7 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
209238 // Fetch entity types from Chronicle.
210239 if ( ! this . _cache . entityTypes ) {
211240 const raw = await this . api . get ( '/entity-types' ) ;
212- this . _cache . entityTypes = Array . isArray ( raw ) ? raw : ( raw ?. data || raw ?. entity_types || [ ] ) ;
241+ this . _cache . entityTypes = this . _normalizeArray ( raw , ' entity_types' ) ;
213242 }
214243 const types = this . _cache . entityTypes ;
215244
@@ -220,8 +249,8 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
220249 let hasMore = true ;
221250 while ( hasMore && page <= 5 ) {
222251 const result = await this . api . get ( `/entities?per_page=100&page=${ page } ` ) ;
223- const entities = result ?. entities || result || [ ] ;
224- if ( Array . isArray ( entities ) && entities . length > 0 ) {
252+ const entities = this . _normalizeArray ( result , 'entities' ) ;
253+ if ( entities . length > 0 ) {
225254 allEntities . push ( ...entities ) ;
226255 hasMore = entities . length === 100 ;
227256 page ++ ;
@@ -346,9 +375,10 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
346375 async _buildMapData ( ) {
347376 // Fetch Chronicle maps.
348377 if ( ! this . _cache . maps ) {
349- this . _cache . maps = await this . api . get ( '/maps' ) . catch ( ( ) => [ ] ) ;
378+ const raw = await this . api . get ( '/maps' ) . catch ( ( ) => [ ] ) ;
379+ this . _cache . maps = this . _normalizeArray ( raw , 'maps' ) ;
350380 }
351- const chronicles = this . _cache . maps || [ ] ;
381+ const chronicles = this . _cache . maps ;
352382
353383 // Index Foundry scenes by linked mapId.
354384 const scenesByMapId = new Map ( ) ;
@@ -397,7 +427,7 @@ export class SyncDashboard extends HandlebarsApplicationMixin(ApplicationV2) {
397427 // Ensure entity types are cached.
398428 if ( ! this . _cache . entityTypes ) {
399429 const raw = await this . api . get ( '/entity-types' ) ;
400- this . _cache . entityTypes = Array . isArray ( raw ) ? raw : ( raw ?. data || raw ?. entity_types || [ ] ) ;
430+ this . _cache . entityTypes = this . _normalizeArray ( raw , ' entity_types' ) ;
401431 }
402432 const types = this . _cache . entityTypes ;
403433
0 commit comments