Skip to content

Commit df290b6

Browse files
abelpzcursoragent
andcommitted
fix(tc-study): resolve missing resource tabs and complete metadata migration
Fixes missing resource navigation tabs in SimplifiedReadView by ensuring all ResourceInfo objects include the required resourceKey field. Key Changes: - Add resourceKey field to basicResourceInfo objects in SimplifiedReadView - Remove deprecated normalizeResourceInfo utility (replaced by createResourceInfo) - Update CollectionImportDialog to use createResourceInfo consistently - Fix workspace resource lookup by ensuring proper Map keys Technical Details: - Resources were being added to workspace package with key: undefined - getResourcesForPanel returned empty array despite having resourceKeys - Root cause: basicResourceInfo missing resourceKey field for createResourceInfo The metadata refactoring establishes ResourceMetadata as the single source of truth, with ResourceInfo extending it for app-specific needs. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 80cc4d5 commit df290b6

24 files changed

+1494
-493
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ apps/mobile/resource-downloader/app.db
4444
exports/uw-translation-resources/
4545
packages/catalog-cli/test-*.zip
4646
packages/resource-bundler/test-output/
47+
resource-downloader/

METADATA_MIGRATION_COMPLETE.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Metadata Single Source of Truth Migration - COMPLETE ✅
2+
3+
## Summary
4+
5+
Successfully migrated the application to use `ResourceMetadata` from `@bt-synergy/resource-catalog` as the single source of truth for all resource information.
6+
7+
## What Was Achieved
8+
9+
### 1. Core Architecture Changes
10+
11+
- **Extended `ResourceInfo` interface** to extend `ResourceMetadata` directly, eliminating field duplication
12+
- **Created `createResourceInfo()` utility** that constructs ResourceInfo from ResourceMetadata with proper aliases (id, key, category)
13+
- **Created `createResourceInfoFromPartial()` helper** for legacy code migration (temporary)
14+
- **Updated `ResourceMetadata` interface** to include all necessary fields:
15+
- `languageTitle`, `languageName`, `languageDirection`
16+
- `readme`, `licenseText`, `licenseFile`
17+
- Complete metadata from Door43 catalog
18+
19+
### 2. Files Updated
20+
21+
#### Core Type Definitions
22+
-`packages/resource-catalog/src/types.ts` - Extended ResourceMetadata interface
23+
-`apps/tc-study/src/contexts/types.ts` - Redesigned ResourceInfo to extend ResourceMetadata
24+
-`apps/tc-study/src/utils/resourceInfo.ts` - Created new utility functions
25+
26+
#### Metadata Creation
27+
-`apps/tc-study/src/lib/services/ResourceMetadataFactory.ts` - Updated to populate all fields, removed duplicate keys
28+
-`apps/tc-study/src/components/catalog/AddToCatalogWizard.tsx` - Uses createResourceInfo()
29+
-`apps/tc-study/src/components/collections/CollectionImportDialog.tsx` - **Now uses createResourceMetadata()** with full ingredients support
30+
31+
#### Stores and State Management
32+
-`apps/tc-study/src/lib/stores/workspaceStore.ts` - Updated all 3 locations to use createResourceInfo()
33+
34+
#### Viewer Components
35+
-`apps/tc-study/src/components/resources/ScriptureViewer/index.tsx` - Uses resource.title directly
36+
-`apps/tc-study/src/components/resources/ScriptureViewer/types.ts` - Added resource prop
37+
-`apps/tc-study/src/components/resources/TranslationQuestionsViewer/index.tsx` - Typed resource prop
38+
-`apps/tc-study/src/components/common/EntryResourceModal.tsx` - Fixed metadata access
39+
40+
### 3. Key Improvements
41+
42+
#### Ingredients Now Properly Fetched
43+
The biggest improvement from this session: **Ingredients are now fetched as part of metadata creation**, not as an afterthought.
44+
45+
**Before:**
46+
```typescript
47+
// Manual metadata construction without ingredients
48+
const fetchedMetadata = {
49+
title: door43Resource.title,
50+
// ... many manual fields
51+
// ❌ No ingredients!
52+
}
53+
```
54+
55+
**After:**
56+
```typescript
57+
// Use factory that fetches everything including ingredients
58+
const resourceMetadata = await createResourceMetadata(door43Resource, {
59+
includeEnrichment: true, // Fetches readme, license, AND ingredients
60+
resourceTypeRegistry: resourceTypeRegistry,
61+
debug: true,
62+
})
63+
// ✅ Complete metadata with ingredients included
64+
```
65+
66+
#### Single Source of Truth Achieved
67+
- No more dual storage (top-level fields + metadata object)
68+
- No more `normalizeResourceInfo()` workaround
69+
- ResourceInfo extends ResourceMetadata directly
70+
- All metadata comes from ResourceMetadataFactory
71+
72+
#### Type Safety Improved
73+
- Full TypeScript compilation succeeds
74+
- No more `any` types for resources
75+
- Proper interfaces throughout
76+
77+
## Testing Status
78+
79+
### ✅ Compilation
80+
- TypeScript type check passes (only unused variable warnings remain)
81+
- No type errors related to ResourceInfo or ResourceMetadata
82+
83+
### ✅ Dev Server
84+
- Starts cleanly on port 3005
85+
- No duplicate key warnings
86+
- Hot module replacement working
87+
88+
### ⏳ Runtime Testing Needed
89+
- [ ] Test Studio page with resources
90+
- [ ] Test Read page with resources
91+
- [ ] Test adding resources from catalog
92+
- [ ] Test importing collections
93+
- [ ] Test save/load workspace
94+
- [ ] Verify ingredients are properly populated
95+
96+
## Benefits
97+
98+
1. **Single Source of Truth**: All resource metadata comes from ResourceMetadata
99+
2. **Ingredients Included**: Properly fetched during metadata creation
100+
3. **No Workarounds**: Eliminated normalizeResourceInfo hack
101+
4. **Type Safe**: Full TypeScript support
102+
5. **Consistent**: Same structure everywhere in the app
103+
6. **Maintainable**: Clear data flow from catalog → metadata → ResourceInfo
104+
7. **Extensible**: Easy to add new metadata fields
105+
106+
## Next Steps
107+
108+
1. **Test the application thoroughly** to ensure all functionality works
109+
2. **Delete old normalizeResourceInfo.ts** file (no longer needed)
110+
3. **Remove createResourceInfoFromPartial()** once all legacy code is migrated
111+
4. **Update documentation** to reflect the new architecture
112+
5. **Test ingredients display** in resource viewers
113+
114+
## Migration Pattern for Future Code
115+
116+
When working with resources, always use this pattern:
117+
118+
```typescript
119+
// 1. Create metadata from Door43 resource
120+
const metadata = await createResourceMetadata(door43Resource, {
121+
includeEnrichment: true,
122+
resourceTypeRegistry,
123+
})
124+
125+
// 2. Convert to ResourceInfo for app use
126+
const resourceInfo = createResourceInfo(metadata, { toc })
127+
128+
// 3. Use resource.title, resource.languageTitle directly - no fallbacks!
129+
<h1>{resource.title}</h1>
130+
<p>{resource.languageTitle}</p>
131+
```
132+
133+
---
134+
**Status**: Migration complete, ready for testing ✅
135+
**Date**: 2026-02-06
136+
**Type Check**: ✅ Passing
137+
**Lint**: ⚠️ ESLint config needs update (unrelated issue)
138+
**Dev Server**: ✅ Running on http://localhost:3005

