stomp_base 0.2.0 → 0.2.2
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/CHANGELOG.md +40 -8
- data/README.md +48 -0
- data/app/components/stomp_base/console/console_examples_component.html.erb +1 -1
- data/app/components/stomp_base/console/terminal_component.html.erb +317 -0
- data/app/components/stomp_base/console/terminal_component.rb +24 -0
- data/app/components/stomp_base/pages/console_component.html.erb +4 -8
- data/app/controllers/stomp_base/application_controller.rb +4 -0
- data/app/controllers/stomp_base/console_controller.rb +94 -15
- data/app/controllers/stomp_base/settings_controller.rb +13 -3
- data/config/locales/en.yml +13 -1
- data/config/locales/ja.yml +12 -1
- data/config/routes.rb +2 -0
- data/lib/stomp_base/engine.rb +106 -7
- data/lib/stomp_base/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b134d98cdd58b0e0f96d5045fdc83e9bc07379cd95e2bae7a7ee462d5ec9cc4
|
4
|
+
data.tar.gz: 3b1f9f0e9aada4b215c1c2d9277af0478a447ab309492004d76ab43a91171761
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49c1f34fc9b74d9c79e59e95a4acc47c518086f883f75586f04058338f8b27190a5de807569c09f4e1be37a2e765dc84bcf00a13324bfd466798c9e77a66f0c0
|
7
|
+
data.tar.gz: 7bd934b72a8ddaf2d29b65f71792d6a72883c9cb53272483b1f39b2c70205d41d65dab12b972328b87e5eda39ff22ccb607cddeb62918b2b93e25890742176eb
|
data/CHANGELOG.md
CHANGED
@@ -7,17 +7,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.2.2] - 2025-07-27
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- **Terminal-Style Console Interface**: Complete redesign of the browser console
|
14
|
+
- Real terminal-like experience with command history and session persistence
|
15
|
+
- Session state management to maintain console state across page reloads
|
16
|
+
- Responsive design optimized for both desktop and mobile devices
|
17
|
+
- Comprehensive Japanese and English translations
|
18
|
+
- **Enhanced Documentation**: Comprehensive documentation for API-only Rails support and authentication features
|
19
|
+
|
20
|
+
### Improved
|
21
|
+
- **Console Functionality**: Enhanced console session management and user experience
|
22
|
+
- **Test Coverage**: Added comprehensive tests for terminal console interface
|
23
|
+
- **Responsive Design**: Improved mobile and tablet compatibility for console interface
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
- **Timezone Dependencies**: Resolved timezone dependency issues in console specifications
|
27
|
+
- **Session Persistence**: Fixed console session state persistence across browser reloads
|
28
|
+
|
29
|
+
## [0.2.1] - 2025-06-28
|
30
|
+
|
31
|
+
### Added
|
32
|
+
- **API-only Rails Support**: Automatic compatibility for API-only Rails applications
|
33
|
+
- Auto-configure necessary middleware (session, cookies, flash, method override)
|
34
|
+
- Automatic session store configuration for API-only applications
|
35
|
+
- No manual middleware configuration required in host applications
|
36
|
+
- **Japanese Documentation**: Complete Japanese translation of README.md (README.ja.md)
|
37
|
+
- **Rails Demo API**: Complete API-only Rails demonstration application
|
38
|
+
- Sample models, migrations, and authentication specifications
|
39
|
+
- Proper bin/ directory with Rails binstubs
|
40
|
+
|
10
41
|
### Changed
|
11
|
-
- **
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- Rails-based tests now use `spec/rails_demo/spec/rails_helper.rb`
|
16
|
-
- **Configuration**: Fixed duplicate `disable_authentication` method in Configuration class
|
42
|
+
- **Settings Controller**: Improved settings save functionality with proper flash message handling
|
43
|
+
- **Application Controller**: Simplified to use Rails standard flash functionality
|
44
|
+
- **Routes**: Added POST route support for settings form submission
|
45
|
+
- **Documentation**: Added cross-language links between README files
|
17
46
|
|
18
47
|
### Fixed
|
19
|
-
-
|
20
|
-
-
|
48
|
+
- **RuboCop Issues**: Fixed RuboCop execution and code style issues
|
49
|
+
- **CSS Assets**: Resolved CSS asset loading issues in API-only Rails applications
|
50
|
+
- **Error Handling**: Improved error handling and logging for middleware setup
|
21
51
|
|
22
52
|
## [0.2.0] - 2025-05-28
|
23
53
|
|
@@ -71,5 +101,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
71
101
|
- 🔧 Easy Integration: Simple gem installation and mounting process
|
72
102
|
- 🔐 Built-in Authentication: Simple authentication options (Basic Auth, API keys, Custom)
|
73
103
|
|
104
|
+
[0.2.2]: https://github.com/snowwshiro/stomp_base/releases/tag/v0.2.2
|
105
|
+
[0.2.1]: https://github.com/snowwshiro/stomp_base/releases/tag/v0.2.1
|
74
106
|
[0.2.0]: https://github.com/snowwshiro/stomp_base/releases/tag/v0.2.0
|
75
107
|
[0.1.0]: https://github.com/snowwshiro/stomp_base/releases/tag/v0.1.0
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# 🎛️ Stomp Base
|
2
2
|
|
3
|
+
[ja README](./README.ja.md)
|
4
|
+
|
3
5
|
[](https://github.com/snowwshiro/stomp_base/actions/workflows/ci.yml)
|
4
6
|
[](https://github.com/snowwshiro/stomp_base/actions/workflows/code-quality.yml)
|
5
7
|
[](https://github.com/snowwshiro/stomp_base/actions/workflows/coverage.yml)
|
@@ -59,6 +61,30 @@ end
|
|
59
61
|
2. **Install View Component** (automatically included as dependency):
|
60
62
|
The gem includes View Component as a dependency, so no additional setup is required.
|
61
63
|
|
64
|
+
### API-Only Rails Applications
|
65
|
+
|
66
|
+
StompBase automatically works with API-only Rails applications! The engine detects when the asset pipeline is not available and configures static asset serving automatically.
|
67
|
+
|
68
|
+
**No additional configuration needed** - StompBase will:
|
69
|
+
- Detect API-only mode (`config.api_only = true`)
|
70
|
+
- Automatically serve CSS assets via `ActionDispatch::Static` middleware
|
71
|
+
- Display helpful warnings if public file server is disabled
|
72
|
+
|
73
|
+
If you encounter styling issues in an API-only app, ensure public file server is enabled:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# config/application.rb or config/environments/development.rb
|
77
|
+
config.public_file_server.enabled = true
|
78
|
+
```
|
79
|
+
|
80
|
+
Alternatively, you can enable ActionView and the asset pipeline:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
# config/application.rb
|
84
|
+
require "action_view/railtie"
|
85
|
+
# Remove or comment out: config.api_only = true
|
86
|
+
```
|
87
|
+
|
62
88
|
## Usage
|
63
89
|
|
64
90
|
### Accessing the Dashboard
|
@@ -245,6 +271,9 @@ StompBase.configure do |config|
|
|
245
271
|
config.locale = :ja # Set interface language
|
246
272
|
config.available_locales = [:en, :ja] # Available language options (read-only)
|
247
273
|
|
274
|
+
# Console configuration
|
275
|
+
config.allow_console_in_production = false # Allow console functionality in production (default: false)
|
276
|
+
|
248
277
|
# Authentication options
|
249
278
|
config.enable_authentication( # Enable authentication
|
250
279
|
method: :basic_auth, # :basic_auth, :api_key, or :custom
|
@@ -270,6 +299,20 @@ StompBase.enable_authentication(method: :basic_auth, username: 'admin', password
|
|
270
299
|
StompBase.disable_authentication
|
271
300
|
```
|
272
301
|
|
302
|
+
### Console Configuration
|
303
|
+
|
304
|
+
For security reasons, the Rails console functionality is disabled in production environments by default. You can enable it if needed:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
# config/initializers/stomp_base.rb
|
308
|
+
StompBase.configure do |config|
|
309
|
+
# Enable console functionality in production (disabled by default for security)
|
310
|
+
config.allow_console_in_production = true
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
314
|
+
**⚠️ Security Warning**: Enabling console functionality in production environments poses significant security risks. Only enable this feature if you fully understand the implications and have proper security measures in place.
|
315
|
+
|
273
316
|
### Direct Configuration
|
274
317
|
|
275
318
|
```ruby
|
@@ -435,6 +478,8 @@ StompBase.configure do |config|
|
|
435
478
|
method: :api_key,
|
436
479
|
keys: [ENV['STOMP_BASE_API_KEY']]
|
437
480
|
)
|
481
|
+
# Console disabled in production by default for security
|
482
|
+
# config.allow_console_in_production = true # Uncomment only if absolutely necessary
|
438
483
|
elsif Rails.env.development?
|
439
484
|
# Simple authentication for development
|
440
485
|
config.enable_authentication(
|
@@ -442,6 +487,7 @@ StompBase.configure do |config|
|
|
442
487
|
username: 'dev',
|
443
488
|
password: 'dev'
|
444
489
|
)
|
490
|
+
# Console enabled in development by default
|
445
491
|
else
|
446
492
|
# Disable authentication for test environment
|
447
493
|
config.disable_authentication
|
@@ -455,6 +501,8 @@ end
|
|
455
501
|
- Use HTTPS (especially when using Basic Authentication)
|
456
502
|
- Update API keys regularly
|
457
503
|
- Be careful not to output authentication information to log files
|
504
|
+
- **Console functionality should remain disabled in production environments** unless absolutely necessary for debugging
|
505
|
+
- If console access is required in production, ensure strong authentication is enabled and access is properly logged
|
458
506
|
|
459
507
|
## Implementation Summary
|
460
508
|
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 0.5rem;">
|
10
10
|
<% console_examples.each do |example| %>
|
11
11
|
<button
|
12
|
-
onclick="
|
12
|
+
onclick="insertTerminalCommand('<%= example[:command] %>')"
|
13
13
|
class="stomp-base-btn"
|
14
14
|
style="text-align: left; padding: 0.75rem; background-color: #f8fafc; color: #374151; border: 1px solid #e2e8f0; border-radius: 0.375rem; font-family: 'Courier New', monospace; font-size: 0.8125rem; transition: all 0.2s ease;"
|
15
15
|
onmouseover="this.style.backgroundColor='#f1f5f9'; this.style.borderColor='#cbd5e1';"
|
@@ -0,0 +1,317 @@
|
|
1
|
+
<!-- Terminal-style Console Interface -->
|
2
|
+
<div class="stomp-base-card" style="margin-bottom: 0.75rem; background-color: #1e1e1e; border: 1px solid #333; border-radius: 0.5rem; overflow: hidden;">
|
3
|
+
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; padding: 0.75rem 1rem; background-color: #2d2d2d; border-bottom: 1px solid #333;">
|
4
|
+
<div style="display: flex; align-items: center; min-width: 0;">
|
5
|
+
<svg style="width: 1.25rem; height: 1.25rem; margin-right: 0.5rem; color: #10b981; flex-shrink: 0;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
6
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 002 2z"></path>
|
7
|
+
</svg>
|
8
|
+
<span style="color: #e5e7eb; font-weight: 600; font-size: 0.875rem; white-space: nowrap;">Rails Console</span>
|
9
|
+
</div>
|
10
|
+
<div style="display: flex; gap: 0.5rem; flex-shrink: 0;">
|
11
|
+
<button onclick="clearTerminal()" class="stomp-base-btn" style="padding: 0.375rem 0.75rem; font-size: 0.75rem; background-color: #374151; color: #e5e7eb; border: 1px solid #4b5563; border-radius: 0.375rem; white-space: nowrap;">
|
12
|
+
<%= t('stomp_base.console.clear') %>
|
13
|
+
</button>
|
14
|
+
<button onclick="restartSession()" class="stomp-base-btn" style="padding: 0.375rem 0.75rem; font-size: 0.75rem; background-color: #dc2626; color: #fff; border: 1px solid #dc2626; border-radius: 0.375rem; white-space: nowrap;">
|
15
|
+
Restart
|
16
|
+
</button>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<!-- Terminal Display Area -->
|
21
|
+
<div
|
22
|
+
id="terminal-display"
|
23
|
+
style="height: 400px; max-height: 60vh; overflow-y: auto; padding: 1rem; background-color: #1e1e1e; font-family: 'Courier New', 'Monaco', 'Consolas', monospace; font-size: 0.875rem; line-height: 1.4; color: #e5e7eb;"
|
24
|
+
>
|
25
|
+
<div id="terminal-output">
|
26
|
+
<div style="color: #10b981; margin-bottom: 0.5rem;"><%= welcome_message %></div>
|
27
|
+
</div>
|
28
|
+
<div id="terminal-input-line" style="display: flex; align-items: flex-start; gap: 0.25rem;">
|
29
|
+
<span id="terminal-prompt" style="color: #10b981; flex-shrink: 0; user-select: none; font-size: 0.875rem; line-height: 1.4;"><%= initial_prompt %></span>
|
30
|
+
<div style="flex: 1; min-width: 0; position: relative;">
|
31
|
+
<textarea
|
32
|
+
id="terminal-input"
|
33
|
+
style="width: 100%; min-height: 1.4em; background: transparent; border: none; outline: none; color: #e5e7eb; font-family: inherit; font-size: inherit; line-height: inherit; resize: none; padding: 0; margin: 0; overflow: hidden; word-wrap: break-word;"
|
34
|
+
placeholder="<%= t('stomp_base.console.placeholder') %>"
|
35
|
+
rows="1"
|
36
|
+
onkeydown="handleTerminalKeydown(event)"
|
37
|
+
oninput="adjustTerminalInputHeight()"
|
38
|
+
></textarea>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
</div>
|
42
|
+
|
43
|
+
<!-- Hidden session ID for JavaScript -->
|
44
|
+
<input type="hidden" id="terminal-session-id" value="<%= session_id %>">
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<style>
|
48
|
+
@media (max-width: 640px) {
|
49
|
+
#terminal-display {
|
50
|
+
height: 300px !important;
|
51
|
+
max-height: 50vh !important;
|
52
|
+
padding: 0.75rem !important;
|
53
|
+
font-size: 0.8125rem !important;
|
54
|
+
}
|
55
|
+
|
56
|
+
#terminal-input {
|
57
|
+
font-size: 0.8125rem !important;
|
58
|
+
}
|
59
|
+
|
60
|
+
#terminal-prompt {
|
61
|
+
font-size: 0.8125rem !important;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
@media (max-width: 480px) {
|
66
|
+
#terminal-display {
|
67
|
+
height: 250px !important;
|
68
|
+
max-height: 40vh !important;
|
69
|
+
padding: 0.5rem !important;
|
70
|
+
font-size: 0.75rem !important;
|
71
|
+
}
|
72
|
+
|
73
|
+
#terminal-input {
|
74
|
+
font-size: 0.75rem !important;
|
75
|
+
}
|
76
|
+
|
77
|
+
#terminal-prompt {
|
78
|
+
font-size: 0.75rem !important;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
</style>
|
82
|
+
|
83
|
+
<script>
|
84
|
+
// Terminal functionality
|
85
|
+
let terminalHistory = [];
|
86
|
+
let terminalHistoryIndex = -1;
|
87
|
+
let terminalCommandCounter = 1;
|
88
|
+
let terminalSessionId = document.getElementById('terminal-session-id').value;
|
89
|
+
|
90
|
+
function handleTerminalKeydown(event) {
|
91
|
+
const input = event.target;
|
92
|
+
|
93
|
+
// Execute on Enter (without Shift)
|
94
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
95
|
+
event.preventDefault();
|
96
|
+
executeTerminalCommand();
|
97
|
+
return;
|
98
|
+
}
|
99
|
+
|
100
|
+
// Allow Shift+Enter for multi-line input
|
101
|
+
if (event.key === 'Enter' && event.shiftKey) {
|
102
|
+
// Let the default behavior handle the new line
|
103
|
+
setTimeout(() => adjustTerminalInputHeight(), 0);
|
104
|
+
return;
|
105
|
+
}
|
106
|
+
|
107
|
+
// History navigation with Up/Down arrows
|
108
|
+
if (event.key === 'ArrowUp' && terminalHistory.length > 0) {
|
109
|
+
event.preventDefault();
|
110
|
+
terminalHistoryIndex = Math.min(terminalHistoryIndex + 1, terminalHistory.length - 1);
|
111
|
+
input.value = terminalHistory[terminalHistoryIndex];
|
112
|
+
adjustTerminalInputHeight();
|
113
|
+
} else if (event.key === 'ArrowDown') {
|
114
|
+
event.preventDefault();
|
115
|
+
if (terminalHistoryIndex > 0) {
|
116
|
+
terminalHistoryIndex--;
|
117
|
+
input.value = terminalHistory[terminalHistoryIndex];
|
118
|
+
} else {
|
119
|
+
terminalHistoryIndex = -1;
|
120
|
+
input.value = '';
|
121
|
+
}
|
122
|
+
adjustTerminalInputHeight();
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
function adjustTerminalInputHeight() {
|
127
|
+
const input = document.getElementById('terminal-input');
|
128
|
+
input.style.height = 'auto';
|
129
|
+
input.style.height = input.scrollHeight + 'px';
|
130
|
+
}
|
131
|
+
|
132
|
+
function showSessionPersistenceNotice() {
|
133
|
+
const notice = document.createElement('div');
|
134
|
+
notice.style.cssText = `
|
135
|
+
position: fixed;
|
136
|
+
top: 20px;
|
137
|
+
right: 20px;
|
138
|
+
background: #10b981;
|
139
|
+
color: white;
|
140
|
+
padding: 12px 16px;
|
141
|
+
border-radius: 6px;
|
142
|
+
font-size: 14px;
|
143
|
+
z-index: 1000;
|
144
|
+
opacity: 0;
|
145
|
+
transform: translateX(100%);
|
146
|
+
transition: all 0.3s ease;
|
147
|
+
`;
|
148
|
+
notice.textContent = '<%= t('stomp_base.console.variable_persistence') %>';
|
149
|
+
|
150
|
+
document.body.appendChild(notice);
|
151
|
+
|
152
|
+
setTimeout(() => {
|
153
|
+
notice.style.opacity = '1';
|
154
|
+
notice.style.transform = 'translateX(0)';
|
155
|
+
}, 100);
|
156
|
+
|
157
|
+
setTimeout(() => {
|
158
|
+
notice.style.opacity = '0';
|
159
|
+
notice.style.transform = 'translateX(100%)';
|
160
|
+
setTimeout(() => notice.remove(), 300);
|
161
|
+
}, 3000);
|
162
|
+
}
|
163
|
+
|
164
|
+
// Show session persistence notice on first command
|
165
|
+
let firstCommandExecuted = false;
|
166
|
+
function executeTerminalCommand() {
|
167
|
+
const input = document.getElementById('terminal-input');
|
168
|
+
const command = input.value.trim();
|
169
|
+
|
170
|
+
if (!command) return;
|
171
|
+
|
172
|
+
// Show persistence notice on first command
|
173
|
+
if (!firstCommandExecuted) {
|
174
|
+
showSessionPersistenceNotice();
|
175
|
+
firstCommandExecuted = true;
|
176
|
+
}
|
177
|
+
|
178
|
+
// Add to history
|
179
|
+
terminalHistory.unshift(command);
|
180
|
+
if (terminalHistory.length > 50) {
|
181
|
+
terminalHistory = terminalHistory.slice(0, 50);
|
182
|
+
}
|
183
|
+
terminalHistoryIndex = -1;
|
184
|
+
|
185
|
+
// Display command in terminal
|
186
|
+
displayTerminalCommand(command);
|
187
|
+
|
188
|
+
// Clear input and reset height
|
189
|
+
input.value = '';
|
190
|
+
input.style.height = 'auto';
|
191
|
+
|
192
|
+
// Execute command via AJAX
|
193
|
+
fetch('<%= StompBase::Engine.routes.url_helpers.console_execute_path %>', {
|
194
|
+
method: 'POST',
|
195
|
+
headers: {
|
196
|
+
'Content-Type': 'application/json',
|
197
|
+
'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
|
198
|
+
},
|
199
|
+
body: JSON.stringify({
|
200
|
+
command: command,
|
201
|
+
session_id: terminalSessionId,
|
202
|
+
command_counter: terminalCommandCounter
|
203
|
+
})
|
204
|
+
})
|
205
|
+
.then(response => response.json())
|
206
|
+
.then(data => {
|
207
|
+
if (data.success) {
|
208
|
+
displayTerminalOutput(data.result, data.command_counter);
|
209
|
+
} else {
|
210
|
+
displayTerminalError(data.error, data.command_counter);
|
211
|
+
}
|
212
|
+
terminalCommandCounter = data.command_counter ? data.command_counter + 1 : terminalCommandCounter + 1;
|
213
|
+
updateTerminalPrompt();
|
214
|
+
})
|
215
|
+
.catch(error => {
|
216
|
+
displayTerminalError(`Network error: ${error.message}`, terminalCommandCounter);
|
217
|
+
terminalCommandCounter++;
|
218
|
+
updateTerminalPrompt();
|
219
|
+
});
|
220
|
+
}
|
221
|
+
|
222
|
+
function displayTerminalCommand(command) {
|
223
|
+
const output = document.getElementById('terminal-output');
|
224
|
+
const commandDiv = document.createElement('div');
|
225
|
+
commandDiv.innerHTML = `<span style="color: #10b981;">${getCurrentPrompt()}</span>${escapeHtml(command)}`;
|
226
|
+
output.appendChild(commandDiv);
|
227
|
+
scrollTerminalToBottom();
|
228
|
+
}
|
229
|
+
|
230
|
+
function displayTerminalOutput(result, commandCounter) {
|
231
|
+
const output = document.getElementById('terminal-output');
|
232
|
+
const resultDiv = document.createElement('div');
|
233
|
+
resultDiv.style.color = '#e5e7eb';
|
234
|
+
resultDiv.style.marginBottom = '0.5rem';
|
235
|
+
resultDiv.style.whiteSpace = 'pre-wrap';
|
236
|
+
resultDiv.textContent = result;
|
237
|
+
output.appendChild(resultDiv);
|
238
|
+
scrollTerminalToBottom();
|
239
|
+
}
|
240
|
+
|
241
|
+
function displayTerminalError(error, commandCounter) {
|
242
|
+
const output = document.getElementById('terminal-output');
|
243
|
+
const errorDiv = document.createElement('div');
|
244
|
+
errorDiv.style.color = '#ef4444';
|
245
|
+
errorDiv.style.marginBottom = '0.5rem';
|
246
|
+
errorDiv.style.whiteSpace = 'pre-wrap';
|
247
|
+
errorDiv.textContent = error;
|
248
|
+
output.appendChild(errorDiv);
|
249
|
+
scrollTerminalToBottom();
|
250
|
+
}
|
251
|
+
|
252
|
+
function getCurrentPrompt() {
|
253
|
+
return `irb(main):${String(terminalCommandCounter).padStart(3, '0')}:0> `;
|
254
|
+
}
|
255
|
+
|
256
|
+
function updateTerminalPrompt() {
|
257
|
+
const prompt = document.getElementById('terminal-prompt');
|
258
|
+
prompt.textContent = getCurrentPrompt();
|
259
|
+
}
|
260
|
+
|
261
|
+
function scrollTerminalToBottom() {
|
262
|
+
const display = document.getElementById('terminal-display');
|
263
|
+
display.scrollTop = display.scrollHeight;
|
264
|
+
}
|
265
|
+
|
266
|
+
function clearTerminal() {
|
267
|
+
const output = document.getElementById('terminal-output');
|
268
|
+
output.innerHTML = `<div style="color: #10b981; margin-bottom: 0.5rem;"><%= welcome_message %></div>`;
|
269
|
+
terminalCommandCounter = 1;
|
270
|
+
updateTerminalPrompt();
|
271
|
+
document.getElementById('terminal-input').focus();
|
272
|
+
}
|
273
|
+
|
274
|
+
function restartSession() {
|
275
|
+
if (confirm('Are you sure you want to restart the console session? All variables will be lost.')) {
|
276
|
+
terminalSessionId = generateSessionId();
|
277
|
+
document.getElementById('terminal-session-id').value = terminalSessionId;
|
278
|
+
clearTerminal();
|
279
|
+
|
280
|
+
// Notify server to clear session
|
281
|
+
fetch('<%= StompBase::Engine.routes.url_helpers.console_execute_path %>', {
|
282
|
+
method: 'POST',
|
283
|
+
headers: {
|
284
|
+
'Content-Type': 'application/json',
|
285
|
+
'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
|
286
|
+
},
|
287
|
+
body: JSON.stringify({
|
288
|
+
command: '__restart_session__',
|
289
|
+
session_id: terminalSessionId
|
290
|
+
})
|
291
|
+
});
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
function generateSessionId() {
|
296
|
+
return Math.random().toString(36).substr(2, 9);
|
297
|
+
}
|
298
|
+
|
299
|
+
function escapeHtml(text) {
|
300
|
+
const div = document.createElement('div');
|
301
|
+
div.textContent = text;
|
302
|
+
return div.innerHTML;
|
303
|
+
}
|
304
|
+
|
305
|
+
function insertTerminalCommand(command) {
|
306
|
+
const input = document.getElementById('terminal-input');
|
307
|
+
input.value = command;
|
308
|
+
input.focus();
|
309
|
+
adjustTerminalInputHeight();
|
310
|
+
}
|
311
|
+
|
312
|
+
// Focus input on page load
|
313
|
+
document.addEventListener('DOMContentLoaded', function() {
|
314
|
+
document.getElementById('terminal-input').focus();
|
315
|
+
updateTerminalPrompt();
|
316
|
+
});
|
317
|
+
</script>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StompBase
|
4
|
+
module Console
|
5
|
+
class TerminalComponent < StompBase::BaseComponent
|
6
|
+
def initialize(session_id: nil)
|
7
|
+
super()
|
8
|
+
@session_id = session_id || SecureRandom.hex(8)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :session_id
|
14
|
+
|
15
|
+
def initial_prompt
|
16
|
+
"irb(main):001:0> "
|
17
|
+
end
|
18
|
+
|
19
|
+
def welcome_message
|
20
|
+
"#{t("stomp_base.console.terminal_welcome")}\n#{t("stomp_base.console.terminal_help")}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -3,21 +3,17 @@
|
|
3
3
|
display_options: {
|
4
4
|
gradient_colors: { from: '#1f2937', to: '#374151' },
|
5
5
|
status_message: t('stomp_base.console.welcome_message'),
|
6
|
-
custom_button: '<button onclick="
|
6
|
+
custom_button: '<button onclick="restartSession()" class="stomp-base-btn" style="display: inline-flex; align-items: center; padding: 0.375rem 0.625rem; font-size: 0.8125rem; background-color: rgba(220,38,38,0.8); color: white; border: 1px solid rgba(220,38,38,0.3); backdrop-filter: blur(10px);">
|
7
7
|
<svg style="width: 0.75rem; height: 0.75rem; margin-right: 0.375rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
8
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="
|
8
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
9
9
|
</svg>
|
10
|
-
|
10
|
+
Restart Session
|
11
11
|
</button>'.html_safe
|
12
12
|
}
|
13
13
|
) %>
|
14
14
|
|
15
15
|
<%= render StompBase::Console::SecurityWarningComponent.new %>
|
16
16
|
|
17
|
-
<%= render StompBase::Console::
|
17
|
+
<%= render StompBase::Console::TerminalComponent.new %>
|
18
18
|
|
19
19
|
<%= render StompBase::Console::ConsoleExamplesComponent.new %>
|
20
|
-
|
21
|
-
<%= render StompBase::Console::ConsoleJavascriptComponent.new %>
|
22
|
-
|
23
|
-
<%= render StompBase::Console::ConsoleCssComponent.new %>
|
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
module StompBase
|
4
4
|
class ApplicationController < ActionController::Base
|
5
|
+
# Include necessary modules for API-only compatibility
|
6
|
+
include ActionController::Cookies
|
7
|
+
include ActionController::Flash unless included_modules.include?(ActionController::Flash)
|
8
|
+
|
5
9
|
include StompBase::I18nHelper
|
6
10
|
include StompBase::Authentication
|
7
11
|
|
@@ -43,40 +43,50 @@ module StompBase
|
|
43
43
|
|
44
44
|
def execute
|
45
45
|
command = params[:command]&.strip
|
46
|
+
session_id = params[:session_id]
|
47
|
+
command_counter = params[:command_counter]&.to_i || 1
|
48
|
+
|
46
49
|
return render_error(I18n.t("stomp_base.console.error")) if command.blank?
|
47
50
|
|
48
|
-
|
51
|
+
# Handle session restart
|
52
|
+
if command == "__restart_session__"
|
53
|
+
clear_session_binding(session_id)
|
54
|
+
return render json: { success: true, result: "Session restarted", command_counter: 1 }
|
55
|
+
end
|
56
|
+
|
57
|
+
process_console_command(command, session_id, command_counter)
|
49
58
|
rescue StandardError => e
|
50
|
-
handle_execution_error(e)
|
59
|
+
handle_execution_error(e, command_counter)
|
51
60
|
end
|
52
61
|
|
53
|
-
def process_console_command(command)
|
62
|
+
def process_console_command(command, session_id, command_counter)
|
54
63
|
Rails.logger.info "StompBase Console Command: #{command}"
|
55
64
|
return render_dangerous_command_error if dangerous_command?(command)
|
56
65
|
|
57
|
-
result = execute_in_rails_console(command)
|
58
|
-
render_success(result)
|
66
|
+
result = execute_in_rails_console(command, session_id)
|
67
|
+
render_success(result, command_counter)
|
59
68
|
end
|
60
69
|
|
61
|
-
def handle_execution_error(error)
|
70
|
+
def handle_execution_error(error, command_counter = 1)
|
62
71
|
Rails.logger.error "StompBase Console Error: #{error.message}"
|
63
|
-
render_error(error.message)
|
72
|
+
render_error(error.message, command_counter)
|
64
73
|
end
|
65
74
|
|
66
75
|
private
|
67
76
|
|
68
|
-
def render_error(message)
|
69
|
-
render json: { success: false, error: message, result: nil }
|
77
|
+
def render_error(message, command_counter = 1)
|
78
|
+
render json: { success: false, error: message, result: nil, command_counter: command_counter }
|
70
79
|
end
|
71
80
|
|
72
|
-
def render_success(result)
|
73
|
-
render json: { success: true, result: result.to_s, error: false }
|
81
|
+
def render_success(result, command_counter = 1)
|
82
|
+
render json: { success: true, result: result.to_s, error: false, command_counter: command_counter }
|
74
83
|
end
|
75
84
|
|
76
85
|
def render_dangerous_command_error
|
77
86
|
render json: {
|
78
87
|
success: false,
|
79
|
-
error: "Dangerous command detected. Execution denied."
|
88
|
+
error: "Dangerous command detected. Execution denied.",
|
89
|
+
command_counter: 1
|
80
90
|
}
|
81
91
|
end
|
82
92
|
|
@@ -90,10 +100,10 @@ module StompBase
|
|
90
100
|
DANGEROUS_PATTERNS.any? { |pattern| command.match?(pattern) }
|
91
101
|
end
|
92
102
|
|
93
|
-
def execute_in_rails_console(command)
|
103
|
+
def execute_in_rails_console(command, session_id)
|
94
104
|
# Evaluate command in secure execution environment
|
95
|
-
#
|
96
|
-
binding_context =
|
105
|
+
# Maintain session state for each session_id
|
106
|
+
binding_context = get_or_create_session_binding(session_id)
|
97
107
|
|
98
108
|
# Set timeout (10 seconds)
|
99
109
|
result = Timeout.timeout(10) do
|
@@ -104,6 +114,47 @@ module StompBase
|
|
104
114
|
format_result(result)
|
105
115
|
end
|
106
116
|
|
117
|
+
# Class-level session storage to persist across requests
|
118
|
+
@@session_bindings = {}
|
119
|
+
@@session_mutex = Mutex.new
|
120
|
+
@@session_timestamps = {}
|
121
|
+
|
122
|
+
def get_or_create_session_binding(session_id)
|
123
|
+
@@session_mutex.synchronize do
|
124
|
+
# Clean up old sessions (older than 30 minutes)
|
125
|
+
cleanup_old_sessions
|
126
|
+
|
127
|
+
# Create or retrieve session binding
|
128
|
+
unless @@session_bindings[session_id]
|
129
|
+
@@session_bindings[session_id] = create_console_binding
|
130
|
+
@@session_timestamps[session_id] = Time.current
|
131
|
+
end
|
132
|
+
|
133
|
+
# Update timestamp
|
134
|
+
@@session_timestamps[session_id] = Time.current
|
135
|
+
@@session_bindings[session_id]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def clear_session_binding(session_id)
|
140
|
+
@@session_mutex.synchronize do
|
141
|
+
@@session_bindings.delete(session_id)
|
142
|
+
@@session_timestamps.delete(session_id)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def cleanup_old_sessions
|
147
|
+
current_time = Time.current
|
148
|
+
expired_sessions = @@session_timestamps.select do |_session_id, timestamp|
|
149
|
+
current_time - timestamp > 30.minutes
|
150
|
+
end
|
151
|
+
|
152
|
+
expired_sessions.each_key do |session_id|
|
153
|
+
@@session_bindings.delete(session_id)
|
154
|
+
@@session_timestamps.delete(session_id)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
107
158
|
def create_console_binding
|
108
159
|
binding_object = ConsoleBindingHelper.new
|
109
160
|
binding_object.instance_eval { binding }
|
@@ -207,5 +258,33 @@ module StompBase
|
|
207
258
|
rescue StandardError => e
|
208
259
|
"#{result} (inspect failed: #{e.message})"
|
209
260
|
end
|
261
|
+
|
262
|
+
# Session management utility methods
|
263
|
+
def active_sessions_count
|
264
|
+
@@session_mutex.synchronize do
|
265
|
+
@@session_bindings.size
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def session_info(session_id)
|
270
|
+
@@session_mutex.synchronize do
|
271
|
+
return nil unless @@session_bindings.key?(session_id)
|
272
|
+
|
273
|
+
{
|
274
|
+
session_id: session_id,
|
275
|
+
created_at: @@session_timestamps[session_id],
|
276
|
+
last_accessed: @@session_timestamps[session_id],
|
277
|
+
active: true
|
278
|
+
}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def all_sessions_info
|
283
|
+
@@session_mutex.synchronize do
|
284
|
+
@@session_bindings.keys.map do |session_id|
|
285
|
+
session_info(session_id)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
210
289
|
end
|
211
290
|
end
|
@@ -14,7 +14,7 @@ module StompBase
|
|
14
14
|
|
15
15
|
update_theme_setting(params[:theme]) if params[:theme]
|
16
16
|
|
17
|
-
|
17
|
+
safe_redirect_with_notice(t("stomp_base.settings.settings_updated"))
|
18
18
|
end
|
19
19
|
|
20
20
|
def update_locale
|
@@ -43,7 +43,7 @@ module StompBase
|
|
43
43
|
respond_to do |format|
|
44
44
|
format.json { render json: { status: "success", locale: locale } }
|
45
45
|
format.html do
|
46
|
-
|
46
|
+
safe_redirect_with_notice(t("stomp_base.settings.settings_updated"))
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -55,7 +55,7 @@ module StompBase
|
|
55
55
|
status: :unprocessable_entity
|
56
56
|
end
|
57
57
|
format.html do
|
58
|
-
|
58
|
+
safe_redirect_with_alert(t("stomp_base.settings.invalid_locale"))
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -75,5 +75,15 @@ module StompBase
|
|
75
75
|
|
76
76
|
session[:stomp_base_theme] = theme
|
77
77
|
end
|
78
|
+
|
79
|
+
def safe_redirect_with_notice(message)
|
80
|
+
flash[:notice] = message
|
81
|
+
redirect_back(fallback_location: stomp_base.root_path)
|
82
|
+
end
|
83
|
+
|
84
|
+
def safe_redirect_with_alert(message)
|
85
|
+
flash[:alert] = message
|
86
|
+
redirect_back(fallback_location: stomp_base.root_path)
|
87
|
+
end
|
78
88
|
end
|
79
89
|
end
|
data/config/locales/en.yml
CHANGED
@@ -82,10 +82,12 @@ en:
|
|
82
82
|
available: "Available"
|
83
83
|
open_console: "Open Console"
|
84
84
|
welcome_message: "Rails Console"
|
85
|
-
placeholder: "
|
85
|
+
placeholder: "Type your Ruby code here..."
|
86
86
|
execute: "Execute"
|
87
87
|
clear: "Clear"
|
88
88
|
clear_history: "Clear History"
|
89
|
+
restart_session: "Restart Session"
|
90
|
+
session_restarted: "Session restarted"
|
89
91
|
history: "History"
|
90
92
|
output: "Output"
|
91
93
|
no_output: "No output"
|
@@ -97,6 +99,8 @@ en:
|
|
97
99
|
sandbox_mode: "Sandbox Mode"
|
98
100
|
enable_sandbox: "Enable Sandbox"
|
99
101
|
disable_sandbox: "Disable Sandbox"
|
102
|
+
terminal_welcome: "Welcome to StompBase Rails Console"
|
103
|
+
terminal_help: "Type 'help' for available commands"
|
100
104
|
examples:
|
101
105
|
title: "Example Commands"
|
102
106
|
user_count: "User.count"
|
@@ -181,3 +185,11 @@ en:
|
|
181
185
|
table_name_label: "Table Name"
|
182
186
|
record_count_label: "Records"
|
183
187
|
null_value: "NULL"
|
188
|
+
session_info: "Session Information"
|
189
|
+
session_id: "Session ID"
|
190
|
+
session_active: "Active"
|
191
|
+
session_created_at: "Created At"
|
192
|
+
session_last_accessed: "Last Accessed"
|
193
|
+
active_sessions: "Active Sessions Count"
|
194
|
+
variable_persistence: "Variable state is maintained between commands"
|
195
|
+
session_timeout: "Sessions automatically expire after 30 minutes of inactivity"
|
data/config/locales/ja.yml
CHANGED
@@ -82,10 +82,12 @@ ja:
|
|
82
82
|
available: "利用可能"
|
83
83
|
open_console: "コンソールを開く"
|
84
84
|
welcome_message: "Rails Console"
|
85
|
-
placeholder: "Ruby
|
85
|
+
placeholder: "Rubyコードを入力してください..."
|
86
86
|
execute: "実行"
|
87
87
|
clear: "クリア"
|
88
88
|
clear_history: "履歴をクリア"
|
89
|
+
restart_session: "セッションを再開"
|
90
|
+
session_restarted: "セッションが再開されました"
|
89
91
|
history: "履歴"
|
90
92
|
output: "出力"
|
91
93
|
no_output: "出力がありません"
|
@@ -97,6 +99,7 @@ ja:
|
|
97
99
|
sandbox_mode: "サンドボックスモード"
|
98
100
|
enable_sandbox: "サンドボックスを有効にする"
|
99
101
|
disable_sandbox: "サンドボックスを無効にする"
|
102
|
+
terminal_welcome: "StompBase Rails Console へようこそ"
|
100
103
|
examples:
|
101
104
|
title: "コマンド例"
|
102
105
|
user_count: "User.count"
|
@@ -186,3 +189,11 @@ ja:
|
|
186
189
|
table_name_label: "テーブル名"
|
187
190
|
record_count_label: "レコード数"
|
188
191
|
null_value: "NULL"
|
192
|
+
session_info: "セッション情報"
|
193
|
+
session_id: "セッションID"
|
194
|
+
session_active: "アクティブ"
|
195
|
+
session_created_at: "作成日時"
|
196
|
+
session_last_accessed: "最終アクセス"
|
197
|
+
active_sessions: "アクティブセッション数"
|
198
|
+
variable_persistence: "変数の状態はセッション間で保持されます"
|
199
|
+
session_timeout: "セッションは30分間非アクティブ状態が続くと自動的に終了します"
|
data/config/routes.rb
CHANGED
@@ -8,7 +8,9 @@ StompBase::Engine.routes.draw do
|
|
8
8
|
|
9
9
|
get "settings", to: "settings#index"
|
10
10
|
patch "settings", to: "settings#update"
|
11
|
+
post "settings", to: "settings#update"
|
11
12
|
patch "settings/locale", to: "settings#update_locale", as: "update_locale"
|
13
|
+
post "settings/locale", to: "settings#update_locale"
|
12
14
|
|
13
15
|
# Console routes
|
14
16
|
get "console", to: "console#index"
|
data/lib/stomp_base/engine.rb
CHANGED
@@ -15,14 +15,16 @@ module StompBase
|
|
15
15
|
g.helper true
|
16
16
|
end
|
17
17
|
|
18
|
-
# Add asset paths for Rails
|
19
|
-
|
20
|
-
config.
|
21
|
-
|
22
|
-
|
18
|
+
# Add asset paths for Rails compatibility (when asset pipeline is available)
|
19
|
+
config.after_initialize do |app|
|
20
|
+
if app.config.respond_to?(:assets)
|
21
|
+
app.config.assets.paths << root.join("app", "assets", "javascripts")
|
22
|
+
app.config.assets.paths << root.join("app", "assets", "stylesheets")
|
23
|
+
app.config.assets.paths << root.join("app", "javascript")
|
23
24
|
|
24
|
-
|
25
|
-
|
25
|
+
# CSS precompilation (JavaScript is managed by importmap)
|
26
|
+
app.config.assets.precompile += %w[stomp_base/application.css stomp_base/base.css]
|
27
|
+
end
|
26
28
|
end
|
27
29
|
|
28
30
|
# I18n configuration
|
@@ -36,5 +38,102 @@ module StompBase
|
|
36
38
|
I18n.default_locale = StompBase.locale
|
37
39
|
end
|
38
40
|
end
|
41
|
+
|
42
|
+
# Configure static asset serving for API-only Rails applications
|
43
|
+
initializer "stomp_base.static_assets" do |app|
|
44
|
+
if self.class.should_serve_static_assets?(app.config)
|
45
|
+
app.middleware.use(
|
46
|
+
::ActionDispatch::Static,
|
47
|
+
"#{root}/app/assets",
|
48
|
+
headers: {
|
49
|
+
"Cache-Control" => "public, max-age=31536000"
|
50
|
+
}
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Configuration validation for StompBase compatibility
|
56
|
+
initializer "stomp_base.validate_configuration" do |app|
|
57
|
+
app.config.after_initialize do
|
58
|
+
if app.config.api_only && !app.config.respond_to?(:assets)
|
59
|
+
Rails.logger.info "StompBase: Detected API-only Rails application without asset pipeline"
|
60
|
+
|
61
|
+
if app.config.public_file_server.enabled
|
62
|
+
Rails.logger.info "StompBase: Configured static asset serving for API-only mode"
|
63
|
+
else
|
64
|
+
Rails.logger.warn <<~WARNING
|
65
|
+
⚠️ StompBase Warning: Your API-only Rails application has public file server disabled.
|
66
|
+
StompBase requires CSS assets to be served for proper UI functionality.
|
67
|
+
|
68
|
+
To fix this, add to your config/application.rb or config/environments/#{Rails.env}.rb:
|
69
|
+
config.public_file_server.enabled = true
|
70
|
+
|
71
|
+
Or enable ActionView and asset pipeline by uncommenting in config/application.rb:
|
72
|
+
require "action_view/railtie"
|
73
|
+
WARNING
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Configure middleware for API-only Rails applications
|
80
|
+
initializer "stomp_base.api_middleware", before: :build_middleware_stack do |app|
|
81
|
+
if app.config.api_only
|
82
|
+
Rails.logger.info "StompBase: Configuring middleware for API-only Rails application"
|
83
|
+
|
84
|
+
# Add necessary middleware for StompBase compatibility
|
85
|
+
required_middleware = [
|
86
|
+
[Rack::MethodOverride, []],
|
87
|
+
[ActionDispatch::Cookies, []],
|
88
|
+
[ActionDispatch::Session::CookieStore, []],
|
89
|
+
[ActionDispatch::Flash, []]
|
90
|
+
]
|
91
|
+
|
92
|
+
required_middleware.each do |middleware_class, args|
|
93
|
+
app.config.middleware.use middleware_class, *args
|
94
|
+
Rails.logger.debug { "StompBase: Added #{middleware_class} middleware" }
|
95
|
+
rescue ArgumentError => e
|
96
|
+
# Middleware might already be present
|
97
|
+
Rails.logger.debug { "StompBase: #{middleware_class} middleware already present or error: #{e.message}" }
|
98
|
+
end
|
99
|
+
|
100
|
+
Rails.logger.info "StompBase: Middleware configuration completed"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Configure session store for API-only Rails applications
|
105
|
+
initializer "stomp_base.session_store" do |app|
|
106
|
+
if app.config.api_only && !Rails.application.config.session_store
|
107
|
+
app.config.session_store :cookie_store, key: "_#{Rails.application.class.module_parent_name.underscore}_session"
|
108
|
+
Rails.logger.info "StompBase: Configured cookie session store for API-only application"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Check if we need to serve static assets (for API-only Rails apps)
|
113
|
+
def self.should_serve_static_assets?(app_config)
|
114
|
+
# Serve static assets if:
|
115
|
+
# 1. The asset pipeline is not available (API-only mode)
|
116
|
+
# 2. Public file server is enabled (default in development/test)
|
117
|
+
!app_config.respond_to?(:assets) && app_config.public_file_server.enabled
|
118
|
+
end
|
119
|
+
|
120
|
+
# Check for ActionView availability and provide guidance
|
121
|
+
initializer "stomp_base.actionview_check", after: :load_config_initializers do |app|
|
122
|
+
if app.config.api_only
|
123
|
+
if defined?(ActionView::Railtie) && Rails.application.config.railties_order.include?(ActionView::Railtie)
|
124
|
+
Rails.logger.info "StompBase: ActionView railtie detected - full UI functionality available"
|
125
|
+
else
|
126
|
+
Rails.logger.warn <<~WARNING
|
127
|
+
⚠️ StompBase Notice: ActionView railtie is not loaded.
|
128
|
+
StompBase requires ActionView for rendering UI components.
|
129
|
+
|
130
|
+
To enable ActionView, uncomment this line in your config/application.rb:
|
131
|
+
require "action_view/railtie"
|
132
|
+
|
133
|
+
StompBase will attempt to function with limited capabilities.
|
134
|
+
WARNING
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
39
138
|
end
|
40
139
|
end
|
data/lib/stomp_base/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stomp_base
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- snowwshiro
|
@@ -69,6 +69,8 @@ files:
|
|
69
69
|
- app/components/stomp_base/console/console_javascript_component.rb
|
70
70
|
- app/components/stomp_base/console/security_warning_component.html.erb
|
71
71
|
- app/components/stomp_base/console/security_warning_component.rb
|
72
|
+
- app/components/stomp_base/console/terminal_component.html.erb
|
73
|
+
- app/components/stomp_base/console/terminal_component.rb
|
72
74
|
- app/components/stomp_base/dashboard/database_info_card_component.html.erb
|
73
75
|
- app/components/stomp_base/dashboard/database_info_card_component.rb
|
74
76
|
- app/components/stomp_base/dashboard/performance_metrics_card_component.html.erb
|