source_monitor 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/commands/release.md +45 -22
- data/.claude/skills/sm-configure/SKILL.md +10 -1
- data/.claude/skills/sm-configure/reference/configuration-reference.md +44 -0
- data/.claude/skills/sm-host-setup/reference/initializer-template.md +17 -0
- data/.claude/skills/sm-host-setup/reference/setup-checklist.md +2 -0
- data/.claude/skills/sm-job/reference/job-conventions.md +26 -0
- data/.claude/skills/sm-upgrade/reference/version-history.md +22 -0
- data/.gitignore +10 -0
- data/AGENTS.md +1 -1
- data/CHANGELOG.md +56 -0
- data/CLAUDE.md +11 -5
- data/Gemfile.lock +1 -1
- data/README.md +6 -4
- data/VERSION +1 -1
- data/app/assets/builds/source_monitor/application.css +43 -0
- data/app/assets/builds/source_monitor/application.js +127 -0
- data/app/assets/builds/source_monitor/application.js.map +3 -3
- data/app/assets/javascripts/source_monitor/application.js +2 -0
- data/app/assets/javascripts/source_monitor/controllers/notification_container_controller.js +138 -0
- data/app/assets/javascripts/source_monitor/controllers/notification_controller.js +11 -0
- data/app/controllers/source_monitor/source_favicon_fetches_controller.rb +38 -0
- data/app/controllers/source_monitor/sources_controller.rb +11 -0
- data/app/helpers/source_monitor/application_helper.rb +51 -0
- data/app/jobs/source_monitor/favicon_fetch_job.rb +71 -0
- data/app/jobs/source_monitor/import_opml_job.rb +9 -0
- data/app/jobs/source_monitor/source_health_check_job.rb +10 -0
- data/app/models/source_monitor/source.rb +2 -0
- data/app/views/layouts/source_monitor/application.html.erb +23 -2
- data/app/views/source_monitor/shared/_toast.html.erb +1 -0
- data/app/views/source_monitor/sources/_details.html.erb +34 -5
- data/app/views/source_monitor/sources/_row.html.erb +11 -6
- data/config/routes.rb +1 -0
- data/docs/configuration.md +1 -1
- data/docs/upgrade.md +22 -0
- data/lib/generators/source_monitor/install/templates/source_monitor.rb.tt +15 -1
- data/lib/source_monitor/configuration/favicons_settings.rb +42 -0
- data/lib/source_monitor/configuration/http_settings.rb +1 -1
- data/lib/source_monitor/configuration/scraping_settings.rb +1 -1
- data/lib/source_monitor/configuration.rb +3 -1
- data/lib/source_monitor/favicons/discoverer.rb +196 -0
- data/lib/source_monitor/fetching/feed_fetcher/source_updater.rb +21 -0
- data/lib/source_monitor/fetching/feed_fetcher.rb +1 -0
- data/lib/source_monitor/http.rb +5 -3
- data/lib/source_monitor/version.rb +1 -1
- data/lib/source_monitor.rb +4 -0
- data/lib/tasks/test_fast.rake +11 -0
- data/source_monitor.gemspec +1 -1
- metadata +7 -93
- data/.vbw-planning/PROJECT.md +0 -51
- data/.vbw-planning/ROADMAP.md +0 -32
- data/.vbw-planning/SHIPPED.md +0 -63
- data/.vbw-planning/STATE.md +0 -27
- data/.vbw-planning/codebase/ARCHITECTURE.md +0 -147
- data/.vbw-planning/codebase/CONCERNS.md +0 -99
- data/.vbw-planning/codebase/CONVENTIONS.md +0 -97
- data/.vbw-planning/codebase/DEPENDENCIES.md +0 -100
- data/.vbw-planning/codebase/INDEX.md +0 -86
- data/.vbw-planning/codebase/META.md +0 -42
- data/.vbw-planning/codebase/PATTERNS.md +0 -262
- data/.vbw-planning/codebase/STACK.md +0 -101
- data/.vbw-planning/codebase/STRUCTURE.md +0 -324
- data/.vbw-planning/codebase/TESTING.md +0 -154
- data/.vbw-planning/config.json +0 -53
- data/.vbw-planning/discovery.json +0 -26
- data/.vbw-planning/milestones/default/ROADMAP.md +0 -115
- data/.vbw-planning/milestones/default/STATE.md +0 -82
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01-SUMMARY.md +0 -56
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01.md +0 -187
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02-SUMMARY.md +0 -64
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02.md +0 -137
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01-SUMMARY.md +0 -67
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01.md +0 -142
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02-SUMMARY.md +0 -64
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02.md +0 -138
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03-SUMMARY.md +0 -85
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03.md +0 -147
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04-SUMMARY.md +0 -63
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04.md +0 -129
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05-SUMMARY.md +0 -74
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05.md +0 -154
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION-wave1.md +0 -303
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION.md +0 -510
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01-SUMMARY.md +0 -61
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01.md +0 -161
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02-SUMMARY.md +0 -66
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02.md +0 -132
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03-SUMMARY.md +0 -59
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03.md +0 -171
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04-SUMMARY.md +0 -56
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04.md +0 -152
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/04-CONTEXT.md +0 -33
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01-SUMMARY.md +0 -42
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01.md +0 -119
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02-SUMMARY.md +0 -52
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02.md +0 -195
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03-SUMMARY.md +0 -79
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03.md +0 -130
- data/.vbw-planning/milestones/generator-enhancements/REQUIREMENTS.md +0 -72
- data/.vbw-planning/milestones/generator-enhancements/ROADMAP.md +0 -125
- data/.vbw-planning/milestones/generator-enhancements/SHIPPED.md +0 -40
- data/.vbw-planning/milestones/generator-enhancements/STATE.md +0 -43
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/01-CONTEXT.md +0 -33
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/01-VERIFICATION.md +0 -86
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/PLAN-01-SUMMARY.md +0 -61
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/PLAN-01.md +0 -380
- data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/02-VERIFICATION.md +0 -78
- data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/PLAN-01-SUMMARY.md +0 -46
- data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/PLAN-01.md +0 -500
- data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/03-VERIFICATION.md +0 -89
- data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/PLAN-01-SUMMARY.md +0 -48
- data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/PLAN-01.md +0 -456
- data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/04-VERIFICATION.md +0 -129
- data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/PLAN-01-SUMMARY.md +0 -70
- data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/PLAN-01.md +0 -747
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/05-VERIFICATION.md +0 -156
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-01-SUMMARY.md +0 -69
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-01.md +0 -455
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-02-SUMMARY.md +0 -39
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-02.md +0 -488
- data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/06-VERIFICATION.md +0 -100
- data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/PLAN-01-SUMMARY.md +0 -37
- data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/PLAN-01.md +0 -345
- data/.vbw-planning/milestones/upgrade-assurance/REQUIREMENTS.md +0 -80
- data/.vbw-planning/milestones/upgrade-assurance/ROADMAP.md +0 -75
- data/.vbw-planning/milestones/upgrade-assurance/STATE.md +0 -29
- data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/01-VERIFICATION.md +0 -144
- data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/PLAN-01-SUMMARY.md +0 -43
- data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/PLAN-01.md +0 -405
- data/.vbw-planning/milestones/upgrade-assurance/phases/02-config-deprecation/PLAN-01-SUMMARY.md +0 -27
- data/.vbw-planning/milestones/upgrade-assurance/phases/02-config-deprecation/PLAN-01.md +0 -303
- data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/03-VERIFICATION.md +0 -380
- data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/PLAN-01-SUMMARY.md +0 -36
- data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/PLAN-01.md +0 -652
- data/.vbw-planning/phases/01-aia-certificate-resolution/.context-dev.md +0 -17
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-01-SUMMARY.md +0 -26
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-01.md +0 -71
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-02-SUMMARY.md +0 -16
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-02.md +0 -56
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-03-SUMMARY.md +0 -17
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-03.md +0 -98
|
@@ -2488,6 +2488,7 @@ var notification_controller_default = class extends Controller {
|
|
|
2488
2488
|
}
|
|
2489
2489
|
this.clearTimeout();
|
|
2490
2490
|
this.registerController();
|
|
2491
|
+
this.applyLevelDelay();
|
|
2491
2492
|
this.startTimer();
|
|
2492
2493
|
}
|
|
2493
2494
|
disconnect() {
|
|
@@ -2505,8 +2506,17 @@ var notification_controller_default = class extends Controller {
|
|
|
2505
2506
|
if (this.delayValue <= 0) return;
|
|
2506
2507
|
this.timeoutId = window.setTimeout(() => this.dismiss(), this.delayValue);
|
|
2507
2508
|
}
|
|
2509
|
+
applyLevelDelay() {
|
|
2510
|
+
const level = this.element.dataset.level;
|
|
2511
|
+
if (level === "error" && this.delayValue === 5e3) {
|
|
2512
|
+
this.delayValue = 1e4;
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2508
2515
|
dismiss() {
|
|
2509
2516
|
if (!this.element) return;
|
|
2517
|
+
this.element.dispatchEvent(
|
|
2518
|
+
new CustomEvent("notification:dismissed", { bubbles: true })
|
|
2519
|
+
);
|
|
2510
2520
|
this.element.classList.add("opacity-0", "translate-y-2");
|
|
2511
2521
|
window.setTimeout(() => {
|
|
2512
2522
|
if (this.element && this.element.remove) {
|
|
@@ -2521,6 +2531,122 @@ var notification_controller_default = class extends Controller {
|
|
|
2521
2531
|
}
|
|
2522
2532
|
};
|
|
2523
2533
|
|
|
2534
|
+
// app/assets/javascripts/source_monitor/controllers/notification_container_controller.js
|
|
2535
|
+
var notification_container_controller_default = class extends Controller {
|
|
2536
|
+
static values = {
|
|
2537
|
+
maxVisible: { default: 3, type: Number },
|
|
2538
|
+
expanded: { default: false, type: Boolean }
|
|
2539
|
+
};
|
|
2540
|
+
static targets = ["list", "badge", "badgeCount", "clearAll"];
|
|
2541
|
+
connect() {
|
|
2542
|
+
this.rafId = null;
|
|
2543
|
+
this.boundHandleClickOutside = this.handleClickOutside.bind(this);
|
|
2544
|
+
this.boundScheduleRecalculate = () => this.scheduleRecalculate();
|
|
2545
|
+
this.observer = new MutationObserver(this.boundScheduleRecalculate);
|
|
2546
|
+
this.observer.observe(this.listTarget, { childList: true });
|
|
2547
|
+
this.listTarget.addEventListener(
|
|
2548
|
+
"notification:dismissed",
|
|
2549
|
+
this.boundScheduleRecalculate
|
|
2550
|
+
);
|
|
2551
|
+
this.recalculateVisibility();
|
|
2552
|
+
}
|
|
2553
|
+
disconnect() {
|
|
2554
|
+
if (this.observer) {
|
|
2555
|
+
this.observer.disconnect();
|
|
2556
|
+
this.observer = null;
|
|
2557
|
+
}
|
|
2558
|
+
if (this.rafId) {
|
|
2559
|
+
cancelAnimationFrame(this.rafId);
|
|
2560
|
+
this.rafId = null;
|
|
2561
|
+
}
|
|
2562
|
+
this.listTarget.removeEventListener(
|
|
2563
|
+
"notification:dismissed",
|
|
2564
|
+
this.boundScheduleRecalculate
|
|
2565
|
+
);
|
|
2566
|
+
document.removeEventListener("click", this.boundHandleClickOutside);
|
|
2567
|
+
}
|
|
2568
|
+
scheduleRecalculate() {
|
|
2569
|
+
if (this.rafId) {
|
|
2570
|
+
cancelAnimationFrame(this.rafId);
|
|
2571
|
+
}
|
|
2572
|
+
this.rafId = requestAnimationFrame(() => {
|
|
2573
|
+
this.rafId = null;
|
|
2574
|
+
this.recalculateVisibility();
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
recalculateVisibility() {
|
|
2578
|
+
const toasts = Array.from(this.listTarget.children);
|
|
2579
|
+
const total = toasts.length;
|
|
2580
|
+
if (this.expandedValue) {
|
|
2581
|
+
toasts.forEach((toast) => {
|
|
2582
|
+
toast.classList.remove("hidden");
|
|
2583
|
+
toast.removeAttribute("aria-hidden");
|
|
2584
|
+
toast.removeAttribute("inert");
|
|
2585
|
+
});
|
|
2586
|
+
} else {
|
|
2587
|
+
toasts.forEach((toast, index) => {
|
|
2588
|
+
if (index < this.maxVisibleValue) {
|
|
2589
|
+
toast.classList.remove("hidden");
|
|
2590
|
+
toast.removeAttribute("aria-hidden");
|
|
2591
|
+
toast.removeAttribute("inert");
|
|
2592
|
+
} else {
|
|
2593
|
+
toast.classList.add("hidden");
|
|
2594
|
+
toast.setAttribute("aria-hidden", "true");
|
|
2595
|
+
toast.setAttribute("inert", "");
|
|
2596
|
+
}
|
|
2597
|
+
});
|
|
2598
|
+
}
|
|
2599
|
+
const hiddenCount = this.expandedValue ? 0 : Math.max(0, total - this.maxVisibleValue);
|
|
2600
|
+
if (this.hasBadgeTarget) {
|
|
2601
|
+
if (this.hasBadgeCountTarget) {
|
|
2602
|
+
this.badgeCountTarget.textContent = `+${hiddenCount} more`;
|
|
2603
|
+
}
|
|
2604
|
+
if (hiddenCount > 0) {
|
|
2605
|
+
this.badgeTarget.classList.remove("hidden");
|
|
2606
|
+
} else {
|
|
2607
|
+
this.badgeTarget.classList.add("hidden");
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
if (this.hasClearAllTarget) {
|
|
2611
|
+
const showClearAll = total > 0 && (hiddenCount > 0 || this.expandedValue);
|
|
2612
|
+
if (showClearAll) {
|
|
2613
|
+
this.clearAllTarget.classList.remove("hidden");
|
|
2614
|
+
} else {
|
|
2615
|
+
this.clearAllTarget.classList.add("hidden");
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
toggleExpand(event) {
|
|
2620
|
+
event.preventDefault();
|
|
2621
|
+
if (this.expandedValue) {
|
|
2622
|
+
this.collapseStack();
|
|
2623
|
+
} else {
|
|
2624
|
+
this.expandStack();
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
expandStack() {
|
|
2628
|
+
this.expandedValue = true;
|
|
2629
|
+
this.recalculateVisibility();
|
|
2630
|
+
document.addEventListener("click", this.boundHandleClickOutside);
|
|
2631
|
+
}
|
|
2632
|
+
collapseStack() {
|
|
2633
|
+
this.expandedValue = false;
|
|
2634
|
+
document.removeEventListener("click", this.boundHandleClickOutside);
|
|
2635
|
+
this.recalculateVisibility();
|
|
2636
|
+
}
|
|
2637
|
+
handleClickOutside(event) {
|
|
2638
|
+
if (!this.element.contains(event.target)) {
|
|
2639
|
+
this.collapseStack();
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
clearAll(event) {
|
|
2643
|
+
event.preventDefault();
|
|
2644
|
+
const toasts = Array.from(this.listTarget.children);
|
|
2645
|
+
toasts.forEach((toast) => toast.remove());
|
|
2646
|
+
this.collapseStack();
|
|
2647
|
+
}
|
|
2648
|
+
};
|
|
2649
|
+
|
|
2524
2650
|
// app/assets/javascripts/source_monitor/controllers/dropdown_controller.js
|
|
2525
2651
|
var dropdown_controller_default = class extends Controller {
|
|
2526
2652
|
static targets = ["menu"];
|
|
@@ -2746,6 +2872,7 @@ if (!existingApplication) {
|
|
|
2746
2872
|
window.SourceMonitorStimulus = application;
|
|
2747
2873
|
}
|
|
2748
2874
|
application.register("notification", notification_controller_default);
|
|
2875
|
+
application.register("notification-container", notification_container_controller_default);
|
|
2749
2876
|
application.register("async-submit", async_submit_controller_default);
|
|
2750
2877
|
application.register("dropdown", dropdown_controller_default);
|
|
2751
2878
|
application.register("modal", modal_controller_default);
|