mirror of
https://github.com/Dvorinka/Trackeep.git
synced 2026-10-28 08:01:15 +00:00
refactor: unify docker deployment and restructure frontend architecture
This commit implements a unified Docker deployment strategy, moving from separate frontend and backend images to a single, multi-stage build image containing both services. It also introduces a major reorganization of the frontend directory structure and simplifies the environment configuration. Key changes: - **Deployment**: Added a multi-stage `Dockerfile` and `docker-entrypoint.sh` to package the Go backend and Nginx-served frontend into a single container. - **CI/CD**: Updated GitHub Actions workflows (`ci-cd.yml`, `release.yml`) to build and push the new unified image instead of separate ones. - **Frontend Refactor**: Reorganized `frontend/src/pages` into a domain-driven directory structure (e.g., `auth/`, `admin/`, `content/`, `communication/`, `productivity/`, `settings/`, `misc/`). - **Configuration**: Simplified `.env.example` and updated `docker-compose.yml` to reflect the unified service model and single host port. - **Cleanup**: Removed deprecated `docker-compose.demo.yml`, `docker-compose.prod.yml`, and various unused frontend components and services. - **Backend**: Refactored configuration loading to use exported `GetDurationEnv` for better consistency.
This commit is contained in:
1 parent
c6a99c7e21
commit
6c448b336a
71 files changed
+135367
-4481
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
{"files": {"code": ["/home/tdvorak/Desktop/PROG+HTML/Trackeep/browser-extension/background.js", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/browser-extension/popup.js", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/browser-extension/options.js", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/browser-extension/youtube-content.js", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/browser-extension/browser-polyfill.js", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/index.ts", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/App.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/types.ts", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/MainTabs.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/TasksScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/NotesScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/SettingsScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/WebAppScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/FilesScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/ConnectionSetupScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/TimeEntriesScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/screens/AuthScreen.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/components/UI.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/context/AppContext.tsx", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/lib/format.ts", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/lib/api.ts", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/lib/url.ts", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/mobile/src/lib/share.ts", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/main.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/seed.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/examples/user_service_example.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/tools/favicon_cli.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/youtube_channels.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/message_detector.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/youtube_cache.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/favicon_fetcher.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/performance.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/ai_recommendation_service.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/metadata.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/favicon_fetcher_test.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/youtube.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/ai_service.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/computer_vision_service.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/messages_realtime.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/video_bookmark.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/youtube_integrated.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/services/message_detector_test.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/ai_features.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/search_settings.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/community.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/audit_log.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/note.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/user.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/web_scraping.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/task.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/knowledge_base.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/teams.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/analytics.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/bookmark.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/messages.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/learning_path.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/file.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/browser_extension.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/chat.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/tag.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/github_user_auth.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/youtube_cache.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/goals_habits.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/integration.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/models.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/backend/models/file_analysis.go", "/home/tdvorak/Desktop/PROG+HTML/Trackeep/bLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
/usr/bin/python3
|
||||
@@ -0,0 +1 @@
|
||||
/home/tdvorak/Desktop/PROG+HTML/Trackeep
|
||||
@@ -0,0 +1,619 @@
|
||||
# Graph Report - Trackeep (2026-04-30)
|
||||
|
||||
## Corpus Check
|
||||
- 330 files · ~395,125 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 2549 nodes · 3694 edges · 99 communities detected
|
||||
- Extraction: 85% EXTRACTED · 15% INFERRED · 0% AMBIGUOUS · INFERRED: 562 edges (avg confidence: 0.8)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
- [[_COMMUNITY_Community 0|Community 0]]
|
||||
- [[_COMMUNITY_Community 1|Community 1]]
|
||||
- [[_COMMUNITY_Community 2|Community 2]]
|
||||
- [[_COMMUNITY_Community 3|Community 3]]
|
||||
- [[_COMMUNITY_Community 4|Community 4]]
|
||||
- [[_COMMUNITY_Community 5|Community 5]]
|
||||
- [[_COMMUNITY_Community 6|Community 6]]
|
||||
- [[_COMMUNITY_Community 7|Community 7]]
|
||||
- [[_COMMUNITY_Community 8|Community 8]]
|
||||
- [[_COMMUNITY_Community 9|Community 9]]
|
||||
- [[_COMMUNITY_Community 10|Community 10]]
|
||||
- [[_COMMUNITY_Community 11|Community 11]]
|
||||
- [[_COMMUNITY_Community 12|Community 12]]
|
||||
- [[_COMMUNITY_Community 13|Community 13]]
|
||||
- [[_COMMUNITY_Community 14|Community 14]]
|
||||
- [[_COMMUNITY_Community 15|Community 15]]
|
||||
- [[_COMMUNITY_Community 16|Community 16]]
|
||||
- [[_COMMUNITY_Community 17|Community 17]]
|
||||
- [[_COMMUNITY_Community 18|Community 18]]
|
||||
- [[_COMMUNITY_Community 19|Community 19]]
|
||||
- [[_COMMUNITY_Community 20|Community 20]]
|
||||
- [[_COMMUNITY_Community 21|Community 21]]
|
||||
- [[_COMMUNITY_Community 22|Community 22]]
|
||||
- [[_COMMUNITY_Community 23|Community 23]]
|
||||
- [[_COMMUNITY_Community 24|Community 24]]
|
||||
- [[_COMMUNITY_Community 25|Community 25]]
|
||||
- [[_COMMUNITY_Community 26|Community 26]]
|
||||
- [[_COMMUNITY_Community 27|Community 27]]
|
||||
- [[_COMMUNITY_Community 28|Community 28]]
|
||||
- [[_COMMUNITY_Community 29|Community 29]]
|
||||
- [[_COMMUNITY_Community 30|Community 30]]
|
||||
- [[_COMMUNITY_Community 31|Community 31]]
|
||||
- [[_COMMUNITY_Community 32|Community 32]]
|
||||
- [[_COMMUNITY_Community 33|Community 33]]
|
||||
- [[_COMMUNITY_Community 34|Community 34]]
|
||||
- [[_COMMUNITY_Community 35|Community 35]]
|
||||
- [[_COMMUNITY_Community 36|Community 36]]
|
||||
- [[_COMMUNITY_Community 37|Community 37]]
|
||||
- [[_COMMUNITY_Community 38|Community 38]]
|
||||
- [[_COMMUNITY_Community 39|Community 39]]
|
||||
- [[_COMMUNITY_Community 40|Community 40]]
|
||||
- [[_COMMUNITY_Community 41|Community 41]]
|
||||
- [[_COMMUNITY_Community 42|Community 42]]
|
||||
- [[_COMMUNITY_Community 43|Community 43]]
|
||||
- [[_COMMUNITY_Community 44|Community 44]]
|
||||
- [[_COMMUNITY_Community 45|Community 45]]
|
||||
- [[_COMMUNITY_Community 46|Community 46]]
|
||||
- [[_COMMUNITY_Community 47|Community 47]]
|
||||
- [[_COMMUNITY_Community 48|Community 48]]
|
||||
- [[_COMMUNITY_Community 49|Community 49]]
|
||||
- [[_COMMUNITY_Community 50|Community 50]]
|
||||
- [[_COMMUNITY_Community 51|Community 51]]
|
||||
- [[_COMMUNITY_Community 52|Community 52]]
|
||||
- [[_COMMUNITY_Community 53|Community 53]]
|
||||
- [[_COMMUNITY_Community 54|Community 54]]
|
||||
- [[_COMMUNITY_Community 55|Community 55]]
|
||||
- [[_COMMUNITY_Community 56|Community 56]]
|
||||
- [[_COMMUNITY_Community 57|Community 57]]
|
||||
- [[_COMMUNITY_Community 58|Community 58]]
|
||||
- [[_COMMUNITY_Community 60|Community 60]]
|
||||
- [[_COMMUNITY_Community 61|Community 61]]
|
||||
- [[_COMMUNITY_Community 62|Community 62]]
|
||||
- [[_COMMUNITY_Community 63|Community 63]]
|
||||
- [[_COMMUNITY_Community 64|Community 64]]
|
||||
- [[_COMMUNITY_Community 66|Community 66]]
|
||||
- [[_COMMUNITY_Community 67|Community 67]]
|
||||
- [[_COMMUNITY_Community 68|Community 68]]
|
||||
- [[_COMMUNITY_Community 69|Community 69]]
|
||||
- [[_COMMUNITY_Community 70|Community 70]]
|
||||
- [[_COMMUNITY_Community 71|Community 71]]
|
||||
- [[_COMMUNITY_Community 74|Community 74]]
|
||||
- [[_COMMUNITY_Community 75|Community 75]]
|
||||
- [[_COMMUNITY_Community 77|Community 77]]
|
||||
- [[_COMMUNITY_Community 79|Community 79]]
|
||||
- [[_COMMUNITY_Community 81|Community 81]]
|
||||
- [[_COMMUNITY_Community 83|Community 83]]
|
||||
- [[_COMMUNITY_Community 86|Community 86]]
|
||||
- [[_COMMUNITY_Community 87|Community 87]]
|
||||
- [[_COMMUNITY_Community 95|Community 95]]
|
||||
- [[_COMMUNITY_Community 96|Community 96]]
|
||||
- [[_COMMUNITY_Community 97|Community 97]]
|
||||
- [[_COMMUNITY_Community 99|Community 99]]
|
||||
- [[_COMMUNITY_Community 101|Community 101]]
|
||||
- [[_COMMUNITY_Community 102|Community 102]]
|
||||
- [[_COMMUNITY_Community 103|Community 103]]
|
||||
- [[_COMMUNITY_Community 104|Community 104]]
|
||||
- [[_COMMUNITY_Community 105|Community 105]]
|
||||
- [[_COMMUNITY_Community 106|Community 106]]
|
||||
- [[_COMMUNITY_Community 112|Community 112]]
|
||||
- [[_COMMUNITY_Community 119|Community 119]]
|
||||
- [[_COMMUNITY_Community 120|Community 120]]
|
||||
- [[_COMMUNITY_Community 130|Community 130]]
|
||||
- [[_COMMUNITY_Community 131|Community 131]]
|
||||
- [[_COMMUNITY_Community 132|Community 132]]
|
||||
- [[_COMMUNITY_Community 133|Community 133]]
|
||||
- [[_COMMUNITY_Community 134|Community 134]]
|
||||
- [[_COMMUNITY_Community 135|Community 135]]
|
||||
- [[_COMMUNITY_Community 136|Community 136]]
|
||||
- [[_COMMUNITY_Community 138|Community 138]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `GetDB()` - 95 edges
|
||||
2. `New()` - 50 edges
|
||||
3. `contains()` - 42 edges
|
||||
4. `main()` - 41 edges
|
||||
5. `toLower()` - 34 edges
|
||||
6. `demoFetch()` - 32 edges
|
||||
7. `Queries` - 28 edges
|
||||
8. `IntegrationHandler` - 26 edges
|
||||
9. `setError()` - 25 edges
|
||||
10. `getAuthUserID()` - 24 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `createTask()` --calls--> `setError()` [INFERRED]
|
||||
mobile/src/screens/TasksScreen.tsx → desktop/src/main.js
|
||||
- `toggleTaskStatus()` --calls--> `setError()` [INFERRED]
|
||||
mobile/src/screens/TasksScreen.tsx → desktop/src/main.js
|
||||
- `deleteTask()` --calls--> `setError()` [INFERRED]
|
||||
mobile/src/screens/TasksScreen.tsx → desktop/src/main.js
|
||||
- `startEntry()` --calls--> `setError()` [INFERRED]
|
||||
mobile/src/screens/TimeEntriesScreen.tsx → desktop/src/main.js
|
||||
- `stopEntry()` --calls--> `setError()` [INFERRED]
|
||||
mobile/src/screens/TimeEntriesScreen.tsx → desktop/src/main.js
|
||||
|
||||
## Communities
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.03
|
||||
Nodes (147): DB, NewDB(), centralizedOAuthUser, buildControlServiceCallbackURL(), buildControlServiceGitHubStartURL(), buildGitHubAppInstallCallbackURL(), clearControlServiceAuthFlowState(), controlServiceClient() (+139 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.02
|
||||
Nodes (74): applySmartSuggestions(), detectAndApplySmartData(), handleQuickSave(), hideMessage(), saveBookmark(), setButtonLoading(), showMessage(), uploadFile() (+66 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.03
|
||||
Nodes (62): handleDemoMode(), ProtectedRoute(), DemoStatus(), Header(), getAuthHeaders(), isDemoMode(), useAuth(), DemoModeApiClient (+54 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.02
|
||||
Nodes (53): initializeDragonflyDB(), main(), AppConfig, Config, getDurationEnv(), getEnvWithDefault(), Load(), DatabaseConfig (+45 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.03
|
||||
Nodes (84): SeedData(), GetDB(), AdminDeleteLearningPath(), AdminGetAllLearningPaths(), AdminGetStats(), AdminGetUsers(), AdminMiddleware(), AdminReviewLearningPath() (+76 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.05
|
||||
Nodes (78): AddConversationMemberRequest, AdminCreateUser(), AttachmentInput, conversationListItem, CreateConversationRequest, CreateMessageRequest, CreateReactionRequest, CreateVaultItemRequest (+70 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.04
|
||||
Nodes (46): AcceptTaskSuggestion(), buildTaskContext(), generateAIContent(), generateAISummary(), GenerateContent(), GenerateTagSuggestions(), generateTaskSuggestions(), GetAIProviders() (+38 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.05
|
||||
Nodes (45): disableTOTP(), enableTOTP(), fetchTOTPStatus(), getAuthHeaders(), regenerateBackupCodes(), setupTOTP(), verifyBackupCode(), verifyTOTPCode() (+37 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.07
|
||||
Nodes (60): Ae(), ar(), at(), Bt(), children(), cr(), Ct(), de() (+52 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.04
|
||||
Nodes (50): GetAISettings(), getDefaultAISettings(), isMasked(), UpdateAISettings(), AISettings, AuthMiddleware(), ChangePassword(), CheckUsers() (+42 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.05
|
||||
Nodes (33): GetChannelVideos(), GetFireshipVideos(), GetNetworkChuckVideos(), GetYouTubeChannelVideosFromURL(), GetYouTubeTrending(), SearchYouTube(), YouTubeSearchTest(), YouTubeChannelRequest (+25 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.05
|
||||
Nodes (27): downloadUpdate(), containsMaliciousContent(), InputValidationMiddleware(), sanitizeInput(), ValidateRequestBody(), generateMemoryCacheKey(), InvalidateMemoryCache(), MemoryCacheInvalidationMiddleware() (+19 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.06
|
||||
Nodes (28): initializeSecuritySecrets(), GenerateAPIKey(), generateRandomString(), createFileShareRequest, buildPublicShareURL(), CreateFileShare(), determineFileType(), generateSecureShareToken() (+20 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.08
|
||||
Nodes (41): getControlServiceTokenForUser(), CreateEncryptedNote(), DecryptNoteContent(), determineFileTypeForEncryption(), DownloadEncryptedFile(), EncryptNoteContent(), generateRandomStringForFile(), GetEncryptedNote() (+33 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.06
|
||||
Nodes (18): InitDatabase(), shouldRunLegacySQLMigrations(), InitLogger(), Logger(), logPerformanceEvent(), logRequestBody(), logSecurityEvent(), PerformanceLogger() (+10 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.1
|
||||
Nodes (24): getApiOrigin(), getApiV1BaseUrl(), trimApiSuffix(), trimTrailingSlash(), getAuthCallbackUrl(), startGitHubSignIn(), backupSelectedRepositories(), checkGitHubConnection() (+16 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.07
|
||||
Nodes (12): calculateFocusScore(), NewAnalyticsHandler(), AnalyticsHandler, getIntValue(), getStringValue(), logSearchAnalytics(), min(), performEnhancedSearch() (+4 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.1
|
||||
Nodes (23): progressWriter, UpdateRequest, backupUserData(), broadcastProgress(), CheckForUpdates(), checkForUpdatesWithDocker(), checkForUpdatesWithDockerRegistry(), copyDirectory() (+15 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.1
|
||||
Nodes (25): BraveNewsResponse, BraveSearchResponse, BraveSearchResult, SearchNews(), SearchWeb(), getBoolEnvWithDefault(), getDefaultSearchSettings(), getEnvWithDefault() (+17 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.07
|
||||
Nodes (2): DBTX, Queries
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.11
|
||||
Nodes (6): NewAIRecommendationHandler(), AIRecommendationHandler, NewAIRecommendationService(), AIRecommendationService, RecommendationRequest, RecommendationScore
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.11
|
||||
Nodes (10): BoundingBox, ComputerVisionService, DocumentAnalysis, DocumentSection, DocumentTable, FaceDetection, ImageAnalysisRequest, ImageAnalysisResponse (+2 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.09
|
||||
Nodes (6): NewVideoBookmarkHandler(), VideoBookmarkHandler, SaveVideoRequest, NewVideoBookmarkService(), VideoBookmarkService, VideoInfo
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.13
|
||||
Nodes (1): IntegrationHandler
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.09
|
||||
Nodes (5): adaptBookmarkFromApi(), editBookmark(), handleAddBookmark(), handleEditBookmark(), handleSubmit()
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.11
|
||||
Nodes (10): handlePageChange(), stats(), storagePercentage(), taskCompletionRate(), totalPages(), weeklyActivityTotal(), handleRefresh(), loadStats() (+2 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.16
|
||||
Nodes (11): containsString(), GetAllFavicons(), GetFavicon(), NewFaviconFetcher(), BenchmarkFaviconFetch(), TestExtractHeadSection(), TestFaviconFetcher(), TestMakeAbsoluteURL() (+3 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.13
|
||||
Nodes (7): fetchWithAuth(), getAuthToken(), handleBackupSelectedRepos(), handleInstallGitHubApp(), loadFiles(), loadGitHubBackupWorkspace(), parseRepoPayload()
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.1
|
||||
Nodes (12): Challenge, ChallengeMilestone, ChallengeMilestoneCompletion, ChallengeParticipant, ChallengeResource, ChallengeTag, ChallengeTeam, Mentorship (+4 more)
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.16
|
||||
Nodes (14): getAuthHeaders(), getQuickSearchSuggestions(), searchBrave(), searchNews(), searchWeb(), extractVideoId(), getVideoInfo(), handleKeyPress() (+6 more)
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.11
|
||||
Nodes (3): looksLikeYouTube(), saveBookmark(), submitManualShare()
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.13
|
||||
Nodes (10): hexToHsl(), isChatOpen(), toggleChat(), applyCustomColors(), applyScheme(), resetColors(), toggleDarkMode(), updateSchemesForTheme() (+2 more)
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.11
|
||||
Nodes (9): Analytics, AnalyticsReport, ContentAnalytics, GitHubAnalytics, Goal, HabitAnalytics, LearningAnalytics, Milestone (+1 more)
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.18
|
||||
Nodes (17): GenerateEmbeddingRequest, GenerateEmbeddingResponse, buildSemanticSearchResult(), compactSemanticText(), cosineSimilarity(), findSimilarContent(), GenerateEmbedding(), generateHighlights() (+9 more)
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.12
|
||||
Nodes (16): DiscordConfig, GitHubConfig, GoogleConfig, Integration, IntegrationConfig, IntegrationStatus, IntegrationType, NotionConfig (+8 more)
|
||||
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.12
|
||||
Nodes (3): calculateMatchScore(), NewCommunityHandler(), CommunityHandler
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.13
|
||||
Nodes (4): Metrics, copyDurationMap(), copyMap(), GetMetrics()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.12
|
||||
Nodes (6): isSupported(), triggerHaptic(), useHaptics(), Messages(), Profile(), Button()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.2
|
||||
Nodes (10): completeSetup(), generateApiKey(), saveSettings(), setButtonLoading(), showConnectionStatus(), showMessage(), showSetupConnectionStatus(), testConnection() (+2 more)
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.12
|
||||
Nodes (2): NewGoalsHabitsHandler(), GoalsHabitsHandler
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.12
|
||||
Nodes (2): NewMarketplaceHandler(), MarketplaceHandler
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.19
|
||||
Nodes (8): generateCalendarDays(), getCellClass(), getDateClass(), getDaysInMonth(), getFirstDayOfMonth(), isDateEnd(), isDateInRange(), isDateStart()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.23
|
||||
Nodes (11): closeCreateWorkspaceModal(), createDefaultWorkspace(), getAuthToken(), getWorkspaceIcon(), handleCreateWorkspace(), handleWorkspaceSelect(), loadWorkspaces(), normalizeWorkspace() (+3 more)
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 0.27
|
||||
Nodes (14): cleanupHistory(), detectContentType(), getTrackeepConfig(), getYouTubeHistory(), openPopupWithContext(), parseResponseError(), parseYouTubeVideoMeta(), saveYouTubeBookmark() (+6 more)
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.13
|
||||
Nodes (1): Validator
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.2
|
||||
Nodes (9): Category, estimateReadingTime(), generateSlug(), Template, TemplateVariable, WikiAttachment, WikiBacklink, WikiPage (+1 more)
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 0.19
|
||||
Nodes (6): generateId(), getFileExtension(), handleDrop(), handleFileSelect(), handleUrlImport(), simulateUpload()
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 0.17
|
||||
Nodes (6): GoalTag, GoalTemplate, GoalTemplateMilestone, Habit, HabitEntry, HabitTag
|
||||
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 0.17
|
||||
Nodes (2): canUpload(), isValidUrl()
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 0.24
|
||||
Nodes (8): handleHexChange(), handleMouseMove(), handleSavedColorClick(), handleSliderMouseDown(), hexToHSL(), hslToHex(), updateColorFromHue(), updateHueFromPosition()
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 0.22
|
||||
Nodes (6): fetchSessions(), getProviderFromModel(), getToken(), handleSendMessage(), loadSessionMessages(), scrollToHighlightedMessage()
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
Cohesion: 0.17
|
||||
Nodes (11): Team, TeamActivity, TeamBookmark, TeamFile, TeamInvitation, TeamMember, TeamNote, TeamProject (+3 more)
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
Cohesion: 0.17
|
||||
Nodes (11): AuditLog, Bookmark, BookmarkTag, File, FileTag, Note, NoteTag, Tag (+3 more)
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 0.2
|
||||
Nodes (6): ContentShare, generateShareToken(), MarketplaceItem, MarketplacePurchase, MarketplaceReview, MarketplaceTag
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.18
|
||||
Nodes (10): AddTaskTagParams, CreateTaskParams, DeleteTaskParams, GetTaskByIDParams, GetTasksByStatusParams, GetTasksByTagParams, GetTasksByUserParams, RemoveTaskTagParams (+2 more)
|
||||
|
||||
### Community 55 - "Community 55"
|
||||
Cohesion: 0.22
|
||||
Nodes (4): getMockCalendarEvents(), createEvent(), fetchCalendarData(), toggleEventCompletion()
|
||||
|
||||
### Community 56 - "Community 56"
|
||||
Cohesion: 0.2
|
||||
Nodes (3): CalendarEvent, CalendarSettings, RecurrenceRule
|
||||
|
||||
### Community 57 - "Community 57"
|
||||
Cohesion: 0.2
|
||||
Nodes (9): AddBookmarkTagParams, CreateBookmarkParams, DeleteBookmarkParams, GetBookmarkByIDParams, GetBookmarksByTagParams, GetBookmarksByUserParams, RemoveBookmarkTagParams, SearchBookmarksParams (+1 more)
|
||||
|
||||
### Community 58 - "Community 58"
|
||||
Cohesion: 0.33
|
||||
Nodes (6): getToken(), handleAddMember(), handleDeleteMember(), loadMembers(), onWorkspaceChanged(), resolveWorkspaceId()
|
||||
|
||||
### Community 60 - "Community 60"
|
||||
Cohesion: 0.31
|
||||
Nodes (4): apiRequest(), getToken(), MessagesRealtimeClient, uploadChatFile()
|
||||
|
||||
### Community 61 - "Community 61"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): AIRecommendation, RecommendationInteraction, UserPreference
|
||||
|
||||
### Community 62 - "Community 62"
|
||||
Cohesion: 0.22
|
||||
Nodes (8): CreateUserParams, CreateUserRow, GetUserByEmailRow, GetUserByIDRow, ListUsersParams, ListUsersRow, UpdateUserParams, UpdateUserRow
|
||||
|
||||
### Community 63 - "Community 63"
|
||||
Cohesion: 0.46
|
||||
Nodes (7): closePrompt(), detectAndNotify(), escapeHtml(), initDetection(), parseYouTubeVideo(), renderPrompt(), sendMessage()
|
||||
|
||||
### Community 64 - "Community 64"
|
||||
Cohesion: 0.25
|
||||
Nodes (5): ScrapedContent, ScrapedImage, ScrapedLink, ScrapedVideo, ScrapingJob
|
||||
|
||||
### Community 66 - "Community 66"
|
||||
Cohesion: 0.48
|
||||
Nodes (5): buildShareDraft(), firstCandidateTitleFromText(), firstUrlFromText(), normalizeUrl(), titleFromUrl()
|
||||
|
||||
### Community 67 - "Community 67"
|
||||
Cohesion: 0.29
|
||||
Nodes (1): UserServiceExample
|
||||
|
||||
### Community 68 - "Community 68"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): AICodeReview, AIContentGeneration, AILearningRecommendation, AISummary, AITagSuggestion, AITaskSuggestion
|
||||
|
||||
### Community 69 - "Community 69"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): Follow, Project, ProjectTag, Skill, SocialLink, UserProfileStats
|
||||
|
||||
### Community 70 - "Community 70"
|
||||
Cohesion: 0.33
|
||||
Nodes (1): TimeEntry
|
||||
|
||||
### Community 71 - "Community 71"
|
||||
Cohesion: 0.29
|
||||
Nodes (5): ContentEmbedding, SavedSearch, SavedSearchTag, SearchAnalytics, SearchSuggestion
|
||||
|
||||
### Community 74 - "Community 74"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): importData(), ExportImport()
|
||||
|
||||
### Community 75 - "Community 75"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): callAIAPI(), handleSendMessage()
|
||||
|
||||
### Community 77 - "Community 77"
|
||||
Cohesion: 0.33
|
||||
Nodes (5): Enrollment, LearningModule, LearningPath, ModuleResource, Progress
|
||||
|
||||
### Community 79 - "Community 79"
|
||||
Cohesion: 0.53
|
||||
Nodes (4): addTag(), filteredTags(), handleInputKeyDown(), removeTag()
|
||||
|
||||
### Community 81 - "Community 81"
|
||||
Cohesion: 0.47
|
||||
Nodes (3): CodeBlock(), inferCodeLanguage(), normalizeCodeLanguage()
|
||||
|
||||
### Community 83 - "Community 83"
|
||||
Cohesion: 0.6
|
||||
Nodes (5): breakDownDuration(), formatDuration(), formatDurationDetailed(), formatDurationShort(), getLargestTimeUnit()
|
||||
|
||||
### Community 86 - "Community 86"
|
||||
Cohesion: 0.4
|
||||
Nodes (1): GracefulShutdown
|
||||
|
||||
### Community 87 - "Community 87"
|
||||
Cohesion: 0.4
|
||||
Nodes (1): ErrorResponse
|
||||
|
||||
### Community 95 - "Community 95"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): YouTubeChannelCache
|
||||
|
||||
### Community 96 - "Community 96"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): FileAnalysis
|
||||
|
||||
### Community 97 - "Community 97"
|
||||
Cohesion: 0.5
|
||||
Nodes (3): GitHubAppInstallation, GitHubAppInstallState, GitHubRepoBackup
|
||||
|
||||
### Community 99 - "Community 99"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): handleSubmit(), resetForm()
|
||||
|
||||
### Community 101 - "Community 101"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): File, FileType
|
||||
|
||||
### Community 102 - "Community 102"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): APIKey, BrowserExtension
|
||||
|
||||
### Community 103 - "Community 103"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): ChatMessage, ChatSession
|
||||
|
||||
### Community 104 - "Community 104"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): VideoBookmark
|
||||
|
||||
### Community 105 - "Community 105"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): Course, LearningPathCourse
|
||||
|
||||
### Community 106 - "Community 106"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): ProductionConfig
|
||||
|
||||
### Community 112 - "Community 112"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): extractVideoId(), handleSubmit()
|
||||
|
||||
### Community 119 - "Community 119"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): handleKeyPress(), handleSendMessage()
|
||||
|
||||
### Community 120 - "Community 120"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): handleKeyPress(), handleSendMessage()
|
||||
|
||||
### Community 130 - "Community 130"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Note
|
||||
|
||||
### Community 131 - "Community 131"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): User
|
||||
|
||||
### Community 132 - "Community 132"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Bookmark
|
||||
|
||||
### Community 133 - "Community 133"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Tag
|
||||
|
||||
### Community 134 - "Community 134"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): GitHubUserAuth
|
||||
|
||||
### Community 135 - "Community 135"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): ControlServiceSession
|
||||
|
||||
### Community 136 - "Community 136"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): UserAISettings
|
||||
|
||||
### Community 138 - "Community 138"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): Querier
|
||||
|
||||
## Knowledge Gaps
|
||||
- **290 isolated node(s):** `Channel`, `ChannelInfo`, `DetectedSuggestion`, `DetectedAttachment`, `CacheEntry` (+285 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **Thin community `Community 19`** (30 nodes): `db.go`, `DBTX`, `Queries`, `.AddBookmarkTag()`, `.AddTaskTag()`, `.CreateBookmark()`, `.CreateTask()`, `.CreateUser()`, `.DeleteBookmark()`, `.DeleteTask()`, `.DeleteUser()`, `.GetBookmarkByID()`, `.GetBookmarksByTag()`, `.GetBookmarksByUser()`, `.GetTaskByID()`, `.GetTasksByStatus()`, `.GetTasksByTag()`, `.GetTasksByUser()`, `.GetUserByEmail()`, `.GetUserByID()`, `.ListUsers()`, `.RemoveBookmarkTag()`, `.RemoveTaskTag()`, `.SearchBookmarks()`, `.SearchTasks()`, `.UpdateBookmark()`, `.UpdateLastLogin()`, `.UpdateTask()`, `.UpdateUser()`, `.WithTx()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 23`** (26 nodes): `IntegrationHandler`, `.AuthorizeIntegration()`, `.CreateIntegration()`, `.DeleteIntegration()`, `.exchangeDiscordCode()`, `.exchangeGitHubCode()`, `.exchangeGoogleCode()`, `.exchangeNotionCode()`, `.exchangeSlackCode()`, `.getDiscordAuthURL()`, `.getGitHubAuthURL()`, `.getGoogleAuthURL()`, `.GetIntegration()`, `.GetIntegrations()`, `.getNotionAuthURL()`, `.getSlackAuthURL()`, `.GetSyncLogs()`, `.OAuthCallback()`, `.performSync()`, `.syncDiscord()`, `.syncGitHub()`, `.syncGoogle()`, `.SyncIntegration()`, `.syncNotion()`, `.syncSlack()`, `.UpdateIntegration()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 39`** (16 nodes): `goals_habits.go`, `NewGoalsHabitsHandler()`, `GoalsHabitsHandler`, `.CreateGoal()`, `.CreateHabit()`, `.CreateHabitEntry()`, `.DeleteGoal()`, `.DeleteHabit()`, `.GetDashboardStats()`, `.GetGoal()`, `.GetGoals()`, `.GetHabit()`, `.GetHabitEntries()`, `.GetHabits()`, `.UpdateGoal()`, `.UpdateHabit()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 40`** (16 nodes): `marketplace.go`, `NewMarketplaceHandler()`, `MarketplaceHandler`, `.CreateContentShare()`, `.CreateMarketplaceItem()`, `.CreateMarketplaceReview()`, `.DeleteContentShare()`, `.DeleteMarketplaceItem()`, `.GetContentShare()`, `.GetMarketplaceItem()`, `.GetMarketplaceItems()`, `.GetMarketplaceReviews()`, `.GetMarketplaceStats()`, `.GetMyContentShares()`, `.GetMyMarketplaceItems()`, `.UpdateMarketplaceItem()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 44`** (15 nodes): `validator.go`, `Validator`, `.Clear()`, `.Email()`, `.GetError()`, `.GetErrors()`, `.HasErrors()`, `.In()`, `.Match()`, `.MaxLength()`, `.MinLength()`, `NewValidator()`, `.Required()`, `.URL()`, `.ValidatePassword()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 48`** (13 nodes): `FileUploadModal.tsx`, `addAssociation()`, `addTag()`, `canUpload()`, `getFileIcon()`, `handleDrag()`, `handleDrop()`, `handleFileSelect()`, `handleKeyDown()`, `handleUpload()`, `isValidUrl()`, `removeAssociation()`, `removeTag()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 67`** (7 nodes): `user_service_example.go`, `NewUserServiceExample()`, `UserServiceExample`, `.CreateUserExample()`, `.GetUserExample()`, `.SearchUsersExample()`, `.TransactionExample()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 70`** (7 nodes): `time_entry.go`, `TimeEntry`, `.BeforeCreate()`, `.BeforeUpdate()`, `.GetDuration()`, `.GetFormattedDuration()`, `.Stop()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 74`** (7 nodes): `ExportImport.tsx`, `export-import.ts`, `exportData()`, `getImportSummary()`, `importData()`, `validateImportData()`, `ExportImport()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 75`** (7 nodes): `AIChat.tsx`, `callAIAPI()`, `checkMobile()`, `handleClickOutside()`, `handleSendMessage()`, `initializeAIModels()`, `startNewChat()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 86`** (5 nodes): `graceful_shutdown.go`, `NewGracefulShutdown()`, `GracefulShutdown`, `.AddCleanupFunc()`, `.Wait()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 87`** (5 nodes): `error_handler.go`, `ErrorHandlerMiddleware()`, `MethodNotAllowedHandler()`, `NotFoundHandler()`, `ErrorResponse`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 95`** (4 nodes): `youtube_cache.go`, `YouTubeChannelCache`, `.IsExpired()`, `.TableName()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 96`** (4 nodes): `file_analysis.go`, `FileAnalysis`, `.BeforeCreate()`, `.TableName()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 99`** (4 nodes): `LearningPathModal.tsx`, `handleInputChange()`, `handleSubmit()`, `resetForm()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 101`** (3 nodes): `file.go`, `File`, `FileType`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 102`** (3 nodes): `browser_extension.go`, `APIKey`, `BrowserExtension`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 103`** (3 nodes): `chat.go`, `ChatMessage`, `ChatSession`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 104`** (3 nodes): `video_bookmark.go`, `VideoBookmark`, `.TableName()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 105`** (3 nodes): `course.go`, `Course`, `LearningPathCourse`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 106`** (3 nodes): `production.go`, `DefaultProductionConfig()`, `ProductionConfig`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 112`** (3 nodes): `VideoUploadModal.tsx`, `extractVideoId()`, `handleSubmit()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 119`** (3 nodes): `FloatingAI.tsx`, `handleKeyPress()`, `handleSendMessage()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 120`** (3 nodes): `AIChatPanel.tsx`, `handleKeyPress()`, `handleSendMessage()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 130`** (2 nodes): `note.go`, `Note`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 131`** (2 nodes): `user.go`, `User`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 132`** (2 nodes): `bookmark.go`, `Bookmark`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 133`** (2 nodes): `tag.go`, `Tag`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 134`** (2 nodes): `github_user_auth.go`, `GitHubUserAuth`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 135`** (2 nodes): `control_service_auth.go`, `ControlServiceSession`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 136`** (2 nodes): `ai_settings.go`, `UserAISettings`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 138`** (2 nodes): `querier.go`, `Querier`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `GetDB()` connect `Community 4` to `Community 0`, `Community 33`, `Community 1`, `Community 3`, `Community 5`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 22`?**
|
||||
_High betweenness centrality (0.165) - this node is a cross-community bridge._
|
||||
- **Why does `main()` connect `Community 3` to `Community 1`, `Community 35`, `Community 4`, `Community 39`, `Community 40`, `Community 9`, `Community 11`, `Community 12`, `Community 14`, `Community 16`, `Community 20`, `Community 22`?**
|
||||
_High betweenness centrality (0.149) - this node is a cross-community bridge._
|
||||
- **Why does `contains()` connect `Community 1` to `Community 0`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 17`, `Community 21`, `Community 26`?**
|
||||
_High betweenness centrality (0.117) - this node is a cross-community bridge._
|
||||
- **Are the 94 inferred relationships involving `GetDB()` (e.g. with `main()` and `SeedData()`) actually correct?**
|
||||
_`GetDB()` has 94 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 49 inferred relationships involving `New()` (e.g. with `InitLogger()` and `applySuggestionAction()`) actually correct?**
|
||||
_`New()` has 49 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 40 inferred relationships involving `contains()` (e.g. with `DetectMessageContent()` and `getDefaultFavicon()`) actually correct?**
|
||||
_`contains()` has 40 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 38 inferred relationships involving `main()` (e.g. with `Load()` and `InitDatabase()`) actually correct?**
|
||||
_`main()` has 38 INFERRED edges - model-reasoned connections that need verification._
|
||||
@@ -0,0 +1,276 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>graphify - /home/tdvorak/Desktop/PROG+HTML/Trackeep/graphify-out/graph.html</title>
|
||||
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { background: #0f0f1a; color: #e0e0e0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; display: flex; height: 100vh; overflow: hidden; }
|
||||
#graph { flex: 1; }
|
||||
#sidebar { width: 280px; background: #1a1a2e; border-left: 1px solid #2a2a4e; display: flex; flex-direction: column; overflow: hidden; }
|
||||
#search-wrap { padding: 12px; border-bottom: 1px solid #2a2a4e; }
|
||||
#search { width: 100%; background: #0f0f1a; border: 1px solid #3a3a5e; color: #e0e0e0; padding: 7px 10px; border-radius: 6px; font-size: 13px; outline: none; }
|
||||
#search:focus { border-color: #4E79A7; }
|
||||
#search-results { max-height: 140px; overflow-y: auto; padding: 4px 12px; border-bottom: 1px solid #2a2a4e; display: none; }
|
||||
.search-item { padding: 4px 6px; cursor: pointer; border-radius: 4px; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.search-item:hover { background: #2a2a4e; }
|
||||
#info-panel { padding: 14px; border-bottom: 1px solid #2a2a4e; min-height: 140px; }
|
||||
#info-panel h3 { font-size: 13px; color: #aaa; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
#info-content { font-size: 13px; color: #ccc; line-height: 1.6; }
|
||||
#info-content .field { margin-bottom: 5px; }
|
||||
#info-content .field b { color: #e0e0e0; }
|
||||
#info-content .empty { color: #555; font-style: italic; }
|
||||
.neighbor-link { display: block; padding: 2px 6px; margin: 2px 0; border-radius: 3px; cursor: pointer; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-left: 3px solid #333; }
|
||||
.neighbor-link:hover { background: #2a2a4e; }
|
||||
#neighbors-list { max-height: 160px; overflow-y: auto; margin-top: 4px; }
|
||||
#legend-wrap { flex: 1; overflow-y: auto; padding: 12px; }
|
||||
#legend-wrap h3 { font-size: 13px; color: #aaa; margin-bottom: 10px; text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
.legend-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; cursor: pointer; border-radius: 4px; font-size: 12px; }
|
||||
.legend-item:hover { background: #2a2a4e; padding-left: 4px; }
|
||||
.legend-item.dimmed { opacity: 0.35; }
|
||||
.legend-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
|
||||
.legend-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.legend-count { color: #666; font-size: 11px; }
|
||||
#stats { padding: 10px 14px; border-top: 1px solid #2a2a4e; font-size: 11px; color: #555; }
|
||||
#legend-controls { display: flex; gap: 6px; margin-bottom: 8px; }
|
||||
#legend-controls button { flex: 1; background: #0f0f1a; border: 1px solid #3a3a5e; color: #aaa; padding: 4px 0; border-radius: 4px; font-size: 11px; cursor: pointer; }
|
||||
#legend-controls button:hover { border-color: #4E79A7; color: #e0e0e0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="graph"></div>
|
||||
<div id="sidebar">
|
||||
<div id="search-wrap">
|
||||
<input id="search" type="text" placeholder="Search nodes..." autocomplete="off">
|
||||
<div id="search-results"></div>
|
||||
</div>
|
||||
<div id="info-panel">
|
||||
<h3>Node Info</h3>
|
||||
<div id="info-content"><span class="empty">Click a node to inspect it</span></div>
|
||||
</div>
|
||||
<div id="legend-wrap">
|
||||
<h3>Communities</h3>
|
||||
<div id="legend-controls">
|
||||
<button onclick="toggleAllCommunities(false)">Show All</button>
|
||||
<button onclick="toggleAllCommunities(true)">Hide All</button>
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2549 nodes · 3694 edges · 221 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "browser_extension_background_js", "label": "background.js", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 14.4, "font": {"size": 0, "color": "#ffffff"}, "title": "background.js", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 14}, {"id": "browser_extension_background_storagesyncget", "label": "storageSyncGet()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "storageSyncGet()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_storagelocalget", "label": "storageLocalGet()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "storageLocalGet()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_storagelocalset", "label": "storageLocalSet()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.9, "font": {"size": 0, "color": "#ffffff"}, "title": "storageLocalSet()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 3}, {"id": "browser_extension_background_parseresponseerror", "label": "parseResponseError()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "parseResponseError()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_parseyoutubevideometa", "label": "parseYouTubeVideoMeta()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "parseYouTubeVideoMeta()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_cleanuphistory", "label": "cleanupHistory()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "cleanupHistory()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_getyoutubehistory", "label": "getYouTubeHistory()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "getYouTubeHistory()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 4}, {"id": "browser_extension_background_updateyoutubehistory", "label": "updateYouTubeHistory()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.9, "font": {"size": 0, "color": "#ffffff"}, "title": "updateYouTubeHistory()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 6}, {"id": "browser_extension_background_gettrackeepconfig", "label": "getTrackeepConfig()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "getTrackeepConfig()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 4}, {"id": "browser_extension_background_shouldpromptforyoutubevideo", "label": "shouldPromptForYouTubeVideo()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "shouldPromptForYouTubeVideo()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 4}, {"id": "browser_extension_background_saveyoutubebookmark", "label": "saveYouTubeBookmark()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color"Line truncated
|
||||
const RAW_EDGES = [{"from": "browser_extension_background_js", "to": "browser_extension_background_storagesyncget", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_storagelocalget", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_storagelocalset", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_parseresponseerror", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_parseyoutubevideometa", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_cleanuphistory", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_getyoutubehistory", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_updateyoutubehistory", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_gettrackeepconfig", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_shouldpromptforyoutubevideo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_saveyoutubebookmark", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_openpopupwithcontext", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_setcontextandopenpopup", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_detectcontenttype", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagesyncget", "to": "browser_extension_background_gettrackeepconfig", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagelocalget", "to": "browser_extension_background_getyoutubehistory", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagelocalset", "to": "browser_extension_background_updateyoutubehistory", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagelocalset", "to": "browser_extension_background_openpopupwithcontext", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_parseresponseerror", "to": "browser_extension_background_saveyoutubebookmark", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_parseyoutubevideometa", "to": "browser_extension_background_detectcontenttype", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_cleanuphistory", "to": "browser_extension_background_updateyoutubehistory", "label": "calls", "title": "cLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 161}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 143}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 123}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 116}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 103}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 82}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 71}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 69}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 67}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 65}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 61}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 55}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 48}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 47}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 39}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 37}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 36}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 31}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 31}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 30}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 29}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 27}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 27}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 26}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 24}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 24}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 23}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 22}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 21}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 21}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 20}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 19}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 18}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 18}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 17}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 17}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 17}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 17}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 16}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 16}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 16}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 16}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 16}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 15}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 15}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 14}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 14}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 13}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 13}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 13}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 13}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 12}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 12}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 11}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 11}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 11}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 10}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 10}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 10}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 10}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 10}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 9}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 9}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 8}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 8}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 8}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 7}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 7}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 7}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 7}, {"cid": 70, "color": "#4E79A7", "labeLine truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,''');
|
||||
}
|
||||
|
||||
// Build vis datasets
|
||||
const nodesDS = new vis.DataSet(RAW_NODES.map(n => ({
|
||||
id: n.id, label: n.label, color: n.color, size: n.size,
|
||||
font: n.font, title: n.title,
|
||||
_community: n.community, _community_name: n.community_name,
|
||||
_source_file: n.source_file, _file_type: n.file_type, _degree: n.degree,
|
||||
})));
|
||||
|
||||
const edgesDS = new vis.DataSet(RAW_EDGES.map((e, i) => ({
|
||||
id: i, from: e.from, to: e.to,
|
||||
label: '',
|
||||
title: e.title,
|
||||
dashes: e.dashes,
|
||||
width: e.width,
|
||||
color: e.color,
|
||||
arrows: { to: { enabled: true, scaleFactor: 0.5 } },
|
||||
})));
|
||||
|
||||
const container = document.getElementById('graph');
|
||||
const network = new vis.Network(container, { nodes: nodesDS, edges: edgesDS }, {
|
||||
physics: {
|
||||
enabled: true,
|
||||
solver: 'forceAtlas2Based',
|
||||
forceAtlas2Based: {
|
||||
gravitationalConstant: -60,
|
||||
centralGravity: 0.005,
|
||||
springLength: 120,
|
||||
springConstant: 0.08,
|
||||
damping: 0.4,
|
||||
avoidOverlap: 0.8,
|
||||
},
|
||||
stabilization: { iterations: 200, fit: true },
|
||||
},
|
||||
interaction: {
|
||||
hover: true,
|
||||
tooltipDelay: 100,
|
||||
hideEdgesOnDrag: true,
|
||||
navigationButtons: false,
|
||||
keyboard: false,
|
||||
},
|
||||
nodes: { shape: 'dot', borderWidth: 1.5 },
|
||||
edges: { smooth: { type: 'continuous', roundness: 0.2 }, selectionWidth: 3 },
|
||||
});
|
||||
|
||||
network.once('stabilizationIterationsDone', () => {
|
||||
network.setOptions({ physics: { enabled: false } });
|
||||
});
|
||||
|
||||
function showInfo(nodeId) {
|
||||
const n = nodesDS.get(nodeId);
|
||||
if (!n) return;
|
||||
const neighborIds = network.getConnectedNodes(nodeId);
|
||||
const neighborItems = neighborIds.map(nid => {
|
||||
const nb = nodesDS.get(nid);
|
||||
const color = nb ? nb.color.background : '#555';
|
||||
return `<span class="neighbor-link" style="border-left-color:${esc(color)}" onclick="focusNode(${JSON.stringify(nid)})">${esc(nb ? nb.label : nid)}</span>`;
|
||||
}).join('');
|
||||
document.getElementById('info-content').innerHTML = `
|
||||
<div class="field"><b>${esc(n.label)}</b></div>
|
||||
<div class="field">Type: ${esc(n._file_type || 'unknown')}</div>
|
||||
<div class="field">Community: ${esc(n._community_name)}</div>
|
||||
<div class="field">Source: ${esc(n._source_file || '-')}</div>
|
||||
<div class="field">Degree: ${n._degree}</div>
|
||||
${neighborIds.length ? `<div class="field" style="margin-top:8px;color:#aaa;font-size:11px">Neighbors (${neighborIds.length})</div><div id="neighbors-list">${neighborItems}</div>` : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
function focusNode(nodeId) {
|
||||
network.focus(nodeId, { scale: 1.4, animation: true });
|
||||
network.selectNodes([nodeId]);
|
||||
showInfo(nodeId);
|
||||
}
|
||||
|
||||
// Track hovered node — hover detection is more reliable than click params
|
||||
let hoveredNodeId = null;
|
||||
network.on('hoverNode', params => {
|
||||
hoveredNodeId = params.node;
|
||||
container.style.cursor = 'pointer';
|
||||
});
|
||||
network.on('blurNode', () => {
|
||||
hoveredNodeId = null;
|
||||
container.style.cursor = 'default';
|
||||
});
|
||||
container.addEventListener('click', () => {
|
||||
if (hoveredNodeId !== null) {
|
||||
showInfo(hoveredNodeId);
|
||||
network.selectNodes([hoveredNodeId]);
|
||||
}
|
||||
});
|
||||
network.on('click', params => {
|
||||
if (params.nodes.length > 0) {
|
||||
showInfo(params.nodes[0]);
|
||||
} else if (hoveredNodeId === null) {
|
||||
document.getElementById('info-content').innerHTML = '<span class="empty">Click a node to inspect it</span>';
|
||||
}
|
||||
});
|
||||
|
||||
const searchInput = document.getElementById('search');
|
||||
const searchResults = document.getElementById('search-results');
|
||||
searchInput.addEventListener('input', () => {
|
||||
const q = searchInput.value.toLowerCase().trim();
|
||||
searchResults.innerHTML = '';
|
||||
if (!q) { searchResults.style.display = 'none'; return; }
|
||||
const matches = RAW_NODES.filter(n => n.label.toLowerCase().includes(q)).slice(0, 20);
|
||||
if (!matches.length) { searchResults.style.display = 'none'; return; }
|
||||
searchResults.style.display = 'block';
|
||||
matches.forEach(n => {
|
||||
const el = document.createElement('div');
|
||||
el.className = 'search-item';
|
||||
el.textContent = n.label;
|
||||
el.style.borderLeft = `3px solid ${n.color.background}`;
|
||||
el.style.paddingLeft = '8px';
|
||||
el.onclick = () => {
|
||||
network.focus(n.id, { scale: 1.5, animation: true });
|
||||
network.selectNodes([n.id]);
|
||||
showInfo(n.id);
|
||||
searchResults.style.display = 'none';
|
||||
searchInput.value = '';
|
||||
};
|
||||
searchResults.appendChild(el);
|
||||
});
|
||||
});
|
||||
document.addEventListener('click', e => {
|
||||
if (!searchResults.contains(e.target) && e.target !== searchInput)
|
||||
searchResults.style.display = 'none';
|
||||
});
|
||||
|
||||
const hiddenCommunities = new Set();
|
||||
|
||||
function toggleAllCommunities(hide) {
|
||||
document.querySelectorAll('.legend-item').forEach(item => {
|
||||
hide ? item.classList.add('dimmed') : item.classList.remove('dimmed');
|
||||
});
|
||||
LEGEND.forEach(c => {
|
||||
if (hide) hiddenCommunities.add(c.cid); else hiddenCommunities.delete(c.cid);
|
||||
});
|
||||
const updates = RAW_NODES.map(n => ({ id: n.id, hidden: hide }));
|
||||
nodesDS.update(updates);
|
||||
}
|
||||
|
||||
const legendEl = document.getElementById('legend');
|
||||
LEGEND.forEach(c => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'legend-item';
|
||||
item.innerHTML = `<div class="legend-dot" style="background:${c.color}"></div>
|
||||
<span class="legend-label">${c.label}</span>
|
||||
<span class="legend-count">${c.count}</span>`;
|
||||
item.onclick = () => {
|
||||
if (hiddenCommunities.has(c.cid)) {
|
||||
hiddenCommunities.delete(c.cid);
|
||||
item.classList.remove('dimmed');
|
||||
} else {
|
||||
hiddenCommunities.add(c.cid);
|
||||
item.classList.add('dimmed');
|
||||
}
|
||||
const updates = RAW_NODES
|
||||
.filter(n => n.community === c.cid)
|
||||
.map(n => ({ id: n.id, hidden: hiddenCommunities.has(c.cid) }));
|
||||
nodesDS.update(updates);
|
||||
};
|
||||
legendEl.appendChild(item);
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
// Render hyperedges as shaded regions
|
||||
const hyperedges = [];
|
||||
// afterDrawing passes ctx already transformed to network coordinate space.
|
||||
// Draw node positions raw — no manual pan/zoom/DPR math needed.
|
||||
network.on('afterDrawing', function(ctx) {
|
||||
hyperedges.forEach(h => {
|
||||
const positions = h.nodes
|
||||
.map(nid => network.getPositions([nid])[nid])
|
||||
.filter(p => p !== undefined);
|
||||
if (positions.length < 2) return;
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.12;
|
||||
ctx.fillStyle = '#6366f1';
|
||||
ctx.strokeStyle = '#6366f1';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
// Centroid and expanded hull in network coordinates
|
||||
const cx = positions.reduce((s, p) => s + p.x, 0) / positions.length;
|
||||
const cy = positions.reduce((s, p) => s + p.y, 0) / positions.length;
|
||||
const expanded = positions.map(p => ({
|
||||
x: cx + (p.x - cx) * 1.15,
|
||||
y: cy + (p.y - cy) * 1.15
|
||||
}));
|
||||
ctx.moveTo(expanded[0].x, expanded[0].y);
|
||||
expanded.slice(1).forEach(p => ctx.lineTo(p.x, p.y));
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.globalAlpha = 0.4;
|
||||
ctx.stroke();
|
||||
// Label
|
||||
ctx.globalAlpha = 0.8;
|
||||
ctx.fillStyle = '#4f46e5';
|
||||
ctx.font = 'bold 11px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(h.label, cx, cy - 5);
|
||||
ctx.restore();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+67279
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,276 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>graphify - graphify-out/index.html</title>
|
||||
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { background: #0f0f1a; color: #e0e0e0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; display: flex; height: 100vh; overflow: hidden; }
|
||||
#graph { flex: 1; }
|
||||
#sidebar { width: 280px; background: #1a1a2e; border-left: 1px solid #2a2a4e; display: flex; flex-direction: column; overflow: hidden; }
|
||||
#search-wrap { padding: 12px; border-bottom: 1px solid #2a2a4e; }
|
||||
#search { width: 100%; background: #0f0f1a; border: 1px solid #3a3a5e; color: #e0e0e0; padding: 7px 10px; border-radius: 6px; font-size: 13px; outline: none; }
|
||||
#search:focus { border-color: #4E79A7; }
|
||||
#search-results { max-height: 140px; overflow-y: auto; padding: 4px 12px; border-bottom: 1px solid #2a2a4e; display: none; }
|
||||
.search-item { padding: 4px 6px; cursor: pointer; border-radius: 4px; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.search-item:hover { background: #2a2a4e; }
|
||||
#info-panel { padding: 14px; border-bottom: 1px solid #2a2a4e; min-height: 140px; }
|
||||
#info-panel h3 { font-size: 13px; color: #aaa; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
#info-content { font-size: 13px; color: #ccc; line-height: 1.6; }
|
||||
#info-content .field { margin-bottom: 5px; }
|
||||
#info-content .field b { color: #e0e0e0; }
|
||||
#info-content .empty { color: #555; font-style: italic; }
|
||||
.neighbor-link { display: block; padding: 2px 6px; margin: 2px 0; border-radius: 3px; cursor: pointer; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-left: 3px solid #333; }
|
||||
.neighbor-link:hover { background: #2a2a4e; }
|
||||
#neighbors-list { max-height: 160px; overflow-y: auto; margin-top: 4px; }
|
||||
#legend-wrap { flex: 1; overflow-y: auto; padding: 12px; }
|
||||
#legend-wrap h3 { font-size: 13px; color: #aaa; margin-bottom: 10px; text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
.legend-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; cursor: pointer; border-radius: 4px; font-size: 12px; }
|
||||
.legend-item:hover { background: #2a2a4e; padding-left: 4px; }
|
||||
.legend-item.dimmed { opacity: 0.35; }
|
||||
.legend-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
|
||||
.legend-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.legend-count { color: #666; font-size: 11px; }
|
||||
#stats { padding: 10px 14px; border-top: 1px solid #2a2a4e; font-size: 11px; color: #555; }
|
||||
#legend-controls { display: flex; gap: 6px; margin-bottom: 8px; }
|
||||
#legend-controls button { flex: 1; background: #0f0f1a; border: 1px solid #3a3a5e; color: #aaa; padding: 4px 0; border-radius: 4px; font-size: 11px; cursor: pointer; }
|
||||
#legend-controls button:hover { border-color: #4E79A7; color: #e0e0e0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="graph"></div>
|
||||
<div id="sidebar">
|
||||
<div id="search-wrap">
|
||||
<input id="search" type="text" placeholder="Search nodes..." autocomplete="off">
|
||||
<div id="search-results"></div>
|
||||
</div>
|
||||
<div id="info-panel">
|
||||
<h3>Node Info</h3>
|
||||
<div id="info-content"><span class="empty">Click a node to inspect it</span></div>
|
||||
</div>
|
||||
<div id="legend-wrap">
|
||||
<h3>Communities</h3>
|
||||
<div id="legend-controls">
|
||||
<button onclick="toggleAllCommunities(false)">Show All</button>
|
||||
<button onclick="toggleAllCommunities(true)">Hide All</button>
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2549 nodes · 3694 edges · 221 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "browser_extension_background_js", "label": "background.js", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 14.4, "font": {"size": 0, "color": "#ffffff"}, "title": "background.js", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 14}, {"id": "browser_extension_background_storagesyncget", "label": "storageSyncGet()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "storageSyncGet()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_storagelocalget", "label": "storageLocalGet()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "storageLocalGet()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_storagelocalset", "label": "storageLocalSet()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.9, "font": {"size": 0, "color": "#ffffff"}, "title": "storageLocalSet()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 3}, {"id": "browser_extension_background_parseresponseerror", "label": "parseResponseError()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "parseResponseError()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_parseyoutubevideometa", "label": "parseYouTubeVideoMeta()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "parseYouTubeVideoMeta()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_cleanuphistory", "label": "cleanupHistory()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "cleanupHistory()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 2}, {"id": "browser_extension_background_getyoutubehistory", "label": "getYouTubeHistory()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "getYouTubeHistory()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 4}, {"id": "browser_extension_background_updateyoutubehistory", "label": "updateYouTubeHistory()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.9, "font": {"size": 0, "color": "#ffffff"}, "title": "updateYouTubeHistory()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 6}, {"id": "browser_extension_background_gettrackeepconfig", "label": "getTrackeepConfig()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "getTrackeepConfig()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 4}, {"id": "browser_extension_background_shouldpromptforyoutubevideo", "label": "shouldPromptForYouTubeVideo()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "shouldPromptForYouTubeVideo()", "community": 43, "community_name": "Community 43", "source_file": "browser-extension/background.js", "file_type": "code", "degree": 4}, {"id": "browser_extension_background_saveyoutubebookmark", "label": "saveYouTubeBookmark()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 11.3, "font": {"size": 0, "color"Line truncated
|
||||
const RAW_EDGES = [{"from": "browser_extension_background_js", "to": "browser_extension_background_storagesyncget", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_storagelocalget", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_storagelocalset", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_parseresponseerror", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_parseyoutubevideometa", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_cleanuphistory", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_getyoutubehistory", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_updateyoutubehistory", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_gettrackeepconfig", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_shouldpromptforyoutubevideo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_saveyoutubebookmark", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_openpopupwithcontext", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_setcontextandopenpopup", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_js", "to": "browser_extension_background_detectcontenttype", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagesyncget", "to": "browser_extension_background_gettrackeepconfig", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagelocalget", "to": "browser_extension_background_getyoutubehistory", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagelocalset", "to": "browser_extension_background_updateyoutubehistory", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_storagelocalset", "to": "browser_extension_background_openpopupwithcontext", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_parseresponseerror", "to": "browser_extension_background_saveyoutubebookmark", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_parseyoutubevideometa", "to": "browser_extension_background_detectcontenttype", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "browser_extension_background_cleanuphistory", "to": "browser_extension_background_updateyoutubehistory", "label": "calls", "title": "cLine truncated
|
||||
const LEGEND = [];
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,''');
|
||||
}
|
||||
|
||||
// Build vis datasets
|
||||
const nodesDS = new vis.DataSet(RAW_NODES.map(n => ({
|
||||
id: n.id, label: n.label, color: n.color, size: n.size,
|
||||
font: n.font, title: n.title,
|
||||
_community: n.community, _community_name: n.community_name,
|
||||
_source_file: n.source_file, _file_type: n.file_type, _degree: n.degree,
|
||||
})));
|
||||
|
||||
const edgesDS = new vis.DataSet(RAW_EDGES.map((e, i) => ({
|
||||
id: i, from: e.from, to: e.to,
|
||||
label: '',
|
||||
title: e.title,
|
||||
dashes: e.dashes,
|
||||
width: e.width,
|
||||
color: e.color,
|
||||
arrows: { to: { enabled: true, scaleFactor: 0.5 } },
|
||||
})));
|
||||
|
||||
const container = document.getElementById('graph');
|
||||
const network = new vis.Network(container, { nodes: nodesDS, edges: edgesDS }, {
|
||||
physics: {
|
||||
enabled: true,
|
||||
solver: 'forceAtlas2Based',
|
||||
forceAtlas2Based: {
|
||||
gravitationalConstant: -60,
|
||||
centralGravity: 0.005,
|
||||
springLength: 120,
|
||||
springConstant: 0.08,
|
||||
damping: 0.4,
|
||||
avoidOverlap: 0.8,
|
||||
},
|
||||
stabilization: { iterations: 200, fit: true },
|
||||
},
|
||||
interaction: {
|
||||
hover: true,
|
||||
tooltipDelay: 100,
|
||||
hideEdgesOnDrag: true,
|
||||
navigationButtons: false,
|
||||
keyboard: false,
|
||||
},
|
||||
nodes: { shape: 'dot', borderWidth: 1.5 },
|
||||
edges: { smooth: { type: 'continuous', roundness: 0.2 }, selectionWidth: 3 },
|
||||
});
|
||||
|
||||
network.once('stabilizationIterationsDone', () => {
|
||||
network.setOptions({ physics: { enabled: false } });
|
||||
});
|
||||
|
||||
function showInfo(nodeId) {
|
||||
const n = nodesDS.get(nodeId);
|
||||
if (!n) return;
|
||||
const neighborIds = network.getConnectedNodes(nodeId);
|
||||
const neighborItems = neighborIds.map(nid => {
|
||||
const nb = nodesDS.get(nid);
|
||||
const color = nb ? nb.color.background : '#555';
|
||||
return `<span class="neighbor-link" style="border-left-color:${esc(color)}" onclick="focusNode(${JSON.stringify(nid)})">${esc(nb ? nb.label : nid)}</span>`;
|
||||
}).join('');
|
||||
document.getElementById('info-content').innerHTML = `
|
||||
<div class="field"><b>${esc(n.label)}</b></div>
|
||||
<div class="field">Type: ${esc(n._file_type || 'unknown')}</div>
|
||||
<div class="field">Community: ${esc(n._community_name)}</div>
|
||||
<div class="field">Source: ${esc(n._source_file || '-')}</div>
|
||||
<div class="field">Degree: ${n._degree}</div>
|
||||
${neighborIds.length ? `<div class="field" style="margin-top:8px;color:#aaa;font-size:11px">Neighbors (${neighborIds.length})</div><div id="neighbors-list">${neighborItems}</div>` : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
function focusNode(nodeId) {
|
||||
network.focus(nodeId, { scale: 1.4, animation: true });
|
||||
network.selectNodes([nodeId]);
|
||||
showInfo(nodeId);
|
||||
}
|
||||
|
||||
// Track hovered node — hover detection is more reliable than click params
|
||||
let hoveredNodeId = null;
|
||||
network.on('hoverNode', params => {
|
||||
hoveredNodeId = params.node;
|
||||
container.style.cursor = 'pointer';
|
||||
});
|
||||
network.on('blurNode', () => {
|
||||
hoveredNodeId = null;
|
||||
container.style.cursor = 'default';
|
||||
});
|
||||
container.addEventListener('click', () => {
|
||||
if (hoveredNodeId !== null) {
|
||||
showInfo(hoveredNodeId);
|
||||
network.selectNodes([hoveredNodeId]);
|
||||
}
|
||||
});
|
||||
network.on('click', params => {
|
||||
if (params.nodes.length > 0) {
|
||||
showInfo(params.nodes[0]);
|
||||
} else if (hoveredNodeId === null) {
|
||||
document.getElementById('info-content').innerHTML = '<span class="empty">Click a node to inspect it</span>';
|
||||
}
|
||||
});
|
||||
|
||||
const searchInput = document.getElementById('search');
|
||||
const searchResults = document.getElementById('search-results');
|
||||
searchInput.addEventListener('input', () => {
|
||||
const q = searchInput.value.toLowerCase().trim();
|
||||
searchResults.innerHTML = '';
|
||||
if (!q) { searchResults.style.display = 'none'; return; }
|
||||
const matches = RAW_NODES.filter(n => n.label.toLowerCase().includes(q)).slice(0, 20);
|
||||
if (!matches.length) { searchResults.style.display = 'none'; return; }
|
||||
searchResults.style.display = 'block';
|
||||
matches.forEach(n => {
|
||||
const el = document.createElement('div');
|
||||
el.className = 'search-item';
|
||||
el.textContent = n.label;
|
||||
el.style.borderLeft = `3px solid ${n.color.background}`;
|
||||
el.style.paddingLeft = '8px';
|
||||
el.onclick = () => {
|
||||
network.focus(n.id, { scale: 1.5, animation: true });
|
||||
network.selectNodes([n.id]);
|
||||
showInfo(n.id);
|
||||
searchResults.style.display = 'none';
|
||||
searchInput.value = '';
|
||||
};
|
||||
searchResults.appendChild(el);
|
||||
});
|
||||
});
|
||||
document.addEventListener('click', e => {
|
||||
if (!searchResults.contains(e.target) && e.target !== searchInput)
|
||||
searchResults.style.display = 'none';
|
||||
});
|
||||
|
||||
const hiddenCommunities = new Set();
|
||||
|
||||
function toggleAllCommunities(hide) {
|
||||
document.querySelectorAll('.legend-item').forEach(item => {
|
||||
hide ? item.classList.add('dimmed') : item.classList.remove('dimmed');
|
||||
});
|
||||
LEGEND.forEach(c => {
|
||||
if (hide) hiddenCommunities.add(c.cid); else hiddenCommunities.delete(c.cid);
|
||||
});
|
||||
const updates = RAW_NODES.map(n => ({ id: n.id, hidden: hide }));
|
||||
nodesDS.update(updates);
|
||||
}
|
||||
|
||||
const legendEl = document.getElementById('legend');
|
||||
LEGEND.forEach(c => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'legend-item';
|
||||
item.innerHTML = `<div class="legend-dot" style="background:${c.color}"></div>
|
||||
<span class="legend-label">${c.label}</span>
|
||||
<span class="legend-count">${c.count}</span>`;
|
||||
item.onclick = () => {
|
||||
if (hiddenCommunities.has(c.cid)) {
|
||||
hiddenCommunities.delete(c.cid);
|
||||
item.classList.remove('dimmed');
|
||||
} else {
|
||||
hiddenCommunities.add(c.cid);
|
||||
item.classList.add('dimmed');
|
||||
}
|
||||
const updates = RAW_NODES
|
||||
.filter(n => n.community === c.cid)
|
||||
.map(n => ({ id: n.id, hidden: hiddenCommunities.has(c.cid) }));
|
||||
nodesDS.update(updates);
|
||||
};
|
||||
legendEl.appendChild(item);
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
// Render hyperedges as shaded regions
|
||||
const hyperedges = [];
|
||||
// afterDrawing passes ctx already transformed to network coordinate space.
|
||||
// Draw node positions raw — no manual pan/zoom/DPR math needed.
|
||||
network.on('afterDrawing', function(ctx) {
|
||||
hyperedges.forEach(h => {
|
||||
const positions = h.nodes
|
||||
.map(nid => network.getPositions([nid])[nid])
|
||||
.filter(p => p !== undefined);
|
||||
if (positions.length < 2) return;
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.12;
|
||||
ctx.fillStyle = '#6366f1';
|
||||
ctx.strokeStyle = '#6366f1';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
// Centroid and expanded hull in network coordinates
|
||||
const cx = positions.reduce((s, p) => s + p.x, 0) / positions.length;
|
||||
const cy = positions.reduce((s, p) => s + p.y, 0) / positions.length;
|
||||
const expanded = positions.map(p => ({
|
||||
x: cx + (p.x - cx) * 1.15,
|
||||
y: cy + (p.y - cy) * 1.15
|
||||
}));
|
||||
ctx.moveTo(expanded[0].x, expanded[0].y);
|
||||
expanded.slice(1).forEach(p => ctx.lineTo(p.x, p.y));
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.globalAlpha = 0.4;
|
||||
ctx.stroke();
|
||||
// Label
|
||||
ctx.globalAlpha = 0.8;
|
||||
ctx.fillStyle = '#4f46e5';
|
||||
ctx.font = 'bold 11px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(h.label, cx, cy - 5);
|
||||
ctx.restore();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user