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,5 @@
|
|
|
1
|
+
@import "qss_variables"; // Parapet's QSS settings, before core so they win over core's !default values
|
|
2
|
+
@import "qss/qss_core"; // from the qss gem (QSS.stylesheets_path on the Sass load path)
|
|
3
|
+
@import "parapet_qss";
|
|
4
|
+
@import "qss_workspace";
|
|
5
|
+
/* Cache Buster: <%= Time.now.to_i %> */
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--header-h: 60px;
|
|
3
|
+
--novice: #10B981;
|
|
4
|
+
--intermediate: #F59E0B;
|
|
5
|
+
--advanced: #EF4444;
|
|
6
|
+
--power: #8B5CF6;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* Structural Layout Integrity */
|
|
10
|
+
#pp-main-root,
|
|
11
|
+
#pp-header,
|
|
12
|
+
#pp-header-inner,
|
|
13
|
+
#pp-header-branding,
|
|
14
|
+
#pp-header-tagline,
|
|
15
|
+
#pp-header-ribbon,
|
|
16
|
+
#pp-workspace-layers,
|
|
17
|
+
#pp-workspace-content,
|
|
18
|
+
#pp-inspector-bar,
|
|
19
|
+
#pp-code-source,
|
|
20
|
+
#pp-code-compiled,
|
|
21
|
+
#pp-footer,
|
|
22
|
+
#pp-preview-iframe {
|
|
23
|
+
contain: layout;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Header & Ribbon Structural Layout (Compiled) */
|
|
27
|
+
.qss-header-inner {
|
|
28
|
+
display: flex;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
align-items: center;
|
|
33
|
+
padding-left: 0.75rem;
|
|
34
|
+
padding-right: 0.75rem;
|
|
35
|
+
justify-content: space-between;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.qss-header-branding {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: row;
|
|
41
|
+
align-items: center;
|
|
42
|
+
gap: 1.5rem;
|
|
43
|
+
width: var(--branding-w, 200px);
|
|
44
|
+
height: 100%;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.qss-header-tagline {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
gap: 0.125rem;
|
|
51
|
+
width: var(--tagline-w, 150px);
|
|
52
|
+
height: 100%;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.qss-header-ribbon {
|
|
56
|
+
flex: 1 1 0%;
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: row;
|
|
59
|
+
align-items: center;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
gap: 2rem;
|
|
62
|
+
height: 100%;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.qss-ribbon-group {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 0.125rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.qss-ribbon-activities {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-direction: row;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: 0.25rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.qss-proficiency-filter-wrap {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
align-items: center;
|
|
83
|
+
gap: 0.125rem;
|
|
84
|
+
padding-left: 0.5rem;
|
|
85
|
+
padding-right: 0.5rem;
|
|
86
|
+
border-right: 1px solid rgba(30, 41, 59, 0.5);
|
|
87
|
+
height: 100%;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.qss-proficiency-filter-items {
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-direction: row;
|
|
93
|
+
align-items: center;
|
|
94
|
+
gap: 0.375rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
#pp-header-branding {
|
|
98
|
+
width: var(--branding-w, 200px);
|
|
99
|
+
height: 100%;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#pp-header-tagline {
|
|
103
|
+
width: var(--tagline-w, 150px);
|
|
104
|
+
height: 100%;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#pp-header-ribbon {
|
|
108
|
+
width: auto;
|
|
109
|
+
height: 100%;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Scrollbar Standard */
|
|
113
|
+
::-webkit-scrollbar { width: 7px; height: 7px; }
|
|
114
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
115
|
+
::-webkit-scrollbar-thumb {
|
|
116
|
+
background: #334155;
|
|
117
|
+
border-radius: 100px;
|
|
118
|
+
border: 1.5px solid transparent;
|
|
119
|
+
background-clip: content-box;
|
|
120
|
+
}
|
|
121
|
+
::-webkit-scrollbar-thumb:hover { background: #475569; background-clip: content-box; }
|
|
122
|
+
|
|
123
|
+
/* Icon Standardization */
|
|
124
|
+
.qss-icon-wrap {
|
|
125
|
+
display: inline-flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
justify-content: center;
|
|
128
|
+
line-height: 1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.qss-icon-raw,
|
|
132
|
+
.qss-icon-lucide {
|
|
133
|
+
width: 100%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
display: block;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
[class^="lucide-"], [class*=" lucide-"],
|
|
139
|
+
[class^="qss-icon-"], [class*=" qss-icon-"],
|
|
140
|
+
[class^="icon-"]:not(.icon-path), [class*=" icon-"]:not(.icon-path) {
|
|
141
|
+
display: inline-flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
justify-content: center;
|
|
144
|
+
font-size: 14px;
|
|
145
|
+
width: 14px;
|
|
146
|
+
height: 14px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Reactive QSS Properties */
|
|
150
|
+
.qss-mini-explorer-dropdown,
|
|
151
|
+
.qss-new-menu-dropdown,
|
|
152
|
+
.qss-link-menu-dropdown {
|
|
153
|
+
top: var(--dropdown-top, auto);
|
|
154
|
+
left: var(--dropdown-left, auto);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.qss-snippet-drawer {
|
|
158
|
+
width: var(--drawer-w, 0px);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.qss-fix-footer {
|
|
162
|
+
height: var(--footer-h, 0px);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* File Editor Structural Identities */
|
|
166
|
+
#pp-file-editor-shell {
|
|
167
|
+
contain: layout;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#pp-editor-viewport {
|
|
171
|
+
display: flex;
|
|
172
|
+
gap: 1px;
|
|
173
|
+
padding: 1px;
|
|
174
|
+
background-color: #0b0d11;
|
|
175
|
+
contain: layout;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
[id^="pp-editor-pane-"] {
|
|
179
|
+
contain: layout;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.no-scrollbar {
|
|
183
|
+
scrollbar-width: none;
|
|
184
|
+
-ms-overflow-style: none;
|
|
185
|
+
&::-webkit-scrollbar {
|
|
186
|
+
display: none;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
.qss-pointer-events-none {
|
|
192
|
+
pointer-events: none;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.qss-pointer-events-auto {
|
|
196
|
+
pointer-events: auto;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* Explicit hidden-state rule: the runtime engine is unreliable for toggling
|
|
200
|
+
display on this pre-migration element; this ID+class rule wins on
|
|
201
|
+
specificity without needing !important. */
|
|
202
|
+
#pp-preview-popup.qss {
|
|
203
|
+
display: flex;
|
|
204
|
+
flex-direction: column;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#pp-preview-popup.qss.hidden {
|
|
208
|
+
display: none;
|
|
209
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample QSS File
|
|
3
|
+
* Verifies the local transpiler loop.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#qss-test-object {
|
|
7
|
+
x: center;
|
|
8
|
+
y: 100;
|
|
9
|
+
w: 200;
|
|
10
|
+
h: 200;
|
|
11
|
+
bg: indigo-500;
|
|
12
|
+
depth: ui;
|
|
13
|
+
border-b: 2;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.qss-test-label {
|
|
17
|
+
x: 10;
|
|
18
|
+
y: 10;
|
|
19
|
+
text-size: 14;
|
|
20
|
+
text-color: slate-300;
|
|
21
|
+
font: bold;
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require "ipaddr"
|
|
2
|
+
|
|
3
|
+
module Parapet
|
|
4
|
+
class ApplicationController < ActionController::Base
|
|
5
|
+
before_action :guard_request
|
|
6
|
+
before_action :set_current_session
|
|
7
|
+
before_action :require_authentication
|
|
8
|
+
|
|
9
|
+
helper Turbo::FramesHelper
|
|
10
|
+
helper Turbo::StreamsHelper
|
|
11
|
+
helper_method :current_user
|
|
12
|
+
|
|
13
|
+
def index
|
|
14
|
+
render "parapet/application"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def set_current_session
|
|
20
|
+
Current.session = Session.find_by(id: cookies.encrypted[:parapet_session_id])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def require_authentication
|
|
24
|
+
redirect_to login_path unless Current.user
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def current_user
|
|
28
|
+
Current.user
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def guard_request
|
|
32
|
+
environment = Rails.env.to_s
|
|
33
|
+
return head(:not_found) unless %w[development test].include?(environment)
|
|
34
|
+
return head(:not_found) unless loopback_request?
|
|
35
|
+
head(:not_found) unless expected_subdomain?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def loopback_request?
|
|
39
|
+
IPAddr.new(request.remote_ip).loopback?
|
|
40
|
+
rescue IPAddr::InvalidAddressError, ActionDispatch::RemoteIp::IpSpoofAttackError
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Defense in depth: the engine's own mount already constrains routing to this
|
|
45
|
+
# subdomain, so any request reaching this controller through normal routing is
|
|
46
|
+
# guaranteed to already satisfy this. This check exists for the cases that bypass
|
|
47
|
+
# normal routing -- a second, unconstrained mount point added by mistake, or direct
|
|
48
|
+
# invocation outside the router -- not for DNS-rebinding defense (the mount
|
|
49
|
+
# constraint and Host authorization handle that).
|
|
50
|
+
def expected_subdomain?
|
|
51
|
+
request.subdomain == Parapet.mount_subdomain
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Parapet
|
|
2
|
+
class BaseController < ApplicationController
|
|
3
|
+
include ApplicationHelper
|
|
4
|
+
helper ApplicationHelper
|
|
5
|
+
|
|
6
|
+
before_action :set_suite_context
|
|
7
|
+
|
|
8
|
+
protected
|
|
9
|
+
|
|
10
|
+
def set_suite_context
|
|
11
|
+
@explorer_type = 'project'
|
|
12
|
+
@root_path = Parapet::Engine.root.to_s
|
|
13
|
+
@scanner = Parapet::DirectoryScanner.new(@root_path)
|
|
14
|
+
physical_tree = @scanner.scan
|
|
15
|
+
@tree_data = Parapet::ExplorerManager.virtualize(physical_tree, @explorer_type)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module Parapet
|
|
2
|
+
module CssSuite
|
|
3
|
+
class CompilerController < ApplicationController
|
|
4
|
+
def grammar
|
|
5
|
+
registry_path = Parapet::Engine.root.join("app/assets/config/parapet/grammar-registry.json")
|
|
6
|
+
if File.exist?(registry_path)
|
|
7
|
+
render json: JSON.parse(File.read(registry_path))
|
|
8
|
+
else
|
|
9
|
+
render json: { error: "Grammar registry not found" }, status: :not_found
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Bypasses Propshaft/Sprockets to serve the absolute latest generated core
|
|
14
|
+
def live
|
|
15
|
+
scss_path = File.join(QSS.stylesheets_path, "qss", "qss_core.scss")
|
|
16
|
+
|
|
17
|
+
if File.exist?(scss_path)
|
|
18
|
+
begin
|
|
19
|
+
result = Sass.compile_string(
|
|
20
|
+
"@import \"parapet/qss_variables\";\n@import \"qss/qss_core\";\n", # Parapet's settings, then core (as in qss_application.scss)
|
|
21
|
+
load_paths: [ Parapet::Engine.root.join("app/assets/stylesheets").to_s, QSS.stylesheets_path ],
|
|
22
|
+
syntax: :scss,
|
|
23
|
+
style: :expanded
|
|
24
|
+
)
|
|
25
|
+
render plain: result.css, content_type: 'text/css'
|
|
26
|
+
rescue => e
|
|
27
|
+
logger.error "SCSS Compilation Error: #{e.message}\n#{e.backtrace.join("\n")}"
|
|
28
|
+
render plain: "/* SCSS Compilation Error: #{e.message} */", content_type: 'text/css', status: :internal_server_error
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
render plain: "/* qss_core.scss not found at #{scss_path} */", content_type: 'text/css', status: :not_found
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def compile
|
|
36
|
+
scss_content = params[:scss]
|
|
37
|
+
|
|
38
|
+
if scss_content.blank?
|
|
39
|
+
render json: { css: "", error: nil }
|
|
40
|
+
return
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
# Compile using sass-embedded
|
|
45
|
+
# We include the engine's stylesheet path for @imports
|
|
46
|
+
load_paths = [ Parapet::Engine.root.join("app/assets/stylesheets").to_s ]
|
|
47
|
+
|
|
48
|
+
result = Sass.compile_string(
|
|
49
|
+
scss_content,
|
|
50
|
+
load_paths: load_paths,
|
|
51
|
+
syntax: :scss,
|
|
52
|
+
style: :expanded
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
render json: { css: result.css, error: nil }
|
|
56
|
+
rescue Sass::CompileError => e
|
|
57
|
+
render json: {
|
|
58
|
+
css: nil,
|
|
59
|
+
error: e.message,
|
|
60
|
+
line: e.span&.start&.line,
|
|
61
|
+
column: e.span&.start&.column
|
|
62
|
+
}, status: :unprocessable_entity
|
|
63
|
+
rescue => e
|
|
64
|
+
render json: { css: nil, error: "System Error: #{e.message}" }, status: :internal_server_error
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def flush
|
|
69
|
+
path = params[:path]
|
|
70
|
+
content = params[:content]
|
|
71
|
+
|
|
72
|
+
if path.blank? || content.nil?
|
|
73
|
+
render json: { error: "Path and content are required" }, status: :bad_request
|
|
74
|
+
return
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
full_path = File.expand_path(Rails.root.join(path).to_s)
|
|
78
|
+
root_path = File.expand_path(Rails.root.to_s)
|
|
79
|
+
root_prefix = root_path.end_with?(File::SEPARATOR) ? root_path : "#{root_path}#{File::SEPARATOR}"
|
|
80
|
+
|
|
81
|
+
unless full_path == root_path || full_path.start_with?(root_prefix)
|
|
82
|
+
render json: { error: "Access Denied" }, status: :forbidden
|
|
83
|
+
return
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
begin
|
|
87
|
+
File.write(full_path, content)
|
|
88
|
+
render json: { success: true, path: path }
|
|
89
|
+
rescue => e
|
|
90
|
+
render json: { error: "Failed to write file: #{e.message}" }, status: :internal_server_error
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Parapet
|
|
2
|
+
module CssSuite
|
|
3
|
+
class PreviewController < ApplicationController
|
|
4
|
+
layout false
|
|
5
|
+
|
|
6
|
+
def show
|
|
7
|
+
path = params[:path].to_s
|
|
8
|
+
Rails.logger.info "Styles Workbench: Preview Request for #{path}"
|
|
9
|
+
|
|
10
|
+
if path.blank? || !path.end_with?('.erb')
|
|
11
|
+
Rails.logger.warn "Styles Workbench: Invalid preview path: #{path}"
|
|
12
|
+
render plain: "Select an ERB view file to preview.", status: :bad_request
|
|
13
|
+
return
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Security & Path Resolution
|
|
17
|
+
root_path = File.expand_path(Parapet::Engine.root.to_s)
|
|
18
|
+
full_path = File.expand_path(File.join(root_path, path.sub(/^\//, '')))
|
|
19
|
+
|
|
20
|
+
unless full_path.start_with?(root_path) && File.exist?(full_path)
|
|
21
|
+
render plain: "File not found or access denied.", status: :not_found
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
# We attempt to render the file as a partial.
|
|
27
|
+
prepend_view_path Parapet::Engine.root.join("app/views")
|
|
28
|
+
|
|
29
|
+
# app/views/parapet/shared/_header.html.erb -> parapet/shared/header
|
|
30
|
+
clean_path = path.sub(%r{^.*app/views/}, '').sub(/\.html\.erb$/, '')
|
|
31
|
+
|
|
32
|
+
# Remove leading underscore from the final segment (the filename)
|
|
33
|
+
parts = clean_path.split('/')
|
|
34
|
+
parts[-1] = parts[-1].sub(/^_/, '')
|
|
35
|
+
partial_path = parts.join('/')
|
|
36
|
+
|
|
37
|
+
render partial: partial_path
|
|
38
|
+
rescue => e
|
|
39
|
+
render html: "<div class='qss-p[20] qss-bg-red-500/10 qss-border qss-border-red-500/20 qss-text-red-400 qss-text-size[11]'>
|
|
40
|
+
<strong>Preview Error:</strong><br/>#{e.message}
|
|
41
|
+
</div>".html_safe
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Parapet
|
|
2
|
+
class DraftsController < ApplicationController
|
|
3
|
+
def show
|
|
4
|
+
draft = DraftRecoveryStore.find(user: current_user, path: file_path)
|
|
5
|
+
return head :no_content unless draft
|
|
6
|
+
|
|
7
|
+
render json: { content: draft.content }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def update
|
|
11
|
+
DraftRecoveryStore.save!(
|
|
12
|
+
user: current_user,
|
|
13
|
+
path: file_path,
|
|
14
|
+
content: params[:content].to_s
|
|
15
|
+
)
|
|
16
|
+
head :no_content
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def destroy
|
|
20
|
+
DraftRecoveryStore.clear!(user: current_user, path: file_path)
|
|
21
|
+
head :no_content
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def file_path
|
|
27
|
+
params[:path].to_s.sub(/^\//, "")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Parapet
|
|
2
|
+
class ExplorersController < ApplicationController
|
|
3
|
+
include ApplicationHelper
|
|
4
|
+
|
|
5
|
+
def show
|
|
6
|
+
@explorer_type = params[:type] || 'project'
|
|
7
|
+
@perspective = params[:perspective] || 'project'
|
|
8
|
+
|
|
9
|
+
# Always scan from the engine root to allow cross-directory virtualization (like Registry)
|
|
10
|
+
@root_path = Parapet::Engine.root.to_s
|
|
11
|
+
|
|
12
|
+
# Initialize scanner and generate tree
|
|
13
|
+
@scanner = Parapet::DirectoryScanner.new(@root_path)
|
|
14
|
+
physical_tree = @scanner.scan
|
|
15
|
+
|
|
16
|
+
# Transform the physical tree into virtual perspectives
|
|
17
|
+
@tree_data = Parapet::ExplorerManager.virtualize(physical_tree, @explorer_type, perspective: @perspective)
|
|
18
|
+
|
|
19
|
+
# Determine which partial to render
|
|
20
|
+
mapped_type = case @explorer_type
|
|
21
|
+
when 'styles' then 'css'
|
|
22
|
+
when 'ideas' then 'intentions'
|
|
23
|
+
else @explorer_type
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
explorer_partial = "parapet/shared/explorers/#{mapped_type}"
|
|
27
|
+
unless lookup_context.exists?(explorer_partial, [], true)
|
|
28
|
+
explorer_partial = "parapet/shared/explorers/base"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
respond_to do |format|
|
|
32
|
+
format.turbo_stream do
|
|
33
|
+
if turbo_frame_request?
|
|
34
|
+
render partial: explorer_partial, locals: { type: @explorer_type, tree_data: @tree_data }
|
|
35
|
+
else
|
|
36
|
+
render turbo_stream: [
|
|
37
|
+
turbo_stream.replace("qss-perspective-filters", partial: "parapet/activities/perspective_filters", locals: { explorer_type: @explorer_type }),
|
|
38
|
+
turbo_stream.replace("qss-explorer-content", partial: explorer_partial, locals: { type: @explorer_type, tree_data: @tree_data }),
|
|
39
|
+
turbo_stream.replace("qss-progress-area", partial: "parapet/activities/progress_area", locals: { summary: Parapet::ExplorerManager.summary(@explorer_type), root_path: @root_path })
|
|
40
|
+
]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
format.html do
|
|
44
|
+
if turbo_frame_request?
|
|
45
|
+
render partial: explorer_partial, locals: { type: @explorer_type, tree_data: @tree_data }
|
|
46
|
+
else
|
|
47
|
+
render partial: "parapet/activities/explorer_tree", locals: { tree_data: @tree_data }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|