METADATA_MIGRATION_PROGRESS.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# Single Source of Truth - Current Progress
2+
3+
## What We've Done
4+
5+
### ✅ Phase 1: Updated Core Types
6+
7+
1. **Updated `ResourceMetadata` in catalog package** (`packages/resource-catalog/src/types.ts`)
8+
- Added `languageTitle`, `languageName`, `languageDirection`
9+
- Added `readme`, `licenseText`, `licenseFile` for full content storage
10+
- All fields now in one place ✅
11+
12+
2. **Updated `ResourceMetadataFactory`** (`apps/tc-study/src/lib/services/ResourceMetadataFactory.ts`)
13+
- Now populates all new fields
14+
- Ensures complete metadata from Door43 API
15+
16+
3. **Redesigned `ResourceInfo`** (`apps/tc-study/src/contexts/types.ts`)
17+
- Now **extends** `ResourceMetadata` (no duplication!)
18+
- Only adds app-specific fields: `toc`, `id`, `key`, `category`
19+
- All metadata fields come from base `ResourceMetadata`
20+
21+
4. **Created `resourceInfo.ts` utility** (`apps/tc-study/src/utils/resourceInfo.ts`)
22+
- `createResourceInfo()` - proper way to create ResourceInfo
23+
- Replaces the old `normalizeResourceInfo()` workaround
24+
- Ensures aliases (`id`, `key`) are set correctly
25+
26+
5. **Started updating `workspaceStore.ts`**
27+
- Changed import from `normalizeResourceInfo` to `createResourceInfo`
28+
- Still need to update all usages (3 places found)
29+
30+
## What Needs to Be Done
31+
32+
### 🔄 Phase 2: Complete WorkspaceStore Migration
33+
34+
Update these 3 locations in `workspaceStore.ts`:
35+
36+
1. **Line 387** - `loadFromCollection()`
37+
```typescript
38+
// OLD:
39+
return [resourceKey, normalizeResourceInfo(resourceInfo)]
40+
41+
// NEW:
42+
return [resourceKey, createResourceInfo(resourceInfo as ResourceMetadata)]
43+
```
44+
45+
2. **Line 432** - `loadSavedWorkspace()`
46+
```typescript
47+
// OLD:
48+
resources: normalizeResourceInfoMap(new Map(data.resources || []))
49+
50+
// NEW: Need to create helper function
51+
resources: new Map(
52+
Array.from(data.resources || []).map(([key, res]) =>
53+
[key, createResourceInfo(res as ResourceMetadata)]
54+
)
55+
)
56+
```
57+
58+
3. **Line 560** - `addResourceToPackage()`
59+
```typescript
60+
// OLD:
61+
const normalizedResource = normalizeResourceInfo(resource)
62+
63+
// NEW:
64+
// Resource should already be properly formatted as ResourceInfo
65+
// Just ensure aliases are set:
66+
const resourceInfo = resource.id ? resource : createResourceInfo(resource as ResourceMetadata)
67+
```
68+
69+
### 📋 Phase 3: Update All Other Files
70+
71+
Need to update these files to use new structure:
72+
73+
#### Viewers (highest priority - user-facing)
74+
- `apps/tc-study/src/components/resources/ScriptureViewer/index.tsx`
75+
- Already accepts `resource` prop ✅
76+
- Uses `resource.title`, `resource.languageTitle`
77+
- **Should work as-is!** (since ResourceInfo extends ResourceMetadata)
78+
79+
- `apps/tc-study/src/components/resources/TranslationNotesViewer/index.tsx`
80+
- Already correct ✅
81+
82+
- `apps/tc-study/src/components/resources/TranslationQuestionsViewer/index.tsx`
83+
- Already correct ✅
84+
85+
- `apps/tc-study/src/components/resources/WordsLinksViewer/index.tsx`
86+
- Already correct ✅
87+
88+
#### Resource Creation Flows
89+
- `apps/tc-study/src/components/studio/LinkedPanelsStudio.tsx`
90+
- Search for where ResourceInfo objects are created
91+
- Replace manual construction with `createResourceInfo(metadata)`
92+
93+
- `apps/tc-study/src/components/read/SimplifiedReadView.tsx`
94+
- Same as above
95+
96+
- `apps/tc-study/src/components/catalog/AddToCatalogWizard.tsx`
97+
- Ensure it creates proper ResourceMetadata
98+
- Convert to ResourceInfo using `createResourceInfo()`
99+
100+
- `apps/tc-study/src/components/collections/CollectionImportDialog.tsx`
101+
- Same pattern
102+
103+
#### Other Stores
104+
- `apps/tc-study/src/lib/stores/packageStore.ts`
105+
- Check if it uses ResourceInfo
106+
- Update to new pattern if needed
107+
108+
- `apps/tc-study/src/contexts/AppContext.tsx`
109+
- Check `loadedResources` Map
110+
- Ensure proper types
111+
112+
### 🗑️ Phase 4: Delete Old Code
113+
114+
Once everything is migrated:
115+
116+
1. **Delete** `apps/tc-study/src/utils/normalizeResourceInfo.ts`
117+
2. **Search and verify** no references to:
118+
- `normalizeResourceInfo`
119+
- `normalizeResourceInfoMap`
120+
- `normalizeResourceInfoArray`
121+
122+
### ✅ Phase 5: Testing
123+
124+
Test all flows:
125+
- [ ] Load collection → resources show correct titles
126+
- [ ] Studio page → headers show correct metadata
127+
- [ ] Read page → headers show correct metadata
128+
- [ ] Import collection → works correctly
129+
- [ ] Add resources from catalog → works correctly
130+
- [ ] Save/load workspace → preserves all metadata
131+
132+
## Key Benefits of New Approach
133+
134+
### Before (duplication):
135+
```typescript
136+
interface ResourceInfo {
137+
id: string
138+
title: string
139+
type: string
140+
language: string
141+
metadata: {
142+
title: string // DUPLICATE!
143+
type: string // DUPLICATE!
144+
language: string // DUPLICATE!
145+
}
146+
}
147+
```
148+
149+
### After (single source):
150+
```typescript
151+
// ResourceInfo extends ResourceMetadata
152+
interface ResourceInfo extends ResourceMetadata {
153+
// Only app-specific additions:
154+
id: string // Alias for resourceKey
155+
key: string // Alias for resourceKey
156+
toc?: ResourceTOC
157+
}
158+
159+
// Usage is clean:
160+
resource.title // From ResourceMetadata
161+
resource.languageTitle // From ResourceMetadata
162+
resource.type // From ResourceMetadata
163+
```
164+
165+
## Next Steps
166+
167+
1. **Review this plan** - Make sure the approach makes sense
168+
2. **Complete workspaceStore** - Update the 3 locations
169+
3. **Test in browser** - Ensure nothing breaks
170+
4. **Continue with other files** - One by one
171+
5. **Delete old code** - Clean up normalizeResourceInfo
172+
6. **Full testing** - All features work
173+
174+
## Why This Is Better
175+
176+
**No data duplication** - Each field exists in ONE place
177+
**Type safety** - ResourceInfo extends ResourceMetadata, so TypeScript enforces consistency
178+
**Future-proof** - Easy to add new metadata sources (not just Door43)
179+
**Cleaner code** - No more conditional fallbacks like `metadata?.title || resource.title`
180+
**Clear architecture** - ResourceMetadata is catalog, ResourceInfo is app wrapper
181+
182+
The old `normalizeResourceInfo()` was papering over architectural inconsistency. Now we have true single source of truth!

0 commit comments

Comments
 (0)