source_monitor 0.11.1 → 0.12.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/rails-audit.md +77 -0
- data/CHANGELOG.md +50 -0
- data/CLAUDE.md +2 -2
- data/Gemfile.lock +7 -20
- data/RAILS_AUDIT.md +424 -0
- data/VERSION +1 -1
- data/app/assets/builds/source_monitor/application.css +4 -24
- data/app/assets/builds/source_monitor/application.js +57 -89
- data/app/assets/builds/source_monitor/application.js.map +4 -4
- data/app/assets/javascripts/source_monitor/application.js +3 -6
- data/app/assets/javascripts/source_monitor/controllers/dropdown_controller.js +6 -86
- data/app/assets/javascripts/source_monitor/controllers/filter_submit_controller.js +13 -0
- data/app/assets/javascripts/source_monitor/controllers/modal_controller.js +56 -0
- data/app/assets/javascripts/source_monitor/controllers/notification_controller.js +3 -13
- data/app/components/source_monitor/application_component.rb +10 -0
- data/app/components/source_monitor/filter_dropdown_component.rb +62 -0
- data/app/components/source_monitor/icon_component.rb +140 -0
- data/app/components/source_monitor/status_badge_component.html.erb +8 -0
- data/app/components/source_monitor/status_badge_component.rb +96 -0
- data/app/controllers/concerns/source_monitor/sanitizes_search_params.rb +4 -0
- data/app/controllers/concerns/source_monitor/set_source.rb +13 -0
- data/app/controllers/source_monitor/application_controller.rb +17 -0
- data/app/controllers/source_monitor/bulk_scrape_enablements_controller.rb +6 -10
- data/app/controllers/source_monitor/dashboard_controller.rb +5 -1
- data/app/controllers/source_monitor/import_history_dismissals_controller.rb +1 -1
- data/app/controllers/source_monitor/import_sessions_controller.rb +30 -9
- data/app/controllers/source_monitor/item_scrapes_controller.rb +70 -0
- data/app/controllers/source_monitor/items_controller.rb +2 -69
- data/app/controllers/source_monitor/source_bulk_scrapes_controller.rb +1 -4
- data/app/controllers/source_monitor/source_favicon_fetches_controller.rb +2 -12
- data/app/controllers/source_monitor/source_fetches_controller.rb +1 -6
- data/app/controllers/source_monitor/source_health_checks_controller.rb +9 -16
- data/app/controllers/source_monitor/source_health_resets_controller.rb +1 -6
- data/app/controllers/source_monitor/source_retries_controller.rb +1 -6
- data/app/controllers/source_monitor/source_scrape_tests_controller.rb +2 -4
- data/app/controllers/source_monitor/source_turbo_responses.rb +1 -3
- data/app/controllers/source_monitor/sources_controller.rb +15 -20
- data/app/helpers/source_monitor/application_helper.rb +15 -31
- data/app/helpers/source_monitor/health_badge_helper.rb +8 -0
- data/app/jobs/source_monitor/download_content_images_job.rb +1 -59
- data/app/jobs/source_monitor/favicon_fetch_job.rb +1 -58
- data/app/jobs/source_monitor/fetch_feed_job.rb +2 -52
- data/app/jobs/source_monitor/import_opml_job.rb +6 -145
- data/app/jobs/source_monitor/import_session_health_check_job.rb +15 -76
- data/app/jobs/source_monitor/item_cleanup_job.rb +5 -0
- data/app/jobs/source_monitor/log_cleanup_job.rb +13 -2
- data/app/jobs/source_monitor/schedule_fetches_job.rb +8 -0
- data/app/jobs/source_monitor/scrape_item_job.rb +6 -52
- data/app/jobs/source_monitor/source_health_check_job.rb +1 -72
- data/app/models/concerns/source_monitor/loggable.rb +12 -0
- data/app/models/source_monitor/fetch_log.rb +0 -8
- data/app/models/source_monitor/health_check_log.rb +0 -8
- data/app/models/source_monitor/import_history.rb +14 -0
- data/app/models/source_monitor/import_session.rb +2 -0
- data/app/models/source_monitor/item.rb +15 -0
- data/app/models/source_monitor/item_content.rb +4 -3
- data/app/models/source_monitor/scrape_log.rb +4 -6
- data/app/models/source_monitor/source.rb +28 -19
- data/app/presenters/source_monitor/base_presenter.rb +19 -0
- data/app/presenters/source_monitor/source_details_presenter.rb +61 -0
- data/app/presenters/source_monitor/sources_filter_presenter.rb +61 -0
- data/app/views/source_monitor/dashboard/_recent_activity.html.erb +3 -3
- data/app/views/source_monitor/dashboard/_stat_card.html.erb +2 -1
- data/app/views/source_monitor/dashboard/_stats.html.erb +5 -7
- data/app/views/source_monitor/items/_details.html.erb +11 -14
- data/app/views/source_monitor/items/index.html.erb +10 -35
- data/app/views/source_monitor/logs/index.html.erb +20 -41
- data/app/views/source_monitor/shared/_form_errors.html.erb +14 -0
- data/app/views/source_monitor/source_scrape_tests/_result.html.erb +1 -29
- data/app/views/source_monitor/source_scrape_tests/_result_content.html.erb +33 -0
- data/app/views/source_monitor/source_scrape_tests/show.html.erb +1 -29
- data/app/views/source_monitor/sources/_bulk_scrape_enable_modal.html.erb +2 -2
- data/app/views/source_monitor/sources/_bulk_scrape_modal.html.erb +7 -5
- data/app/views/source_monitor/sources/_details.html.erb +24 -52
- data/app/views/source_monitor/sources/_health_status_badge.html.erb +4 -6
- data/app/views/source_monitor/sources/_row.html.erb +7 -18
- data/app/views/source_monitor/sources/edit.html.erb +1 -10
- data/app/views/source_monitor/sources/index.html.erb +26 -46
- data/app/views/source_monitor/sources/new.html.erb +1 -10
- data/config/routes.rb +1 -1
- data/db/migrate/20260313120000_add_composite_indexes_to_log_tables.rb +14 -0
- data/db/migrate/20260314120000_align_health_status_default.rb +11 -0
- data/lib/source_monitor/analytics/sources_index_metrics.rb +15 -0
- data/lib/source_monitor/dashboard/queries/recent_activity_query.rb +10 -4
- data/lib/source_monitor/dashboard/turbo_broadcaster.rb +21 -5
- data/lib/source_monitor/favicons/fetcher.rb +86 -0
- data/lib/source_monitor/fetching/cloudflare_bypass.rb +14 -5
- data/lib/source_monitor/fetching/completion/event_publisher.rb +12 -0
- data/lib/source_monitor/fetching/completion/follow_up_handler.rb +15 -2
- data/lib/source_monitor/fetching/completion/retention_handler.rb +11 -3
- data/lib/source_monitor/fetching/feed_fetcher.rb +2 -21
- data/lib/source_monitor/fetching/fetch_runner.rb +12 -3
- data/lib/source_monitor/fetching/retry_orchestrator.rb +102 -0
- data/lib/source_monitor/fetching/stalled_fetch_reconciler.rb +9 -0
- data/lib/source_monitor/health/source_health_check_orchestrator.rb +95 -0
- data/lib/source_monitor/health.rb +1 -0
- data/lib/source_monitor/images/downloader.rb +6 -7
- data/lib/source_monitor/images/processor.rb +98 -0
- data/lib/source_monitor/import_sessions/health_check_updater.rb +95 -0
- data/lib/source_monitor/import_sessions/opml_importer.rb +163 -0
- data/lib/source_monitor/items/item_creator.rb +0 -21
- data/lib/source_monitor/logs/query.rb +20 -0
- data/lib/source_monitor/queries/scrape_candidates_query.rb +30 -0
- data/lib/source_monitor/queries.rb +7 -0
- data/lib/source_monitor/scheduler.rb +5 -0
- data/lib/source_monitor/scraping/bulk_result_presenter.rb +11 -8
- data/lib/source_monitor/scraping/runner.rb +52 -0
- data/lib/source_monitor/scraping/scheduler.rb +5 -0
- data/lib/source_monitor/scraping/state.rb +4 -2
- data/lib/source_monitor/security/parameter_sanitizer.rb +7 -0
- data/lib/source_monitor/version.rb +1 -1
- data/lib/source_monitor.rb +7 -0
- data/source_monitor.gemspec +1 -0
- metadata +47 -1
|
@@ -626,6 +626,10 @@ video {
|
|
|
626
626
|
pointer-events: auto;
|
|
627
627
|
}
|
|
628
628
|
|
|
629
|
+
.fm-admin .visible {
|
|
630
|
+
visibility: visible;
|
|
631
|
+
}
|
|
632
|
+
|
|
629
633
|
.fm-admin .static {
|
|
630
634
|
position: static;
|
|
631
635
|
}
|
|
@@ -705,10 +709,6 @@ video {
|
|
|
705
709
|
margin-bottom: 0.25rem;
|
|
706
710
|
}
|
|
707
711
|
|
|
708
|
-
.fm-admin .mb-1 {
|
|
709
|
-
margin-bottom: 0.25rem;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
712
|
.fm-admin .ml-0\.5 {
|
|
713
713
|
margin-left: 0.125rem;
|
|
714
714
|
}
|
|
@@ -717,14 +717,6 @@ video {
|
|
|
717
717
|
margin-left: 0.5rem;
|
|
718
718
|
}
|
|
719
719
|
|
|
720
|
-
.fm-admin .ml-3 {
|
|
721
|
-
margin-left: 0.75rem;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
.fm-admin .ml-4 {
|
|
725
|
-
margin-left: 1rem;
|
|
726
|
-
}
|
|
727
|
-
|
|
728
720
|
.fm-admin .mr-1 {
|
|
729
721
|
margin-right: 0.25rem;
|
|
730
722
|
}
|
|
@@ -809,10 +801,6 @@ video {
|
|
|
809
801
|
height: 1rem;
|
|
810
802
|
}
|
|
811
803
|
|
|
812
|
-
.fm-admin .h-5 {
|
|
813
|
-
height: 1.25rem;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
804
|
.fm-admin .h-8 {
|
|
817
805
|
height: 2rem;
|
|
818
806
|
}
|
|
@@ -861,10 +849,6 @@ video {
|
|
|
861
849
|
width: 10rem;
|
|
862
850
|
}
|
|
863
851
|
|
|
864
|
-
.fm-admin .w-5 {
|
|
865
|
-
width: 1.25rem;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
852
|
.fm-admin .w-8 {
|
|
869
853
|
width: 2rem;
|
|
870
854
|
}
|
|
@@ -1885,10 +1869,6 @@ video {
|
|
|
1885
1869
|
opacity: 0;
|
|
1886
1870
|
}
|
|
1887
1871
|
|
|
1888
|
-
.fm-admin .opacity-25 {
|
|
1889
|
-
opacity: 0.25;
|
|
1890
|
-
}
|
|
1891
|
-
|
|
1892
1872
|
.fm-admin .opacity-60 {
|
|
1893
1873
|
opacity: 0.6;
|
|
1894
1874
|
}
|
|
@@ -2483,11 +2483,7 @@ var notification_controller_default = class extends Controller {
|
|
|
2483
2483
|
delay: { default: 5e3, type: Number }
|
|
2484
2484
|
};
|
|
2485
2485
|
connect() {
|
|
2486
|
-
if (!window.SourceMonitorControllers) {
|
|
2487
|
-
window.SourceMonitorControllers = {};
|
|
2488
|
-
}
|
|
2489
2486
|
this.clearTimeout();
|
|
2490
|
-
this.registerController();
|
|
2491
2487
|
this.applyLevelDelay();
|
|
2492
2488
|
this.startTimer();
|
|
2493
2489
|
}
|
|
@@ -2499,18 +2495,11 @@ var notification_controller_default = class extends Controller {
|
|
|
2499
2495
|
this.clearTimeout();
|
|
2500
2496
|
this.dismiss();
|
|
2501
2497
|
}
|
|
2502
|
-
registerController() {
|
|
2503
|
-
window.SourceMonitorControllers.notification = this;
|
|
2504
|
-
}
|
|
2505
2498
|
startTimer() {
|
|
2506
2499
|
if (this.delayValue <= 0) return;
|
|
2507
2500
|
this.timeoutId = window.setTimeout(() => this.dismiss(), this.delayValue);
|
|
2508
2501
|
}
|
|
2509
2502
|
applyLevelDelay() {
|
|
2510
|
-
const level = this.element.dataset.level;
|
|
2511
|
-
if (level === "error" && this.delayValue === 5e3) {
|
|
2512
|
-
this.delayValue = 1e4;
|
|
2513
|
-
}
|
|
2514
2503
|
}
|
|
2515
2504
|
dismiss() {
|
|
2516
2505
|
if (!this.element) return;
|
|
@@ -2651,92 +2640,25 @@ var notification_container_controller_default = class extends Controller {
|
|
|
2651
2640
|
var dropdown_controller_default = class extends Controller {
|
|
2652
2641
|
static targets = ["menu"];
|
|
2653
2642
|
static values = {
|
|
2654
|
-
transitionModule: { type: String, default: "stimulus-use" },
|
|
2655
2643
|
hiddenClass: { type: String, default: "hidden" }
|
|
2656
2644
|
};
|
|
2657
2645
|
connect() {
|
|
2658
|
-
this.
|
|
2659
|
-
this.
|
|
2660
|
-
if (typeof this.toggleTransition !== "function") {
|
|
2661
|
-
this.toggleTransition = this.toggleVisibility.bind(this);
|
|
2662
|
-
}
|
|
2663
|
-
if (typeof this.leave !== "function") {
|
|
2664
|
-
this.leave = this.hideMenu.bind(this);
|
|
2665
|
-
}
|
|
2666
|
-
this.loadTransitions().catch(() => null).finally(() => {
|
|
2667
|
-
this.element.dataset.dropdownState = "ready";
|
|
2668
|
-
});
|
|
2646
|
+
this._hideOnClickOutside = this.hide.bind(this);
|
|
2647
|
+
document.addEventListener("click", this._hideOnClickOutside);
|
|
2669
2648
|
}
|
|
2670
2649
|
disconnect() {
|
|
2671
|
-
|
|
2672
|
-
}
|
|
2673
|
-
// Dynamic import provides progressive enhancement: smooth transitions when stimulus-use
|
|
2674
|
-
// is available, graceful fallback to CSS class toggling when not. This complexity is
|
|
2675
|
-
// justified as it allows the engine to work without requiring stimulus-use as a dependency.
|
|
2676
|
-
// Evaluated for simplification in Phase 20.05.07 - Decision: Keep current implementation.
|
|
2677
|
-
async loadTransitions() {
|
|
2678
|
-
if (!this.hasMenuTarget || this.transitionModuleValue === "") {
|
|
2679
|
-
this.logFallback();
|
|
2680
|
-
return;
|
|
2681
|
-
}
|
|
2682
|
-
try {
|
|
2683
|
-
const module = await import(this.transitionModuleValue);
|
|
2684
|
-
const useTransition = module?.useTransition || module?.default?.useTransition;
|
|
2685
|
-
if (typeof useTransition === "function") {
|
|
2686
|
-
useTransition(this, {
|
|
2687
|
-
element: this.menuTarget,
|
|
2688
|
-
hiddenClass: this.hiddenClassValue
|
|
2689
|
-
});
|
|
2690
|
-
this.transitionEnabled = true;
|
|
2691
|
-
} else {
|
|
2692
|
-
this.logFallback();
|
|
2693
|
-
}
|
|
2694
|
-
} catch (error2) {
|
|
2695
|
-
this.logFallback(error2);
|
|
2696
|
-
}
|
|
2650
|
+
document.removeEventListener("click", this._hideOnClickOutside);
|
|
2697
2651
|
}
|
|
2698
2652
|
toggle(event) {
|
|
2699
|
-
if (
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
this.toggleVisibility();
|
|
2703
|
-
}
|
|
2653
|
+
if (event) event.stopPropagation();
|
|
2654
|
+
if (!this.hasMenuTarget) return;
|
|
2655
|
+
this.menuTarget.classList.toggle(this.hiddenClassValue);
|
|
2704
2656
|
}
|
|
2705
2657
|
hide(event) {
|
|
2706
2658
|
if (!this.hasMenuTarget) return;
|
|
2707
2659
|
if (event && this.element.contains(event.target)) return;
|
|
2708
|
-
if (this.transitionEnabled && typeof this.leave === "function") {
|
|
2709
|
-
this.leave();
|
|
2710
|
-
} else {
|
|
2711
|
-
this.hideMenu();
|
|
2712
|
-
}
|
|
2713
|
-
}
|
|
2714
|
-
toggleVisibility() {
|
|
2715
|
-
this.isOpen() ? this.hideMenu() : this.showMenu();
|
|
2716
|
-
}
|
|
2717
|
-
showMenu() {
|
|
2718
|
-
if (!this.hasMenuTarget) return;
|
|
2719
|
-
this.menuTarget.classList.remove(this.hiddenClassValue);
|
|
2720
|
-
}
|
|
2721
|
-
hideMenu() {
|
|
2722
|
-
if (!this.hasMenuTarget) return;
|
|
2723
2660
|
this.menuTarget.classList.add(this.hiddenClassValue);
|
|
2724
2661
|
}
|
|
2725
|
-
isOpen() {
|
|
2726
|
-
return this.hasMenuTarget && !this.menuTarget.classList.contains(this.hiddenClassValue);
|
|
2727
|
-
}
|
|
2728
|
-
logFallback(error2 = null) {
|
|
2729
|
-
this.transitionEnabled = false;
|
|
2730
|
-
if (!this._fallbackLogged && typeof window !== "undefined" && window.console) {
|
|
2731
|
-
window.console.warn(
|
|
2732
|
-
"SourceMonitor dropdown transitions unavailable; using CSS class toggling instead."
|
|
2733
|
-
);
|
|
2734
|
-
if (error2 && typeof window.console.debug === "function") {
|
|
2735
|
-
window.console.debug(error2);
|
|
2736
|
-
}
|
|
2737
|
-
}
|
|
2738
|
-
this._fallbackLogged = true;
|
|
2739
|
-
}
|
|
2740
2662
|
};
|
|
2741
2663
|
|
|
2742
2664
|
// app/assets/javascripts/source_monitor/controllers/modal_controller.js
|
|
@@ -2746,6 +2668,7 @@ var modal_controller_default = class extends Controller {
|
|
|
2746
2668
|
static values = { autoOpen: Boolean, removeOnClose: Boolean };
|
|
2747
2669
|
connect() {
|
|
2748
2670
|
this.handleEscape = this.handleEscape.bind(this);
|
|
2671
|
+
this._inertElements = [];
|
|
2749
2672
|
if (this.autoOpenValue) {
|
|
2750
2673
|
this.open();
|
|
2751
2674
|
}
|
|
@@ -2762,6 +2685,8 @@ var modal_controller_default = class extends Controller {
|
|
|
2762
2685
|
}
|
|
2763
2686
|
document.body.classList.add("overflow-hidden");
|
|
2764
2687
|
document.addEventListener("keydown", this.handleEscape);
|
|
2688
|
+
this._setInert(true);
|
|
2689
|
+
this._focusFirstElement();
|
|
2765
2690
|
}
|
|
2766
2691
|
close(event) {
|
|
2767
2692
|
if (event) event.preventDefault();
|
|
@@ -2770,6 +2695,7 @@ var modal_controller_default = class extends Controller {
|
|
|
2770
2695
|
if (this.hasOpenClass) {
|
|
2771
2696
|
this.panelTarget.classList.remove(this.openClass);
|
|
2772
2697
|
}
|
|
2698
|
+
this._setInert(false);
|
|
2773
2699
|
this.teardown();
|
|
2774
2700
|
if (this.removeOnCloseValue) {
|
|
2775
2701
|
this.element.remove();
|
|
@@ -2789,6 +2715,43 @@ var modal_controller_default = class extends Controller {
|
|
|
2789
2715
|
document.body.classList.remove("overflow-hidden");
|
|
2790
2716
|
document.removeEventListener("keydown", this.handleEscape);
|
|
2791
2717
|
}
|
|
2718
|
+
// -- Private helpers --
|
|
2719
|
+
_setInert(inert) {
|
|
2720
|
+
if (inert) {
|
|
2721
|
+
const modalRoot = this._findModalRoot();
|
|
2722
|
+
if (!modalRoot) return;
|
|
2723
|
+
this._inertElements = [];
|
|
2724
|
+
for (const sibling of document.body.children) {
|
|
2725
|
+
if (sibling === modalRoot || sibling === this.element) continue;
|
|
2726
|
+
if (sibling.nodeType !== Node.ELEMENT_NODE) continue;
|
|
2727
|
+
if (!sibling.hasAttribute("inert")) {
|
|
2728
|
+
sibling.setAttribute("inert", "");
|
|
2729
|
+
this._inertElements.push(sibling);
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
} else {
|
|
2733
|
+
for (const el of this._inertElements) {
|
|
2734
|
+
el.removeAttribute("inert");
|
|
2735
|
+
}
|
|
2736
|
+
this._inertElements = [];
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
_findModalRoot() {
|
|
2740
|
+
let el = this.hasPanelTarget ? this.panelTarget : this.element;
|
|
2741
|
+
while (el && el.parentElement !== document.body) {
|
|
2742
|
+
el = el.parentElement;
|
|
2743
|
+
}
|
|
2744
|
+
return el;
|
|
2745
|
+
}
|
|
2746
|
+
_focusFirstElement() {
|
|
2747
|
+
requestAnimationFrame(() => {
|
|
2748
|
+
if (!this.hasPanelTarget) return;
|
|
2749
|
+
const focusable = this.panelTarget.querySelector(
|
|
2750
|
+
'button, [href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
2751
|
+
);
|
|
2752
|
+
if (focusable) focusable.focus();
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2792
2755
|
};
|
|
2793
2756
|
|
|
2794
2757
|
// app/assets/javascripts/source_monitor/controllers/confirm_navigation_controller.js
|
|
@@ -2878,6 +2841,14 @@ var select_all_controller_default = class extends Controller {
|
|
|
2878
2841
|
}
|
|
2879
2842
|
};
|
|
2880
2843
|
|
|
2844
|
+
// app/assets/javascripts/source_monitor/controllers/filter_submit_controller.js
|
|
2845
|
+
var filter_submit_controller_default = class extends Controller {
|
|
2846
|
+
submit(event) {
|
|
2847
|
+
const form = event.target.closest("form");
|
|
2848
|
+
if (form) form.requestSubmit();
|
|
2849
|
+
}
|
|
2850
|
+
};
|
|
2851
|
+
|
|
2881
2852
|
// app/assets/javascripts/source_monitor/turbo_actions.js
|
|
2882
2853
|
if (window.Turbo && window.Turbo.StreamActions) {
|
|
2883
2854
|
window.Turbo.StreamActions.redirect = function() {
|
|
@@ -2890,11 +2861,7 @@ if (window.Turbo && window.Turbo.StreamActions) {
|
|
|
2890
2861
|
}
|
|
2891
2862
|
|
|
2892
2863
|
// app/assets/javascripts/source_monitor/application.js
|
|
2893
|
-
var
|
|
2894
|
-
var application = existingApplication || Application.start();
|
|
2895
|
-
if (!existingApplication) {
|
|
2896
|
-
window.SourceMonitorStimulus = application;
|
|
2897
|
-
}
|
|
2864
|
+
var application = Application.start();
|
|
2898
2865
|
application.register("notification", notification_controller_default);
|
|
2899
2866
|
application.register("notification-container", notification_container_controller_default);
|
|
2900
2867
|
application.register("async-submit", async_submit_controller_default);
|
|
@@ -2902,6 +2869,7 @@ application.register("dropdown", dropdown_controller_default);
|
|
|
2902
2869
|
application.register("modal", modal_controller_default);
|
|
2903
2870
|
application.register("confirm-navigation", confirm_navigation_controller_default);
|
|
2904
2871
|
application.register("select-all", select_all_controller_default);
|
|
2872
|
+
application.register("filter-submit", filter_submit_controller_default);
|
|
2905
2873
|
var application_default = application;
|
|
2906
2874
|
export {
|
|
2907
2875
|
application_default as default
|