parapet-rails 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +48 -0
- data/Rakefile +7 -0
- data/app/assets/config/parapet/grammar-registry.json +52 -0
- data/app/assets/images/parapet/icons/activities/component-inspector.svg +4 -0
- data/app/assets/images/parapet/icons/activities/coverage-heatmap.svg +3 -0
- data/app/assets/images/parapet/icons/activities/discovery-sidebar.svg +3 -0
- data/app/assets/images/parapet/icons/activities/environment-toggles.svg +4 -0
- data/app/assets/images/parapet/icons/activities/failure-inspector.svg +5 -0
- data/app/assets/images/parapet/icons/activities/flaky-history.svg +3 -0
- data/app/assets/images/parapet/icons/activities/flight-recorder.svg +5 -0
- data/app/assets/images/parapet/icons/activities/health-graph.svg +3 -0
- data/app/assets/images/parapet/icons/activities/injection-engine.svg +3 -0
- data/app/assets/images/parapet/icons/activities/live-sql-stream.svg +5 -0
- data/app/assets/images/parapet/icons/activities/live-web-preview.svg +4 -0
- data/app/assets/images/parapet/icons/activities/monaco-editor.svg +5 -0
- data/app/assets/images/parapet/icons/activities/progress-area.svg +3 -0
- data/app/assets/images/parapet/icons/activities/registry-metadata.svg +5 -0
- data/app/assets/images/parapet/icons/activities/seed-inspector.svg +4 -0
- data/app/assets/images/parapet/icons/activities/slow-test-bottlenecks.svg +4 -0
- data/app/assets/images/parapet/icons/activities/smart-search.svg +4 -0
- data/app/assets/images/parapet/icons/activities/snippet-library.svg +4 -0
- data/app/assets/images/parapet/icons/activities/terminal.svg +4 -0
- data/app/assets/images/parapet/icons/activities/unified-schema-view.svg +4 -0
- data/app/assets/images/parapet/icons/activities/visual-comparison.svg +3 -0
- data/app/assets/images/parapet/icons/activities/visual-summary-bar.svg +5 -0
- data/app/assets/images/parapet/icons/nav/ideas.svg +4 -0
- data/app/assets/images/parapet/icons/nav/languages.svg +8 -0
- data/app/assets/images/parapet/icons/nav/profile.svg +4 -0
- data/app/assets/images/parapet/icons/nav/pulse.svg +7 -0
- data/app/assets/images/parapet/icons/nav/settings.svg +4 -0
- data/app/assets/images/parapet/icons/nav/state.svg +5 -0
- data/app/assets/images/parapet/icons/nav/styles.svg +7 -0
- data/app/assets/images/parapet/icons/nav/tests.svg +4 -0
- data/app/assets/images/parapet/icons/nav/traffic.svg +12 -0
- data/app/assets/javascripts/parapet/activity-card.js +439 -0
- data/app/assets/javascripts/parapet/activity-cards.js +291 -0
- data/app/assets/javascripts/parapet/activity-registry.js +181 -0
- data/app/assets/javascripts/parapet/activity-toggles.js +76 -0
- data/app/assets/javascripts/parapet/application.js +37 -0
- data/app/assets/javascripts/parapet/card-failure-inspector.js +134 -0
- data/app/assets/javascripts/parapet/card-file-editor.js +1722 -0
- data/app/assets/javascripts/parapet/card-progress-area.js +297 -0
- data/app/assets/javascripts/parapet/card-smart-search.js +114 -0
- data/app/assets/javascripts/parapet/card-snippet-library.js +251 -0
- data/app/assets/javascripts/parapet/explorer-resizer.js +92 -0
- data/app/assets/javascripts/parapet/parapet_qss.js +342 -0
- data/app/assets/javascripts/parapet/proficiency-filter.js +53 -0
- data/app/assets/javascripts/parapet/sidebar-resizer.js +197 -0
- data/app/assets/javascripts/parapet/styles-workbench.js +819 -0
- data/app/assets/javascripts/parapet/tree-logic.js +320 -0
- data/app/assets/stylesheets/parapet/_qss_variables.scss +122 -0
- data/app/assets/stylesheets/parapet/parapet_qss.scss +69 -0
- data/app/assets/stylesheets/parapet/qss_application.css +260940 -0
- data/app/assets/stylesheets/parapet/qss_application.css.map +1 -0
- data/app/assets/stylesheets/parapet/qss_application.scss +5 -0
- data/app/assets/stylesheets/parapet/qss_workspace.scss +209 -0
- data/app/assets/stylesheets/parapet/sample.qss +22 -0
- data/app/controllers/parapet/application_controller.rb +54 -0
- data/app/controllers/parapet/base_controller.rb +18 -0
- data/app/controllers/parapet/build_suite/dashboard_controller.rb +10 -0
- data/app/controllers/parapet/css_suite/compiler_controller.rb +95 -0
- data/app/controllers/parapet/css_suite/dashboard_controller.rb +10 -0
- data/app/controllers/parapet/css_suite/preview_controller.rb +46 -0
- data/app/controllers/parapet/dashboard_controller.rb +8 -0
- data/app/controllers/parapet/drafts_controller.rb +30 -0
- data/app/controllers/parapet/explorers_controller.rb +53 -0
- data/app/controllers/parapet/files_controller.rb +208 -0
- data/app/controllers/parapet/footers_controller.rb +24 -0
- data/app/controllers/parapet/intentions_suite/dashboard_controller.rb +10 -0
- data/app/controllers/parapet/landing_controller.rb +14 -0
- data/app/controllers/parapet/monitor_suite/dashboard_controller.rb +10 -0
- data/app/controllers/parapet/pm_suite/publish_controller.rb +16 -0
- data/app/controllers/parapet/polyglot_suite/dashboard_controller.rb +10 -0
- data/app/controllers/parapet/runner_controller.rb +34 -0
- data/app/controllers/parapet/sessions_controller.rb +35 -0
- data/app/controllers/parapet/signal_suite/dashboard_controller.rb +10 -0
- data/app/controllers/parapet/test_suite/dashboard_controller.rb +10 -0
- data/app/controllers/parapet/widgets_controller.rb +33 -0
- data/app/helpers/parapet/application_helper.rb +23 -0
- data/app/helpers/parapet/icon_helper.rb +57 -0
- data/app/jobs/parapet/application_job.rb +4 -0
- data/app/mailers/parapet/application_mailer.rb +6 -0
- data/app/models/parapet/activity.rb +14 -0
- data/app/models/parapet/application_record.rb +5 -0
- data/app/models/parapet/current.rb +6 -0
- data/app/models/parapet/draft_recovery.rb +9 -0
- data/app/models/parapet/internal_record.rb +34 -0
- data/app/models/parapet/run_history.rb +22 -0
- data/app/models/parapet/runtime_setting.rb +8 -0
- data/app/models/parapet/session.rb +7 -0
- data/app/models/parapet/suite_assignment.rb +30 -0
- data/app/models/parapet/user.rb +12 -0
- data/app/services/parapet/activity_phrase_renderer.rb +35 -0
- data/app/services/parapet/activity_writer.rb +26 -0
- data/app/services/parapet/authorization.rb +198 -0
- data/app/services/parapet/consistency_auditor.rb +58 -0
- data/app/services/parapet/directory_scanner.rb +159 -0
- data/app/services/parapet/draft_recovery_store.rb +18 -0
- data/app/services/parapet/explorer_manager.rb +402 -0
- data/app/services/parapet/file_save_service.rb +21 -0
- data/app/services/parapet/git_side_ref_committer.rb +50 -0
- data/app/services/parapet/noun_discovery.rb +26 -0
- data/app/services/parapet/publish_gate.rb +83 -0
- data/app/services/parapet/test_runner.rb +178 -0
- data/app/views/layouts/parapet/application.html.erb +83 -0
- data/app/views/layouts/parapet/landing.html.erb +19 -0
- data/app/views/parapet/activities/_ai_error_explainer.html.erb +33 -0
- data/app/views/parapet/activities/_ai_explainer_widget.html.erb +20 -0
- data/app/views/parapet/activities/_calendar_widget.html.erb +31 -0
- data/app/views/parapet/activities/_code_snippets_widget.html.erb +22 -0
- data/app/views/parapet/activities/_coverage_explorer.html.erb +1 -0
- data/app/views/parapet/activities/_dropdown_test.html.erb +20 -0
- data/app/views/parapet/activities/_explorer_node.html.erb +102 -0
- data/app/views/parapet/activities/_explorer_tree.html.erb +16 -0
- data/app/views/parapet/activities/_file_editor.html.erb +183 -0
- data/app/views/parapet/activities/_file_explorer.html.erb +23 -0
- data/app/views/parapet/activities/_fix_suggestions_widget.html.erb +13 -0
- data/app/views/parapet/activities/_generic.html.erb +6 -0
- data/app/views/parapet/activities/_live_preview.html.erb +13 -0
- data/app/views/parapet/activities/_perspective_filters.html.erb +36 -0
- data/app/views/parapet/activities/_progress_area.html.erb +37 -0
- data/app/views/parapet/activities/_project_explorer.html.erb +1 -0
- data/app/views/parapet/activities/_registry_explorer.html.erb +1 -0
- data/app/views/parapet/activities/_run_history.html.erb +2 -0
- data/app/views/parapet/activities/_smart_search.html.erb +11 -0
- data/app/views/parapet/activities/file_explorer/_perspective_scripts.html.erb +58 -0
- data/app/views/parapet/activities/file_explorer/_perspectives.html.erb +0 -0
- data/app/views/parapet/activities/file_explorer/_viewport_scripts.html.erb +33 -0
- data/app/views/parapet/css_suite/_workbench.html.erb +51 -0
- data/app/views/parapet/dashboards/index.html.erb +113 -0
- data/app/views/parapet/debug_panel.html.erb +79 -0
- data/app/views/parapet/debug_panel_tailwind.html.erb +98 -0
- data/app/views/parapet/erb_patch_test.html.erb +5 -0
- data/app/views/parapet/explorers/show.html.erb +1 -0
- data/app/views/parapet/git_viewer.html.erb +62 -0
- data/app/views/parapet/git_viewer_after.html.erb +14 -0
- data/app/views/parapet/git_viewer_before.html.erb +14 -0
- data/app/views/parapet/git_viewer_governed.html.erb +88 -0
- data/app/views/parapet/git_viewer_governed_after.html.erb +36 -0
- data/app/views/parapet/git_viewer_governed_before.html.erb +36 -0
- data/app/views/parapet/git_viewer_tailwind.html.erb +88 -0
- data/app/views/parapet/git_viewer_thin_wrapper.html.erb +85 -0
- data/app/views/parapet/hierarchical_layout_test.html.erb +85 -0
- data/app/views/parapet/hybrid_stress_test.html.erb +25 -0
- data/app/views/parapet/index.html.erb +35 -0
- data/app/views/parapet/mutation_stress_test.html.erb +82 -0
- data/app/views/parapet/recursive_anchoring_test.html.erb +66 -0
- data/app/views/parapet/sessions/new.html.erb +28 -0
- data/app/views/parapet/shared/_cad_inspector.html.erb +92 -0
- data/app/views/parapet/shared/_discovery_sidebar.html.erb +48 -0
- data/app/views/parapet/shared/_explorer_bar.html.erb +71 -0
- data/app/views/parapet/shared/_footer.html.erb +10 -0
- data/app/views/parapet/shared/_footer_ideas.html.erb +36 -0
- data/app/views/parapet/shared/_footer_languages.html.erb +33 -0
- data/app/views/parapet/shared/_footer_pulse.html.erb +33 -0
- data/app/views/parapet/shared/_footer_state.html.erb +33 -0
- data/app/views/parapet/shared/_footer_styles.html.erb +37 -0
- data/app/views/parapet/shared/_footer_tests.html.erb +39 -0
- data/app/views/parapet/shared/_footer_traffic.html.erb +45 -0
- data/app/views/parapet/shared/_global_nav.html.erb +55 -0
- data/app/views/parapet/shared/_head.html.erb +4 -0
- data/app/views/parapet/shared/_header.html.erb +20 -0
- data/app/views/parapet/shared/_object_inspector.html.erb +76 -0
- data/app/views/parapet/shared/_ribbon_header.html.erb +3 -0
- data/app/views/parapet/shared/_root_selector_modal.html.erb +15 -0
- data/app/views/parapet/shared/_tab_bar.html.erb +62 -0
- data/app/views/parapet/shared/activities_ribbon/_agent_group.html.erb +15 -0
- data/app/views/parapet/shared/activities_ribbon/_analysis_group.html.erb +15 -0
- data/app/views/parapet/shared/activities_ribbon/_architect_group.html.erb +21 -0
- data/app/views/parapet/shared/activities_ribbon/_explorer_group.html.erb +12 -0
- data/app/views/parapet/shared/activities_ribbon/_inspector_group.html.erb +15 -0
- data/app/views/parapet/shared/activities_ribbon/_proficiency_filter.html.erb +24 -0
- data/app/views/parapet/shared/activities_ribbon/_runner_group.html.erb +21 -0
- data/app/views/parapet/shared/activities_ribbon/_spatial_inspector_group.html.erb +18 -0
- data/app/views/parapet/shared/activities_ribbon/_studio_group.html.erb +18 -0
- data/app/views/parapet/shared/activities_ribbon/_stylist_group.html.erb +18 -0
- data/app/views/parapet/shared/explorers/_base.html.erb +107 -0
- data/app/views/parapet/shared/explorers/_css.html.erb +1 -0
- data/app/views/parapet/shared/explorers/_intentions.html.erb +1 -0
- data/app/views/parapet/shared/explorers/_project.html.erb +1 -0
- data/app/views/parapet/shared/explorers/_tests.html.erb +1 -0
- data/app/views/parapet/shared/head/_meta.html.erb +3 -0
- data/app/views/parapet/shared/head/_styles_activities.html.erb +152 -0
- data/app/views/parapet/shared/head/_styles_shared.html.erb +52 -0
- data/app/views/parapet/shared/head/_styles_workspace.html.erb +67 -0
- data/app/views/parapet/shared/ribbon_header/_diagnostic_controls.html.erb +17 -0
- data/app/views/parapet/shared/ribbon_header/_execution_controls.html.erb +28 -0
- data/app/views/parapet/shared/ribbon_header/_focus_search.html.erb +5 -0
- data/app/views/parapet/shared/root_selector/_header.html.erb +10 -0
- data/app/views/parapet/shared/root_selector/_path_input.html.erb +13 -0
- data/app/views/parapet/shared/root_selector/_quick_select.html.erb +20 -0
- data/app/views/parapet/shared/root_selector/_scripts.html.erb +61 -0
- data/app/views/parapet/shared/root_selector/_warning.html.erb +11 -0
- data/app/views/parapet/shared/widgets/_base.html.erb +6 -0
- data/app/views/parapet/shared/widgets/_css.html.erb +79 -0
- data/app/views/parapet/widgets/_explainer.html.erb +17 -0
- data/app/views/parapet/widgets/_hotkeys.html.erb +20 -0
- data/app/views/parapet/widgets/_search.html.erb +68 -0
- data/app/views/parapet/widgets/_spatial_inspector.html.erb +54 -0
- data/app/views/parapet/widgets/_widget-explainer.html.erb +17 -0
- data/app/views/parapet/widgets/_widget-hotkeys.html.erb +20 -0
- data/app/views/parapet/widgets/_widget-search.html.erb +68 -0
- data/app/views/parapet/widgets/_widget-snippets.html.erb +18 -0
- data/app/views/parapet/widgets/_widget-suggestions.html.erb +15 -0
- data/app/views/parapet/widgets/show.html.erb +3 -0
- data/app/views/shared/_footer.html.erb +0 -0
- data/config/parapet/qss_config.yml +117 -0
- data/config/parapet/qss_registry.yml +14 -0
- data/config/routes.rb +40 -0
- data/db/migrate/20260916035300_create_run_histories.rb +16 -0
- data/db/migrate/20261002000000_expand_run_histories_for_activity_tracking.rb +7 -0
- data/db/parapet_migrate/20260929184200_create_parapet_users.rb +12 -0
- data/db/parapet_migrate/20260929184300_create_parapet_sessions.rb +9 -0
- data/db/parapet_migrate/20260930000000_create_parapet_runtime_settings.rb +12 -0
- data/db/parapet_migrate/20260930000100_create_parapet_suite_assignments.rb +14 -0
- data/db/parapet_migrate/20261002000000_create_parapet_activities.rb +16 -0
- data/db/parapet_migrate/20261002000100_create_parapet_draft_recoveries.rb +13 -0
- data/db/parapet_schema.rb +64 -0
- data/db/schema.rb +21 -0
- data/db/schema.released.rb +0 -0
- data/lib/parapet/engine.rb +11 -0
- data/lib/parapet/environment_guard.rb +14 -0
- data/lib/parapet/version.rb +3 -0
- data/lib/parapet-rails.rb +1 -0
- data/lib/parapet.rb +59 -0
- data/lib/tasks/parapet_qss.rake +26 -0
- data/lib/tasks/parapet_tasks.rake +25 -0
- data/lib/tasks/randomize_explorer_health.rb +101 -0
- metadata +423 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
class DiagnosticAreaCard extends ActivityCard {
|
|
3
|
+
get cardTitle() { return 'Diagnostic Area'; }
|
|
4
|
+
get cardKeyArea() { return 'Runner'; }
|
|
5
|
+
get cardProficiency() { return 0; }
|
|
6
|
+
get cardIcon() {
|
|
7
|
+
return `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
8
|
+
<path class="icon-path" d="M22 12H18L15 21L9 3L6 12H2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
</svg>`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
defaults() {
|
|
13
|
+
return Object.assign({}, super.defaults(), {
|
|
14
|
+
width: 500, height: 300,
|
|
15
|
+
minWidth: 350, minHeight: 180,
|
|
16
|
+
lastRun: null
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
buildContent() {
|
|
21
|
+
return `
|
|
22
|
+
<div class="qss-progress-area-container qss-flex qss-flex-col qss-h-full qss-bg-[#111418] qss-text-size[11] qss-font-mono qss-overflow-hidden">
|
|
23
|
+
<!-- Control Bar -->
|
|
24
|
+
<div class="qss-flex qss-items-center qss-justify-between qss-px[12] qss-py[8] qss-border-b qss-border-slate-800 qss-bg-[#16191e]/50">
|
|
25
|
+
<div class="qss-flex qss-items-center qss-gap[8]">
|
|
26
|
+
<div class="qss-test-triggers qss-flex qss-items-center qss-gap[8]">
|
|
27
|
+
<!-- Dynamic buttons will be injected here -->
|
|
28
|
+
<div class="qss-animate-pulse qss-w[64] qss-h[20] qss-bg-slate-800 qss-rounded"></div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="qss-w[1] qss-h[16] qss-bg-slate-800 qss-mx[4]"></div>
|
|
31
|
+
<div class="qss-status-indicator qss-flex qss-items-center qss-gap[8] qss-text-slate-500 qss-italic">
|
|
32
|
+
<span class="qss-status-text">Idle</span>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="qss-flex qss-items-center qss-gap[8]">
|
|
36
|
+
<button class="qss-clear-btn qss-text-slate-600 hover:qss-text-white qss-transition-colors qss-p[4]" title="Clear Console">
|
|
37
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="qss-w[12] qss-h[12]"><path d="M3 6h18m-2 0v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6m3 0V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2m-6 5v6m4-6v6"/></svg>
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<!-- Output Console -->
|
|
43
|
+
<div class="qss-output-console qss-flex-grow qss-overflow-y-auto qss-p[12] qss-space-y[2] qss-custom-scrollbar qss-bg-black/20">
|
|
44
|
+
<div class="qss-text-slate-600 qss-italic qss-uppercase qss-tracking-widest qss-text-size[9] qss-mb[8] qss-border-b qss-border-slate-800/50 qss-pb[4]">System Output</div>
|
|
45
|
+
<div class="qss-console-lines qss-flex qss-flex-col qss-gap[2]">
|
|
46
|
+
<div class="qss-text-slate-500">Ready for execution.</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Summary Stats (Footer) -->
|
|
51
|
+
<div class="qss-stats-footer qss-h[32] qss-px[12] qss-border-t qss-border-slate-800 qss-bg-[#0b0d11] qss-flex qss-items-center qss-justify-between qss-overflow-hidden">
|
|
52
|
+
<div class="qss-flex qss-items-center qss-gap[16]">
|
|
53
|
+
<div class="qss-flex qss-items-center qss-gap[6]">
|
|
54
|
+
<div class="qss-w[6] qss-h[6] qss-rounded-full qss-bg-emerald-500"></div>
|
|
55
|
+
<span class="qss-text-slate-400"><strong class="qss-pass-count qss-text-slate-200 qss-font-bold">0</strong> Passing</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="qss-flex qss-items-center qss-gap[6]">
|
|
58
|
+
<div class="qss-w[6] qss-h[6] qss-rounded-full qss-bg-red-500 qss-shadow-[0_0_8px_rgba(239,68,68,0.4)]"></div>
|
|
59
|
+
<span class="qss-text-slate-400"><strong class="qss-fail-count qss-text-slate-200 qss-font-bold">0</strong> Failing</span>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="qss-run-time qss-text-slate-600 qss-italic qss-text-size[10]">--</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
onInit() {
|
|
69
|
+
this.triggerContainer = this.element.querySelector('.qss-test-triggers');
|
|
70
|
+
this.clearBtn = this.element.querySelector('.qss-clear-btn');
|
|
71
|
+
this.consoleLines = this.element.querySelector('.qss-console-lines');
|
|
72
|
+
this.statusText = this.element.querySelector('.qss-status-text');
|
|
73
|
+
|
|
74
|
+
this.clearBtn.addEventListener('click', () => this.clearConsole());
|
|
75
|
+
this.detectFrameworks();
|
|
76
|
+
|
|
77
|
+
// Global listener for "Run Test" requests from other cards
|
|
78
|
+
this._onRunRequest = (e) => {
|
|
79
|
+
if (e.detail && e.detail.path) {
|
|
80
|
+
this.runTests(e.detail.path);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
document.addEventListener('parapet:runTest', this._onRunRequest);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
onDestroy() {
|
|
87
|
+
if (this._onRunRequest) document.removeEventListener('parapet:runTest', this._onRunRequest);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async detectFrameworks() {
|
|
91
|
+
try {
|
|
92
|
+
const response = await fetch('/runner/detect');
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
|
|
95
|
+
this.triggerContainer.innerHTML = '';
|
|
96
|
+
|
|
97
|
+
if (data.frameworks.length === 0) {
|
|
98
|
+
this.triggerContainer.innerHTML = '<span class="qss-text-slate-600 qss-italic qss-text-[9px]">No tests detected</span>';
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
data.frameworks.forEach(fw => {
|
|
103
|
+
const btn = document.createElement('button');
|
|
104
|
+
const colorMap = {
|
|
105
|
+
red: 'qss-bg-red-600/20 qss-text-red-400 qss-border-red-500/30 hover:qss-bg-red-600/30',
|
|
106
|
+
blue: 'qss-bg-blue-600/20 qss-text-blue-400 qss-border-blue-500/30 hover:qss-bg-blue-600/30',
|
|
107
|
+
emerald: 'qss-bg-emerald-600/20 qss-text-emerald-400 qss-border-emerald-500/30 hover:qss-bg-emerald-600/30',
|
|
108
|
+
amber: 'qss-bg-amber-600/20 qss-text-amber-400 qss-border-amber-500/30 hover:qss-bg-amber-600/30',
|
|
109
|
+
indigo: 'qss-bg-indigo-600/20 qss-text-indigo-400 qss-border-indigo-500/30 hover:qss-bg-indigo-600/30',
|
|
110
|
+
slate: 'qss-bg-slate-600/20 qss-text-slate-400 qss-border-slate-500/30 hover:qss-bg-slate-600/30',
|
|
111
|
+
orange: 'qss-bg-orange-600/20 qss-text-orange-400 qss-border-orange-500/30 hover:qss-bg-orange-600/30',
|
|
112
|
+
cyan: 'qss-bg-cyan-600/20 qss-text-cyan-400 qss-border-cyan-500/30 hover:qss-bg-cyan-600/30',
|
|
113
|
+
rose: 'qss-bg-rose-600/20 qss-text-rose-400 qss-border-rose-500/30 hover:qss-bg-rose-600/30',
|
|
114
|
+
lime: 'qss-bg-lime-600/20 qss-text-lime-400 qss-border-lime-500/30 hover:qss-bg-lime-600/30',
|
|
115
|
+
pink: 'qss-bg-pink-600/20 qss-text-pink-400 qss-border-pink-500/30 hover:qss-bg-pink-600/30',
|
|
116
|
+
teal: 'qss-bg-teal-600/20 qss-text-teal-400 qss-border-teal-500/30 hover:qss-bg-teal-600/30',
|
|
117
|
+
violet: 'qss-bg-violet-600/20 qss-text-violet-400 qss-border-violet-500/30 hover:qss-bg-violet-600/30',
|
|
118
|
+
sky: 'qss-bg-sky-600/20 qss-text-sky-400 qss-border-sky-500/30 hover:qss-bg-sky-600/30'
|
|
119
|
+
};
|
|
120
|
+
const colorClasses = colorMap[fw.color] || colorMap.blue;
|
|
121
|
+
|
|
122
|
+
btn.className = `qss-run-btn qss-flex qss-items-center qss-gap-1.5 qss-px-2 qss-py-1 qss-border qss-rounded qss-transition-all active:qss-scale-95 ${colorClasses}`;
|
|
123
|
+
btn.dataset.command = fw.id;
|
|
124
|
+
btn.innerHTML = `<span class="qss-font-bold qss-uppercase qss-tracking-wider qss-text-[9px]">${fw.name}</span>`;
|
|
125
|
+
|
|
126
|
+
btn.addEventListener('click', () => this.runTests(null, fw.id));
|
|
127
|
+
this.triggerContainer.appendChild(btn);
|
|
128
|
+
});
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error("Framework detection failed", err);
|
|
131
|
+
this.triggerContainer.innerHTML = '<span class="qss-text-red-400 qss-italic">Detection failed</span>';
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async runTests(path = null, command = null) {
|
|
136
|
+
if (this._running) return;
|
|
137
|
+
this._running = true;
|
|
138
|
+
|
|
139
|
+
const btns = this.triggerContainer.querySelectorAll('button');
|
|
140
|
+
btns.forEach(btn => {
|
|
141
|
+
btn.disabled = true;
|
|
142
|
+
btn.classList.add('qss-opacity-50', 'qss-grayscale');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const statusMessages = {
|
|
146
|
+
'rspec': 'Executing Tests...',
|
|
147
|
+
'cucumber': 'Running Scenarios...',
|
|
148
|
+
'minitest': 'Running Tests...',
|
|
149
|
+
'rubocop': 'Inspecting Style...',
|
|
150
|
+
'standardrb': 'Checking Standards...',
|
|
151
|
+
'brakeman': 'Scanning Security...',
|
|
152
|
+
'zeitwerk': 'Checking Autoloads...',
|
|
153
|
+
'bundle_audit': 'Auditing Gems...',
|
|
154
|
+
'rails_best_practices': 'Analyzing Quality...',
|
|
155
|
+
'factory_bot_lint': 'Linting Factories...',
|
|
156
|
+
'erb_lint': 'Inspecting Templates...',
|
|
157
|
+
'database_consistency': 'Checking DB Health...',
|
|
158
|
+
'i18n_tasks': 'Checking Translations...'
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
this.statusText.textContent = statusMessages[command] || "Running...";
|
|
162
|
+
this.statusText.className = "qss-status-text qss-text-amber-400 qss-animate-pulse";
|
|
163
|
+
|
|
164
|
+
const logCommand = command || (path ? 'test' : 'run all');
|
|
165
|
+
this.log(`> Parapet executing ${logCommand}...`, 'qss-text-indigo-400 qss-font-bold qss-mt-2');
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content;
|
|
169
|
+
const response = await fetch('/runner/execute', {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: {
|
|
172
|
+
'Content-Type': 'application/json',
|
|
173
|
+
'X-CSRF-Token': csrfToken
|
|
174
|
+
},
|
|
175
|
+
body: JSON.stringify({ path: path, command: command })
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const data = await response.json();
|
|
179
|
+
|
|
180
|
+
if (data.status === 'success') {
|
|
181
|
+
// Speed up the simulation for high-output tools
|
|
182
|
+
const delay = data.output.length > 50 ? 15 : 40;
|
|
183
|
+
|
|
184
|
+
for (const line of data.output) {
|
|
185
|
+
await new Promise(r => setTimeout(r, delay));
|
|
186
|
+
|
|
187
|
+
let colorClass = 'qss-text-slate-400';
|
|
188
|
+
let canClick = false;
|
|
189
|
+
|
|
190
|
+
if (line.type === 'pass') colorClass = 'qss-text-emerald-500 qss-inline-block qss-mr-0.5';
|
|
191
|
+
if (line.type === 'fail' || line.type === 'error') {
|
|
192
|
+
colorClass = 'qss-text-red-500 qss-font-bold qss-inline-block qss-mr-0.5 qss-cursor-pointer hover:qss-underline hover:qss-scale-110 qss-transition-transform';
|
|
193
|
+
canClick = true;
|
|
194
|
+
}
|
|
195
|
+
if (line.type === 'lint') {
|
|
196
|
+
colorClass = 'qss-text-slate-500 qss-cursor-pointer hover:qss-text-indigo-400 hover:qss-underline qss-transition-colors';
|
|
197
|
+
canClick = true;
|
|
198
|
+
}
|
|
199
|
+
if (line.type === 'summary') {
|
|
200
|
+
if (line.text.includes('Finished')) colorClass = 'qss-text-slate-200 qss-border-t qss-border-slate-800 qss-mt-2 qss-pt-1';
|
|
201
|
+
else colorClass = 'qss-text-slate-100 qss-font-bold';
|
|
202
|
+
}
|
|
203
|
+
if (line.type === 'info' && line.text.startsWith('>')) colorClass = 'qss-text-indigo-400 qss-font-bold qss-mt-2';
|
|
204
|
+
|
|
205
|
+
const el = this.log(line.text, colorClass, line.type === 'pass' || line.type === 'fail' || line.type === 'error');
|
|
206
|
+
|
|
207
|
+
if (canClick && el) {
|
|
208
|
+
el.title = `Click to reveal: ${line.file}:${line.line} - ${line.message}`;
|
|
209
|
+
el.addEventListener('click', () => {
|
|
210
|
+
document.dispatchEvent(new CustomEvent('parapet:revealLine', {
|
|
211
|
+
detail: { path: line.file, line: line.line, message: line.message }
|
|
212
|
+
}));
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Auto-dispatch to Failure Inspector if it's a failure
|
|
216
|
+
if (line.type === 'fail' || line.type === 'error' || line.type === 'lint') {
|
|
217
|
+
document.dispatchEvent(new CustomEvent('parapet:failureFound', {
|
|
218
|
+
detail: { path: line.file, line: line.line, message: line.message }
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
this.updateStats(data.summary);
|
|
225
|
+
const hasFailures = data.summary.failures > 0 || data.summary.errors > 0;
|
|
226
|
+
this.statusText.textContent = hasFailures ? "Failures Detected" : "Success";
|
|
227
|
+
this.statusText.className = `qss-status-text ${hasFailures ? 'qss-text-red-400' : 'qss-text-emerald-400'}`;
|
|
228
|
+
} else {
|
|
229
|
+
this.log(`Error: ${data.error}`, 'qss-text-red-500 qss-font-bold');
|
|
230
|
+
this.statusText.textContent = "Error";
|
|
231
|
+
this.statusText.className = "qss-status-text qss-text-red-500";
|
|
232
|
+
}
|
|
233
|
+
} catch (err) {
|
|
234
|
+
console.error("Test runner failed", err);
|
|
235
|
+
this.log("Network Error: Could not reach test runner", 'qss-text-red-500 qss-font-bold');
|
|
236
|
+
this.statusText.textContent = "Network Error";
|
|
237
|
+
this.statusText.className = "qss-status-text qss-text-red-500";
|
|
238
|
+
} finally {
|
|
239
|
+
this._running = false;
|
|
240
|
+
const btns = this.triggerContainer.querySelectorAll('button');
|
|
241
|
+
btns.forEach(btn => {
|
|
242
|
+
btn.disabled = false;
|
|
243
|
+
btn.classList.remove('qss-opacity-50', 'qss-grayscale');
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
log(message, className = 'qss-text-slate-400', inline = false) {
|
|
249
|
+
const div = document.createElement(inline ? 'span' : 'div');
|
|
250
|
+
div.className = className;
|
|
251
|
+
div.textContent = message;
|
|
252
|
+
|
|
253
|
+
// If inline, we might need a container if the last child isn't an inline-container
|
|
254
|
+
if (inline) {
|
|
255
|
+
let last = this.consoleLines.lastElementChild;
|
|
256
|
+
if (!last || !last.classList.contains('qss-inline-row')) {
|
|
257
|
+
last = document.createElement('div');
|
|
258
|
+
last.className = 'qss-inline-row qss-flex qss-flex-wrap';
|
|
259
|
+
this.consoleLines.appendChild(last);
|
|
260
|
+
}
|
|
261
|
+
last.appendChild(div);
|
|
262
|
+
} else {
|
|
263
|
+
this.consoleLines.appendChild(div);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Auto scroll
|
|
267
|
+
const console = this.element.querySelector('.qss-output-console');
|
|
268
|
+
console.scrollTop = console.scrollHeight;
|
|
269
|
+
return div;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
clearConsole() {
|
|
273
|
+
this.consoleLines.innerHTML = '<div class="qss-text-slate-600 qss-italic">Console cleared.</div>';
|
|
274
|
+
this.statusText.textContent = "Idle";
|
|
275
|
+
this.statusText.className = "qss-status-text qss-text-slate-500 qss-italic";
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
updateStats(summary) {
|
|
279
|
+
const passEl = this.element.querySelector('.qss-pass-count');
|
|
280
|
+
const failEl = this.element.querySelector('.qss-fail-count');
|
|
281
|
+
const timeEl = this.element.querySelector('.qss-run-time');
|
|
282
|
+
|
|
283
|
+
if (passEl) passEl.textContent = summary.runs - (summary.failures + summary.errors);
|
|
284
|
+
if (failEl) failEl.textContent = summary.failures + summary.errors;
|
|
285
|
+
if (timeEl) timeEl.textContent = `${(Math.random() * 0.5 + 0.1).toFixed(2)}s`;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
onDestroy() {
|
|
289
|
+
if (this._onRunRequest) {
|
|
290
|
+
document.removeEventListener('parapet:runTest', this._onRunRequest);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
DiagnosticAreaCard.cardId = 'progress-area';
|
|
296
|
+
ActivityCards.registry['progress-area'] = DiagnosticAreaCard;
|
|
297
|
+
})();
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
class SmartSearchCard extends ActivityCard {
|
|
3
|
+
get cardId() { return 'smart-search'; }
|
|
4
|
+
get cardTitle() { return 'Smart Search'; }
|
|
5
|
+
get cardIcon() { return `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path class="icon-path" d="M11 19C15.4183 19 19 15.4183 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19Z" stroke="currentColor" stroke-width="2"/><path class="icon-path" d="M21 21L16.65 16.65" stroke="currentColor" stroke-width="2"/></svg>`; }
|
|
6
|
+
get cardKeyArea() { return 'Explorer'; }
|
|
7
|
+
get cardProficiency() { return 2; }
|
|
8
|
+
|
|
9
|
+
defaults() {
|
|
10
|
+
return Object.assign({}, super.defaults(), {
|
|
11
|
+
width: 320,
|
|
12
|
+
height: 400,
|
|
13
|
+
minWidth: 280,
|
|
14
|
+
minHeight: 300
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
buildContent() {
|
|
19
|
+
return `
|
|
20
|
+
<div class="qss-flex qss-flex-col qss-h-full qss-bg-[#111418]">
|
|
21
|
+
<!-- Search Input Area -->
|
|
22
|
+
<div class="qss-p-3 qss-border-b qss-border-slate-800/50">
|
|
23
|
+
<div class="qss-relative qss-group">
|
|
24
|
+
<input type="text"
|
|
25
|
+
class="qss-w-full qss-bg-[#0f1115] qss-border qss-border-slate-700/50 qss-rounded qss-px-8 qss-py-1.5 qss-text-[11px] qss-text-slate-300 focus:qss-outline-none focus:qss-border-indigo-500/50 qss-transition-all placeholder:qss-text-slate-600"
|
|
26
|
+
placeholder="Ask anything or search code...">
|
|
27
|
+
<div class="qss-absolute qss-left-2.5 qss-top-1/2 qss--translate-y-1/2 qss-text-slate-500 group-focus-within:qss-text-indigo-400 qss-transition-colors">
|
|
28
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
29
|
+
<circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
30
|
+
</svg>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="qss-flex qss-gap-1.5 qss-mt-2 qss-overflow-x-auto qss-pb-1 no-scrollbar">
|
|
34
|
+
<span class="qss-text-[9px] qss-bg-slate-800/50 qss-text-slate-400 qss-px-1.5 qss-py-0.5 qss-rounded qss-border qss-border-slate-700/30 qss-whitespace-nowrap qss-cursor-pointer hover:qss-bg-slate-700/50 qss-transition-colors">Files</span>
|
|
35
|
+
<span class="qss-text-[9px] qss-bg-slate-800/50 qss-text-slate-400 qss-px-1.5 qss-py-0.5 qss-rounded qss-border qss-border-slate-700/30 qss-whitespace-nowrap qss-cursor-pointer hover:qss-bg-slate-700/50 qss-transition-colors">Symbols</span>
|
|
36
|
+
<span class="qss-text-[9px] qss-bg-slate-800/50 qss-text-slate-400 qss-px-1.5 qss-py-0.5 qss-rounded qss-border qss-border-slate-700/30 qss-whitespace-nowrap qss-cursor-pointer hover:qss-bg-slate-700/50 qss-transition-colors">AI Help</span>
|
|
37
|
+
<span class="qss-text-[9px] qss-bg-slate-800/50 qss-text-slate-400 qss-px-1.5 qss-py-0.5 qss-rounded qss-border qss-border-slate-700/30 qss-whitespace-nowrap qss-cursor-pointer hover:qss-bg-slate-700/50 qss-transition-colors">Tests</span>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<!-- Results / Suggestions Area -->
|
|
42
|
+
<div class="qss-flex-1 qss-overflow-y-auto qss-p-2 qss-custom-scrollbar qss-space-y-3">
|
|
43
|
+
<!-- Recent Activity Section -->
|
|
44
|
+
<div>
|
|
45
|
+
<div class="qss-text-[9px] qss-font-bold qss-text-slate-500 qss-uppercase qss-tracking-widest qss-px-1 qss-mb-2">Recent & Relevant</div>
|
|
46
|
+
<div class="qss-space-y-1">
|
|
47
|
+
<div class="qss-flex qss-items-center qss-gap-2 qss-p-1.5 qss-rounded hover:qss-bg-white/5 qss-cursor-pointer qss-group qss-transition-colors">
|
|
48
|
+
<div class="qss-w-6 qss-h-6 qss-rounded qss-bg-indigo-500/10 qss-flex qss-items-center qss-justify-center qss-text-indigo-400">
|
|
49
|
+
<i class="lucide-file-text w-3 h-3"></i>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="qss-flex-1 qss-min-w-0">
|
|
52
|
+
<div class="qss-text-[10px] qss-text-slate-300 qss-truncate">dashboard_controller.rb</div>
|
|
53
|
+
<div class="qss-text-[8px] qss-text-slate-500 qss-truncate">app/controllers/parapet/</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="qss-flex qss-items-center qss-gap-2 qss-p-1.5 qss-rounded hover:qss-bg-white/5 qss-cursor-pointer qss-group qss-transition-colors">
|
|
57
|
+
<div class="qss-w-6 qss-h-6 qss-rounded qss-bg-emerald-500/10 qss-flex qss-items-center qss-justify-center qss-text-emerald-400">
|
|
58
|
+
<i class="lucide-test-tube w-3 h-3"></i>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="qss-flex-1 qss-min-w-0">
|
|
61
|
+
<div class="qss-text-[10px] qss-text-slate-300 qss-truncate">index_spec.rb</div>
|
|
62
|
+
<div class="qss-text-[8px] qss-text-slate-500 qss-truncate">spec/views/parapet/dashboard/</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<!-- Suggested Queries Section -->
|
|
69
|
+
<div>
|
|
70
|
+
<div class="qss-text-[9px] qss-font-bold qss-text-slate-500 qss-uppercase qss-tracking-widest qss-px-1 qss-mb-2">Try searching for...</div>
|
|
71
|
+
<div class="qss-grid qss-grid-cols-1 qss-gap-1">
|
|
72
|
+
<div class="qss-text-[10px] qss-text-slate-400 qss-bg-white/5 qss-p-2 qss-rounded qss-border qss-border-slate-700/20 hover:qss-border-indigo-500/30 qss-cursor-pointer qss-transition-all">
|
|
73
|
+
"How do I add a new activity card?"
|
|
74
|
+
</div>
|
|
75
|
+
<div class="qss-text-[10px] qss-text-slate-400 qss-bg-white/5 qss-p-2 qss-rounded qss-border qss-border-slate-700/20 hover:qss-border-indigo-500/30 qss-cursor-pointer qss-transition-all">
|
|
76
|
+
"Find all Novice proficiency elements"
|
|
77
|
+
</div>
|
|
78
|
+
<div class="qss-text-[10px] qss-text-slate-400 qss-bg-white/5 qss-p-2 qss-rounded qss-border qss-border-slate-700/20 hover:qss-border-indigo-500/30 qss-cursor-pointer qss-transition-all">
|
|
79
|
+
"Show me where routes are defined"
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<!-- Footer / Status -->
|
|
86
|
+
<div class="qss-px-3 qss-py-2 qss-border-t qss-border-slate-800/50 qss-bg-[#0f1115]/50 qss-flex qss-items-center qss-justify-between">
|
|
87
|
+
<div class="qss-flex qss-items-center qss-gap-1.5 qss-text-[9px] qss-text-slate-500">
|
|
88
|
+
<div class="qss-w-1.5 qss-h-1.5 qss-rounded-full qss-bg-emerald-500/50"></div>
|
|
89
|
+
<span>AI Index Ready</span>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="qss-text-[9px] qss-text-slate-600">
|
|
92
|
+
<span class="qss-bg-slate-800 qss-px-1 qss-rounded qss-border qss-border-slate-700/50">⌘K</span>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
onInit() {
|
|
100
|
+
// Future interaction logic for stub
|
|
101
|
+
const input = this.element.querySelector('input');
|
|
102
|
+
if (input) {
|
|
103
|
+
input.addEventListener('keydown', (e) => {
|
|
104
|
+
if (e.key === 'Enter') {
|
|
105
|
+
// Simulated search
|
|
106
|
+
console.log('Smart search for:', input.value);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
ActivityCards.registry['smart-search'] = SmartSearchCard;
|
|
114
|
+
})();
|