mbeditor 0.7.1 → 0.7.3
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 +31 -0
- data/README.md +68 -17
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +4 -5
- data/app/controllers/mbeditor/editors_controller.rb +11 -2
- data/app/services/mbeditor/rails_related_files_service.rb +14 -10
- data/app/services/mbeditor/schema_service.rb +58 -7
- data/app/views/layouts/mbeditor/application.html.erb +1 -1
- data/config/routes.rb +4 -56
- data/lib/mbeditor/configuration.rb +4 -1
- data/lib/mbeditor/engine.rb +38 -0
- data/lib/mbeditor/mount_path.rb +62 -0
- data/lib/mbeditor/private_routes.rb +38 -0
- data/lib/mbeditor/rack/resilient_router.rb +74 -0
- data/lib/mbeditor/route_map.rb +65 -0
- data/lib/mbeditor/version.rb +1 -1
- data/lib/mbeditor.rb +3 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 720ab9c5f06c65a444d4e7a4d9204926a91e31941ed5d21df9a8cb234c322124
|
|
4
|
+
data.tar.gz: 3c31e3387d38ba23e997dd71051328678bd225ea6ec2078c7d8cae72b44b09c6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aa5177a8fb2e8511a4452dc33d3965c5838001991883360e2767ad598edefcb0b3f4feeeb54cd9692b0d7e7527cdf87463faeef2713edcb48cdd672aadfc961b
|
|
7
|
+
data.tar.gz: 1634701e852db9e3273f0217e5268c6298f3443fdfc5b598d53cfff6a462771a754c7f4ed187cbc247429e0d19ba27913d188715e3846856c034f3382facab5b
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.7.3] - 2026-06-03
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Custom path reverse lookup** — moved the custom-path check in `extract_resource_names` before the `case` statement so paths under `app/assets/`, `app/javascript/`, etc. are handled. Stripped `_controller`/`_model`/`_helper`/`_service` suffixes from custom-path filenames in both backend and frontend for consistent label/grouping.
|
|
12
|
+
- **Schema modal `self.table_name` support** — reads `self.table_name` from the model file before falling back to `ActiveSupport::Inflector.tableize`, enabling custom table names.
|
|
13
|
+
- **Structure.sql broader schema-prefix regex** — handles quoted schemas, non-public schemas, and no prefix.
|
|
14
|
+
- **PostgreSQL type coverage** — expanded `sql_type_to_rails` with full PostgreSQL type coverage (timestamptz, double precision, citext, hstore, geometric types, etc.).
|
|
15
|
+
- **Schema read error handling** — broadened rescue in `try_schema_rb`/`try_structure_sql` to catch encoding errors.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [0.7.2] - 2026-06-03
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **Changelog entries backfilled** — added full release notes for 0.7.1 (persistent undo history, `db/structure.sql` schema support, Rails panel fixes) so the What's New panel shows accurate content on upgrade.
|
|
23
|
+
- **Release workflow documented** — `CLAUDE.md` now describes the release process so future releases can be triggered with a single instruction.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## [0.7.1] - 2026-06-03
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **Persistent undo history** — edit operations are captured in the browser and flushed to the server on save and tab close, then replayed the next time the file is opened. Undo/redo now reaches back further than the current session. Stale history is pruned automatically when old branches are cleaned up.
|
|
31
|
+
- **`db/structure.sql` schema support** — the model schema modal now reads `db/structure.sql` when `db/schema.rb` is absent (SQL-format migrations).
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- **Rails panel long filenames** — long filenames in the Rails panel are now truncated correctly and custom-path entries populate reliably.
|
|
35
|
+
- **Schema lookup error logging** — failures to parse the schema file now emit a diagnostic log entry to aid debugging.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
8
39
|
## [0.7.0] - 2026-05-21
|
|
9
40
|
|
|
10
41
|
### Added
|
data/README.md
CHANGED
|
@@ -71,26 +71,61 @@ Mbeditor.configure do |config|
|
|
|
71
71
|
# Optional Ruby/Rails side panel tuning
|
|
72
72
|
# config.ruby_def_include_dirs = %w[app/models app/controllers app/helpers app/concerns]
|
|
73
73
|
# config.related_files_custom_paths = %w[app/assets/javascripts/app app/policies]
|
|
74
|
+
|
|
75
|
+
# Resilient routing (see the "Resilient Routing" section below)
|
|
76
|
+
# config.mount_path = "/mbeditor" # explicit prefix override; auto-detected when nil
|
|
77
|
+
# config.resilient_routing = false # escape hatch; true keeps the editor up when host routes break
|
|
74
78
|
end
|
|
75
79
|
```
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
81
|
+
### Core
|
|
82
|
+
|
|
83
|
+
| Option | Default | Description |
|
|
84
|
+
|--------|---------|-------------|
|
|
85
|
+
| `allowed_environments` | `[:development]` | Rails environments allowed to access the engine. |
|
|
86
|
+
| `workspace_root` | `Rails.root` | Root directory exposed by Mbeditor. |
|
|
87
|
+
| `excluded_paths` | `%w[.git tmp log node_modules .bundle coverage vendor/bundle]` | Files/directories hidden from the tree and path operations. Entries without `/` match a name anywhere in the path; entries with `/` match relative paths and their descendants. |
|
|
88
|
+
| `rubocop_command` | `"rubocop"` | Command used for inline Ruby linting and formatting. |
|
|
89
|
+
|
|
90
|
+
### Authentication
|
|
91
|
+
|
|
92
|
+
| Option | Default | Description |
|
|
93
|
+
|--------|---------|-------------|
|
|
94
|
+
| `authenticate_with` | `nil` | Proc run as a `before_action` in all engine controllers. Executed via `instance_exec` inside the controller, so it has access to `session`, `cookies`, `redirect_to`, and auth-library class methods (e.g. Authlogic's `UserSession.find`) — but not helper methods from the host's `ApplicationController`. |
|
|
95
|
+
| `authentication_cache_ttl` | `0` | Seconds to cache the auth result in the session (`0` = no caching). Set e.g. `300` to avoid calling `authenticate_with` on every request when the proc is expensive. Trade-off: after host logout, mbeditor stays accessible for up to TTL seconds. |
|
|
96
|
+
|
|
97
|
+
### Test runner
|
|
98
|
+
|
|
99
|
+
| Option | Default | Description |
|
|
100
|
+
|--------|---------|-------------|
|
|
101
|
+
| `test_framework` | `nil` | `:minitest` or `:rspec`. Auto-detected from file suffix, `.rspec`, or `test`/`spec` directory when `nil`. |
|
|
102
|
+
| `test_command` | `nil` | Full command used to run a test file. When `nil`, picks `bin/rails test` (Minitest) or `bin/rspec` / `bundle exec rspec` (RSpec). |
|
|
103
|
+
| `test_timeout` | `60` | Maximum seconds a test run may take before being killed. |
|
|
104
|
+
|
|
105
|
+
### Redmine
|
|
106
|
+
|
|
107
|
+
| Option | Default | Description |
|
|
108
|
+
|--------|---------|-------------|
|
|
109
|
+
| `redmine_enabled` | `false` | Enables issue-lookup integration. |
|
|
110
|
+
| `redmine_url` | — | Redmine base URL. Required when `redmine_enabled` is `true`. |
|
|
111
|
+
| `redmine_api_key` | — | Redmine API key. Required when `redmine_enabled` is `true`. |
|
|
112
|
+
| `redmine_ticket_source` | `:commit` | How the current ticket is identified. `:commit` scans the 100 most recent branch commits for a `#123` reference; `:branch` reads leading digits from the branch name (e.g. `123-my-feature` → ticket 123). |
|
|
113
|
+
|
|
114
|
+
### Ruby/Rails side panel
|
|
115
|
+
|
|
116
|
+
| Option | Default | Description |
|
|
117
|
+
|--------|---------|-------------|
|
|
118
|
+
| `ruby_def_include_dirs` | `%w[app/models app/controllers app/helpers app/concerns]` | Workspace-relative directories searched when resolving Ruby go-to-definition jumps. Add any extra dirs holding Ruby source you want indexed. |
|
|
119
|
+
| `related_files_custom_paths` | `[]` | Extra base directories for the Rails related-files side panel. For each entry the panel looks for a subdirectory named after the current resource (plural or singular). E.g. `"app/assets/javascripts/app"` surfaces `app/assets/javascripts/app/users/` when editing a `users` resource. |
|
|
120
|
+
|
|
121
|
+
### Resilient routing
|
|
122
|
+
|
|
123
|
+
See [Resilient Routing](#resilient-routing) for details.
|
|
124
|
+
|
|
125
|
+
| Option | Default | Description |
|
|
126
|
+
|--------|---------|-------------|
|
|
127
|
+
| `mount_path` | `nil` | Explicit URL prefix to serve resilient routing from. When `nil`, auto-detected from your `mount Mbeditor::Engine, at: "..."` line on every healthy boot. Set only to override detection. |
|
|
128
|
+
| `resilient_routing` | `true` | Keeps mbeditor reachable when the host's `config/routes.rb` is broken, by serving its traffic from middleware that dispatches to a private route set. Set to `false` as an escape hatch: no middleware is inserted and the private set is never built. |
|
|
94
129
|
|
|
95
130
|
## Test Runner
|
|
96
131
|
|
|
@@ -111,6 +146,22 @@ The Test button appears in the editor toolbar for any `.rb` file when a `test/`
|
|
|
111
146
|
- Minitest: `bin/rails test <file>` if `bin/rails` exists, otherwise `bundle exec ruby -Itest <file>`
|
|
112
147
|
- RSpec: `bin/rspec <file>` if `bin/rspec` exists, otherwise `bundle exec rspec --format json <file>`
|
|
113
148
|
|
|
149
|
+
## Resilient Routing
|
|
150
|
+
|
|
151
|
+
A broken `config/routes.rb` normally takes down the whole app — every request, including the one you'd use to fix it, raises while Rails tries to reload the route table. Mbeditor stays reachable anyway: it serves its own traffic from middleware that dispatches to a **private route set** built at boot and never registered with Rails' route reloader. When a bad route draw wipes the host route table, that private set survives the wipe, so `/mbeditor` keeps working while the rest of the app is down. This is on by default (`resilient_routing = true`); you don't need to configure anything.
|
|
152
|
+
|
|
153
|
+
**Custom mount paths work with zero configuration.** On every healthy boot, mbeditor detects the prefix from your `mount Mbeditor::Engine, at: "..."` line and remembers it. If the route table later breaks, the remembered prefix is used — so resilient routing serves from your custom mount, not just `/mbeditor`. Detection only ever updates from a *healthy* load, so a broken reload can never overwrite a good prefix. Set `config.mount_path` only if you want to override detection explicitly.
|
|
154
|
+
|
|
155
|
+
**What it cannot recover from: a host app that fails to *boot*.** Resilient routing relies on mbeditor's engine initializers running — that's when the middleware is inserted and the private route set is built. If the app can't boot at all, those initializers never run and there is nothing to fall back to. This includes:
|
|
156
|
+
|
|
157
|
+
- a syntax error or raised exception in `config/application.rb` or other engine/initializer code,
|
|
158
|
+
- a broken initializer in `config/initializers/`,
|
|
159
|
+
- a bad or incompatible gem that fails to load.
|
|
160
|
+
|
|
161
|
+
A *broken route* is recoverable in the browser; a *failed boot* is not. If the app won't boot, fix it from a terminal — mbeditor can't help until the app can start.
|
|
162
|
+
|
|
163
|
+
**Turning it off.** Set `config.resilient_routing = false` as an escape hatch (e.g. to debug a middleware-ordering conflict). With the flag off, no mbeditor middleware is inserted and the private route set is never built; mbeditor is then served only through the normal mount and shares the fate of a broken `config/routes.rb`.
|
|
164
|
+
|
|
114
165
|
## Keyboard Shortcuts
|
|
115
166
|
|
|
116
167
|
| Shortcut | Action |
|
|
@@ -1631,13 +1631,12 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
1631
1631
|
if (p.startsWith(base + '/')) {
|
|
1632
1632
|
var rest = p.slice(base.length + 1);
|
|
1633
1633
|
var resource = rest.split('/')[0].replace(/\.[^.]+$/, '');
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
}
|
|
1634
|
+
// Strip Rails-style suffixes so custom-path files group with their controller/model
|
|
1635
|
+
resource = resource.replace(/_(controller|model|helper|service)$/, '');
|
|
1636
|
+
if (resource) { name = resource; break; }
|
|
1638
1637
|
}
|
|
1639
1638
|
}
|
|
1640
|
-
return null;
|
|
1639
|
+
if (!name) return null;
|
|
1641
1640
|
}
|
|
1642
1641
|
var seg = (name || '').split('/').pop() || name || '';
|
|
1643
1642
|
// Normalize plural→singular so views/users and models/user share one group
|
|
@@ -15,6 +15,7 @@ module Mbeditor
|
|
|
15
15
|
before_action :verify_mbeditor_client, unless: -> { request.get? || request.head? }
|
|
16
16
|
|
|
17
17
|
IMAGE_EXTENSIONS = %w[png jpg jpeg gif svg ico webp bmp avif].freeze
|
|
18
|
+
helper_method :mbeditor_base_path
|
|
18
19
|
|
|
19
20
|
# GET /mbeditor — renders the IDE shell
|
|
20
21
|
def index
|
|
@@ -545,8 +546,7 @@ module Mbeditor
|
|
|
545
546
|
|
|
546
547
|
# GET /mbeditor/manifest.webmanifest — PWA manifest
|
|
547
548
|
def pwa_manifest
|
|
548
|
-
|
|
549
|
-
base = raw.start_with?("/") || raw.empty? ? raw : "/#{raw}"
|
|
549
|
+
base = mbeditor_base_path
|
|
550
550
|
manifest = {
|
|
551
551
|
name: "Mbeditor — #{Rails.root.basename}",
|
|
552
552
|
short_name: "Mbeditor",
|
|
@@ -787,6 +787,15 @@ module Mbeditor
|
|
|
787
787
|
|
|
788
788
|
private
|
|
789
789
|
|
|
790
|
+
# Normalized base prefix mbeditor renders URLs against. Sourced from
|
|
791
|
+
# MountPath (not the engine `root_path` helper) so it still resolves when a
|
|
792
|
+
# broken host config/routes.rb has wiped Mbeditor::Engine.routes — the exact
|
|
793
|
+
# state resilient routing exists to survive.
|
|
794
|
+
def mbeditor_base_path
|
|
795
|
+
raw = Mbeditor::MountPath.resolve.chomp("/")
|
|
796
|
+
raw.start_with?("/") || raw.empty? ? raw : "/#{raw}"
|
|
797
|
+
end
|
|
798
|
+
|
|
790
799
|
def history_file_path(branch, rel_path)
|
|
791
800
|
branch_hash = Digest::SHA256.hexdigest(branch.to_s)[0, 16]
|
|
792
801
|
file_hash = Digest::SHA256.hexdigest(rel_path.to_s)[0, 16]
|
|
@@ -124,6 +124,20 @@ module Mbeditor
|
|
|
124
124
|
parts = relative_path.to_s.split("/")
|
|
125
125
|
return nil unless parts.length >= 2
|
|
126
126
|
|
|
127
|
+
# Custom paths are checked first so they work regardless of top-level prefix.
|
|
128
|
+
# Paths under app/assets/, app/javascript/, etc. never reach the standard
|
|
129
|
+
# "app" branch, so the check must happen before the case statement.
|
|
130
|
+
Array(custom_paths).each do |base|
|
|
131
|
+
base = base.to_s.strip
|
|
132
|
+
next if base.empty?
|
|
133
|
+
next unless relative_path.start_with?("#{base}/")
|
|
134
|
+
rest = relative_path.delete_prefix("#{base}/")
|
|
135
|
+
resource = rest.split('/').first.to_s.sub(/\.[^.]+$/, '') # first segment, no extension
|
|
136
|
+
resource = resource.sub(/_(controller|model|helper|service)$/, '') # strip Rails suffixes
|
|
137
|
+
next if resource.empty?
|
|
138
|
+
return [pluralize(resource), singularize(resource)]
|
|
139
|
+
end
|
|
140
|
+
|
|
127
141
|
case parts[0]
|
|
128
142
|
when "app"
|
|
129
143
|
case parts[1]
|
|
@@ -230,16 +244,6 @@ module Mbeditor
|
|
|
230
244
|
end
|
|
231
245
|
|
|
232
246
|
else
|
|
233
|
-
# Custom path fallback — must be last
|
|
234
|
-
Array(custom_paths).each do |base|
|
|
235
|
-
base = base.to_s.strip
|
|
236
|
-
next if base.empty?
|
|
237
|
-
next unless relative_path.start_with?("#{base}/")
|
|
238
|
-
rest = relative_path.delete_prefix("#{base}/")
|
|
239
|
-
resource = rest.split('/').first.to_s.sub(/\.[^.]+$/, '') # first path segment, no extension
|
|
240
|
-
next if resource.empty?
|
|
241
|
-
return [pluralize(resource), singularize(resource)]
|
|
242
|
-
end
|
|
243
247
|
nil
|
|
244
248
|
end
|
|
245
249
|
end
|
|
@@ -40,8 +40,25 @@ module Mbeditor
|
|
|
40
40
|
private
|
|
41
41
|
|
|
42
42
|
# "User" → "users", "OrderItem" → "order_items", "Order Item" → "order_items"
|
|
43
|
+
# Also checks the model file for an explicit `self.table_name = "..."` declaration.
|
|
43
44
|
def derive_table_name(model_name)
|
|
44
45
|
normalized = model_name.delete(" ")
|
|
46
|
+
|
|
47
|
+
# Check model file for an explicit table_name override
|
|
48
|
+
singular = ActiveSupport::Inflector.underscore(normalized)
|
|
49
|
+
model_file = File.join(@workspace_root, "app", "models", "#{singular}.rb")
|
|
50
|
+
if File.exist?(model_file)
|
|
51
|
+
begin
|
|
52
|
+
source = File.read(model_file, encoding: "utf-8")
|
|
53
|
+
# Matches: self.table_name = "name" or = :name or = 'name'
|
|
54
|
+
if (m = source.match(/self\.table_name\s*=\s*[:"']([^"'\s]+)["']?/))
|
|
55
|
+
return m[1]
|
|
56
|
+
end
|
|
57
|
+
rescue StandardError
|
|
58
|
+
# fall through to default derivation
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
45
62
|
ActiveSupport::Inflector.tableize(normalized)
|
|
46
63
|
end
|
|
47
64
|
|
|
@@ -53,7 +70,7 @@ module Mbeditor
|
|
|
53
70
|
begin
|
|
54
71
|
content = File.read(schema_path, encoding: "utf-8")
|
|
55
72
|
parse_schema_rb(content, table_name)
|
|
56
|
-
rescue
|
|
73
|
+
rescue StandardError => e
|
|
57
74
|
Rails.logger.debug("SchemaService: failed to read #{schema_path}: #{e.message}")
|
|
58
75
|
nil
|
|
59
76
|
end
|
|
@@ -67,7 +84,7 @@ module Mbeditor
|
|
|
67
84
|
begin
|
|
68
85
|
content = File.read(schema_path, encoding: "utf-8")
|
|
69
86
|
parse_structure_sql(content, table_name)
|
|
70
|
-
rescue
|
|
87
|
+
rescue StandardError => e
|
|
71
88
|
Rails.logger.debug("SchemaService: failed to read #{schema_path}: #{e.message}")
|
|
72
89
|
nil
|
|
73
90
|
end
|
|
@@ -145,11 +162,13 @@ module Mbeditor
|
|
|
145
162
|
# Handles: PostgreSQL, MySQL, SQLite with quoted/unquoted names
|
|
146
163
|
# Ends with different delimiters: ); ENGINE...; or just );
|
|
147
164
|
quoted_name = Regexp.escape(table_name)
|
|
165
|
+
# Schema prefix pattern: matches public., "public"., myschema., "myschema". or nothing.
|
|
166
|
+
schema_prefix = /(?:(?:"[^"]+"|`[^`]+`|\w+)\.)?/
|
|
148
167
|
patterns = [
|
|
149
|
-
# PostgreSQL
|
|
150
|
-
/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)
|
|
151
|
-
# MySQL
|
|
152
|
-
/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)
|
|
168
|
+
# PostgreSQL: CREATE TABLE [schema.]table ( ... );
|
|
169
|
+
/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?#{schema_prefix}["`]?#{quoted_name}["`]?\s*\(([\s\S]*?)\)\s*;/mi,
|
|
170
|
+
# MySQL: CREATE TABLE [schema.]`table` ( ... ) ENGINE=...;
|
|
171
|
+
/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?#{schema_prefix}["`]?#{quoted_name}["`]?\s*\(([\s\S]*?)\)\s*(?:ENGINE|DEFAULT)/mi
|
|
153
172
|
]
|
|
154
173
|
|
|
155
174
|
table_def = nil
|
|
@@ -240,6 +259,9 @@ module Mbeditor
|
|
|
240
259
|
type_map = {
|
|
241
260
|
'integer' => 'integer',
|
|
242
261
|
'int' => 'integer',
|
|
262
|
+
'int4' => 'integer',
|
|
263
|
+
'int2' => 'integer',
|
|
264
|
+
'int8' => 'bigint',
|
|
243
265
|
'bigint' => 'bigint',
|
|
244
266
|
'smallint' => 'integer',
|
|
245
267
|
'bigserial' => 'bigint',
|
|
@@ -247,21 +269,50 @@ module Mbeditor
|
|
|
247
269
|
'varchar' => 'string',
|
|
248
270
|
'character varying' => 'string',
|
|
249
271
|
'character' => 'string',
|
|
272
|
+
'char' => 'string',
|
|
250
273
|
'text' => 'text',
|
|
274
|
+
'citext' => 'string',
|
|
251
275
|
'boolean' => 'boolean',
|
|
252
276
|
'bool' => 'boolean',
|
|
253
277
|
'decimal' => 'decimal',
|
|
254
278
|
'numeric' => 'decimal',
|
|
279
|
+
'real' => 'float',
|
|
255
280
|
'float' => 'float',
|
|
281
|
+
'float4' => 'float',
|
|
282
|
+
'float8' => 'float',
|
|
283
|
+
'double precision' => 'float',
|
|
256
284
|
'double' => 'float',
|
|
285
|
+
'money' => 'decimal',
|
|
257
286
|
'timestamp' => 'datetime',
|
|
287
|
+
'timestamp without time zone' => 'datetime',
|
|
288
|
+
'timestamp with time zone' => 'datetime',
|
|
289
|
+
'timestamptz' => 'datetime',
|
|
258
290
|
'datetime' => 'datetime',
|
|
259
291
|
'date' => 'date',
|
|
260
292
|
'time' => 'time',
|
|
293
|
+
'time without time zone' => 'time',
|
|
294
|
+
'time with time zone' => 'time',
|
|
295
|
+
'interval' => 'string',
|
|
261
296
|
'json' => 'json',
|
|
262
297
|
'jsonb' => 'jsonb',
|
|
263
298
|
'uuid' => 'uuid',
|
|
264
|
-
'bytea' => 'binary'
|
|
299
|
+
'bytea' => 'binary',
|
|
300
|
+
'bit' => 'string',
|
|
301
|
+
'bit varying' => 'string',
|
|
302
|
+
'inet' => 'string',
|
|
303
|
+
'cidr' => 'string',
|
|
304
|
+
'macaddr' => 'string',
|
|
305
|
+
'xml' => 'string',
|
|
306
|
+
'hstore' => 'hstore',
|
|
307
|
+
'tsvector' => 'string',
|
|
308
|
+
'ltree' => 'string',
|
|
309
|
+
'point' => 'string',
|
|
310
|
+
'line' => 'string',
|
|
311
|
+
'lseg' => 'string',
|
|
312
|
+
'box' => 'string',
|
|
313
|
+
'path' => 'string',
|
|
314
|
+
'polygon' => 'string',
|
|
315
|
+
'circle' => 'string'
|
|
265
316
|
}
|
|
266
317
|
|
|
267
318
|
type_map[sql_type.downcase] || sql_type
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<meta name="theme-color" content="#1e1e2e" />
|
|
8
8
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
9
9
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
10
|
-
<%
|
|
10
|
+
<% pwa_base = mbeditor_base_path %>
|
|
11
11
|
<link rel="manifest" href="<%= "#{pwa_base}/manifest.webmanifest" %>" />
|
|
12
12
|
<script>
|
|
13
13
|
if ('serviceWorker' in navigator) {
|
data/config/routes.rb
CHANGED
|
@@ -1,58 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
Mbeditor::
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
get 'workspace', to: 'editors#workspace'
|
|
8
|
-
get 'files', to: 'editors#files'
|
|
9
|
-
get 'file', to: 'editors#show'
|
|
10
|
-
get 'raw', to: 'editors#raw'
|
|
11
|
-
post 'file', to: 'editors#save'
|
|
12
|
-
post 'create_file', to: 'editors#create_file'
|
|
13
|
-
post 'create_dir', to: 'editors#create_dir'
|
|
14
|
-
patch 'rename', to: 'editors#rename'
|
|
15
|
-
delete 'delete', to: 'editors#destroy_path'
|
|
16
|
-
get 'state', to: 'editors#state'
|
|
17
|
-
post 'state', to: 'editors#save_state'
|
|
18
|
-
get 'branch_state', to: 'editors#branch_state'
|
|
19
|
-
post 'branch_state', to: 'editors#save_branch_state'
|
|
20
|
-
post 'prune_branch_states', to: 'editors#prune_branch_states'
|
|
21
|
-
get 'file_history', to: 'editors#file_history'
|
|
22
|
-
post 'file_history', to: 'editors#save_file_history'
|
|
23
|
-
get 'search', to: 'editors#search'
|
|
24
|
-
post 'replace_in_files', to: 'editors#replace_in_files'
|
|
25
|
-
get 'definition', to: 'editors#definition'
|
|
26
|
-
get 'js_definition', to: 'editors#js_definition'
|
|
27
|
-
get 'js_members', to: 'editors#js_members'
|
|
28
|
-
get 'module_members', to: 'editors#module_members'
|
|
29
|
-
get 'file_includes', to: 'editors#file_includes'
|
|
30
|
-
get 'client_config', to: 'editors#client_config'
|
|
31
|
-
get 'related_files', to: 'editors#related_files'
|
|
32
|
-
get 'model_schema', to: 'editors#model_schema'
|
|
33
|
-
get 'changelog', to: 'editors#changelog'
|
|
34
|
-
get 'git_info', to: 'editors#git_info'
|
|
35
|
-
get 'git_status', to: 'editors#git_status'
|
|
36
|
-
get 'manifest.webmanifest', to: 'editors#pwa_manifest', format: false
|
|
37
|
-
get 'sw.js', to: 'editors#pwa_sw', format: false
|
|
38
|
-
get 'mbeditor-icon.svg', to: 'editors#pwa_icon', format: false
|
|
39
|
-
get 'monaco_worker.js', to: 'editors#monaco_worker', format: false
|
|
40
|
-
get 'ts_worker.js', to: 'editors#ts_worker', format: false
|
|
41
|
-
get 'monaco-editor/*asset_path', to: 'editors#monaco_asset', format: false
|
|
42
|
-
get 'min-maps/*asset_path', to: 'editors#monaco_asset', format: false
|
|
43
|
-
post 'lint', to: 'editors#lint'
|
|
44
|
-
post 'quick_fix', to: 'editors#quick_fix'
|
|
45
|
-
post 'format', to: 'editors#format_file'
|
|
46
|
-
post 'test', to: 'editors#run_test'
|
|
47
|
-
|
|
48
|
-
# ── Git & Code Review ──────────────────────────────────────────────────────
|
|
49
|
-
get 'git/diff', to: 'git#diff'
|
|
50
|
-
get 'git/blame', to: 'git#blame'
|
|
51
|
-
get 'git/file_history', to: 'git#file_history'
|
|
52
|
-
get 'git/commit_graph', to: 'git#commit_graph'
|
|
53
|
-
get 'git/commit_detail', to: 'git#commit_detail'
|
|
54
|
-
get 'git/combined_diff', to: 'git#combined_diff'
|
|
55
|
-
|
|
56
|
-
# Redmine integration (enabled via config.mbeditor.redmine_enabled)
|
|
57
|
-
get 'redmine/issue/:id', to: 'git#redmine_issue', as: :redmine_issue
|
|
58
|
-
end
|
|
3
|
+
# Routes are declared in Mbeditor::ROUTE_MAP (lib/mbeditor/route_map.rb), the
|
|
4
|
+
# single source of truth shared with the private, isolated route set. Drawing
|
|
5
|
+
# from it here keeps the engine route set and the private set from drifting.
|
|
6
|
+
Mbeditor::Engine.routes.draw(&Mbeditor::ROUTE_MAP)
|
|
@@ -7,7 +7,8 @@ module Mbeditor
|
|
|
7
7
|
:test_framework, :test_command, :test_timeout,
|
|
8
8
|
:authenticate_with, :authentication_cache_ttl,
|
|
9
9
|
:lint_timeout, :base_branch_candidates, :git_timeout,
|
|
10
|
-
:ruby_def_include_dirs, :related_files_custom_paths
|
|
10
|
+
:ruby_def_include_dirs, :related_files_custom_paths,
|
|
11
|
+
:mount_path, :resilient_routing
|
|
11
12
|
|
|
12
13
|
def initialize
|
|
13
14
|
@allowed_environments = [:development]
|
|
@@ -27,6 +28,8 @@ module Mbeditor
|
|
|
27
28
|
@ruby_def_include_dirs = %w[app/models app/controllers app/helpers app/concerns]
|
|
28
29
|
@related_files_custom_paths = []
|
|
29
30
|
@authentication_cache_ttl = 0
|
|
31
|
+
@mount_path = nil # explicit URL prefix override; nil falls through to detection/"/mbeditor"
|
|
32
|
+
@resilient_routing = true # serve /mbeditor from middleware so the editor survives a broken host routes.rb; false is the escape hatch
|
|
30
33
|
end
|
|
31
34
|
end
|
|
32
35
|
end
|
data/lib/mbeditor/engine.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "mbeditor/rack/silence_ping_request"
|
|
4
4
|
require "mbeditor/rack/handle_pending_migrations"
|
|
5
|
+
require "mbeditor/rack/resilient_router"
|
|
5
6
|
require "mbeditor/cable_log_filter"
|
|
6
7
|
|
|
7
8
|
module Mbeditor
|
|
@@ -12,6 +13,43 @@ module Mbeditor
|
|
|
12
13
|
app.middleware.insert_before Rails::Rack::Logger, Mbeditor::Rack::SilencePingRequest
|
|
13
14
|
end
|
|
14
15
|
|
|
16
|
+
initializer "mbeditor.resilient_routing" do |app|
|
|
17
|
+
# Serve mbeditor's own traffic from middleware that dispatches to a
|
|
18
|
+
# private, isolated route set, so the editor survives a broken host
|
|
19
|
+
# config/routes.rb. Disabling the flag is the escape hatch: no middleware
|
|
20
|
+
# is inserted and the private set is never built.
|
|
21
|
+
next unless Mbeditor.configuration.resilient_routing
|
|
22
|
+
|
|
23
|
+
# ActionDispatch::Reloader is only in the stack when reloading is enabled
|
|
24
|
+
# (the same condition Rails uses to add it). Sitting just above it means
|
|
25
|
+
# mbeditor requests are intercepted before any route reload can raise,
|
|
26
|
+
# while staying below DebugExceptions/ShowExceptions (mbeditor's own
|
|
27
|
+
# errors still get Rails error pages) and below Executor (dispatch runs
|
|
28
|
+
# inside app.executor's connection management).
|
|
29
|
+
if app.config.reloading_enabled?
|
|
30
|
+
app.middleware.insert_before ActionDispatch::Reloader, Mbeditor::Rack::ResilientRouter
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Build the private set at boot so it is ready before the first request
|
|
34
|
+
# and before the host route table can ever break.
|
|
35
|
+
Mbeditor::PrivateRoutes.route_set
|
|
36
|
+
|
|
37
|
+
# Auto-detect the mount prefix from each *healthy* route load and cache it,
|
|
38
|
+
# so resilient routing works at a custom mount with zero configuration.
|
|
39
|
+
# after_routes_loaded fires only after a successful load — a raising
|
|
40
|
+
# routes.rb skips it — so the cache is never populated from the wiped
|
|
41
|
+
# break-time table. MountPath.refresh! is a no-op when the engine isn't
|
|
42
|
+
# found, so a stray load can never clobber a prefix from an earlier
|
|
43
|
+
# healthy one.
|
|
44
|
+
#
|
|
45
|
+
# The hook's yielded receiver is NOT reliably Rails.application — the
|
|
46
|
+
# reloader's to_run path fires it with the reloader callback context as
|
|
47
|
+
# self — so read the live route set through Rails.application directly.
|
|
48
|
+
app.config.after_routes_loaded do
|
|
49
|
+
Mbeditor::MountPath.refresh!(Rails.application.routes)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
15
53
|
initializer "mbeditor.handle_pending_migrations" do |app|
|
|
16
54
|
# Insert before CheckPending so our middleware wraps it and can rescue
|
|
17
55
|
# the error it raises. Falls back silently if CheckPending is absent
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mbeditor
|
|
4
|
+
# Resolves the active URL prefix mbeditor serves from.
|
|
5
|
+
#
|
|
6
|
+
# At break-time the host route table is wiped, so it is the wrong place to
|
|
7
|
+
# ask "where am I mounted?". MountPath answers from a resolution chain that
|
|
8
|
+
# never touches the route table directly:
|
|
9
|
+
#
|
|
10
|
+
# 1. explicit Mbeditor.configuration.mount_path (override)
|
|
11
|
+
# 2. the cached detected value (populated from a healthy route load)
|
|
12
|
+
# 3. the "/mbeditor" default
|
|
13
|
+
#
|
|
14
|
+
# The cache is guarded by a mutex because it is read at break-time from
|
|
15
|
+
# whatever request thread happens to be serving mbeditor.
|
|
16
|
+
module MountPath
|
|
17
|
+
DEFAULT = '/mbeditor'
|
|
18
|
+
|
|
19
|
+
@mutex = Mutex.new
|
|
20
|
+
@cached = nil
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def resolve
|
|
24
|
+
Mbeditor.configuration.mount_path || cached || DEFAULT
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Scans a route set for the route that mounts Mbeditor::Engine and returns
|
|
28
|
+
# its path-spec prefix (e.g. "/mbeditor"), or nil if the engine is not
|
|
29
|
+
# mounted in this set. A mounted engine's route.app is a Constraints
|
|
30
|
+
# wrapper whose #app is the engine; an unmounted route's app is something
|
|
31
|
+
# else, so an unwrap-once-then-compare is enough.
|
|
32
|
+
def detect(route_set)
|
|
33
|
+
route_set.routes.each do |route|
|
|
34
|
+
app = route.app
|
|
35
|
+
target = app.respond_to?(:app) ? app.app : app
|
|
36
|
+
return route.path.spec.to_s if target == Mbeditor::Engine
|
|
37
|
+
end
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Re-detects from a route set and caches the result. Called from the
|
|
42
|
+
# engine's after_routes_loaded hook, which fires only on a *healthy* route
|
|
43
|
+
# load — never at break-time, when the table is wiped. A nil detection is
|
|
44
|
+
# left as a no-op so a stray refresh from an engine-less set can never
|
|
45
|
+
# clobber a good prefix cached from an earlier healthy load.
|
|
46
|
+
def refresh!(route_set)
|
|
47
|
+
detected = detect(route_set)
|
|
48
|
+
self.cached = detected if detected
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The cached detected prefix, or nil if nothing has been detected yet.
|
|
52
|
+
def cached
|
|
53
|
+
@mutex.synchronize { @cached }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Stores the detected prefix. Passing nil clears the cache.
|
|
57
|
+
def cached=(value)
|
|
58
|
+
@mutex.synchronize { @cached = value }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mbeditor
|
|
4
|
+
# The private, isolated route set mbeditor dispatches to when the host route
|
|
5
|
+
# table is broken.
|
|
6
|
+
#
|
|
7
|
+
# It is built from Mbeditor::ROUTE_MAP — the same source the engine's own
|
|
8
|
+
# route set draws from — so the two can never drift apart. Crucially, this set
|
|
9
|
+
# is created with ActionDispatch::Routing::RouteSet.new and is *never*
|
|
10
|
+
# registered with the host RoutesReloader. The reloader's clear! wipes every
|
|
11
|
+
# route set it knows about when a host route draw raises; because this set is
|
|
12
|
+
# unknown to it, it survives the wipe and keeps mbeditor reachable.
|
|
13
|
+
#
|
|
14
|
+
# ROUTE_MAP declares controllers without a namespace (e.g. "editors#index").
|
|
15
|
+
# The engine resolves those under "mbeditor/" via isolate_namespace; a plain
|
|
16
|
+
# RouteSet does not, so we reproduce the namespacing with scope module:.
|
|
17
|
+
module PrivateRoutes
|
|
18
|
+
@mutex = Mutex.new
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def route_set
|
|
22
|
+
@mutex.synchronize { @route_set ||= build }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def build
|
|
28
|
+
set = ActionDispatch::Routing::RouteSet.new
|
|
29
|
+
set.draw do
|
|
30
|
+
scope module: 'mbeditor' do
|
|
31
|
+
instance_exec(&Mbeditor::ROUTE_MAP)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
set
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mbeditor
|
|
4
|
+
module Rack
|
|
5
|
+
# Serves mbeditor's own traffic from a private, isolated route set so the
|
|
6
|
+
# editor stays reachable even when the host config/routes.rb is broken.
|
|
7
|
+
#
|
|
8
|
+
# Sibling of HandlePendingMigrations: both intercept mbeditor requests when
|
|
9
|
+
# the normal path is blocked. This one sits above ActionDispatch::Reloader,
|
|
10
|
+
# so a prefix-matching request is dispatched before any route reload can
|
|
11
|
+
# raise. Requests that don't match the mount prefix pass through untouched.
|
|
12
|
+
#
|
|
13
|
+
# The matched request is rewritten to mirror how Rails mounts an engine:
|
|
14
|
+
# the prefix is stripped from PATH_INFO and moved to SCRIPT_NAME, so the
|
|
15
|
+
# private set sees the un-prefixed path while the rendered base path stays
|
|
16
|
+
# correct. Dispatch still flows through the mbeditor controllers, so
|
|
17
|
+
# verify_mbeditor_client and resolve_path run unchanged.
|
|
18
|
+
#
|
|
19
|
+
# Because this middleware sits above the Reloader — and therefore above the
|
|
20
|
+
# host's Cookies/Session/Flash middleware — a bare dispatch would leave
|
|
21
|
+
# resilient-routed requests without a session, breaking session-based
|
|
22
|
+
# authenticate_with. To keep parity with the normal mount, the private set
|
|
23
|
+
# is wrapped in the host app's own cookies/session/flash middleware. The
|
|
24
|
+
# crypto config (key generator, secret_key_base, serializer) is already in
|
|
25
|
+
# env, merged by Rails::Application#call before the stack runs.
|
|
26
|
+
class ResilientRouter
|
|
27
|
+
def initialize(app)
|
|
28
|
+
@app = app
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def call(env)
|
|
32
|
+
prefix = Mbeditor::MountPath.resolve
|
|
33
|
+
path = "#{env["SCRIPT_NAME"]}#{env["PATH_INFO"]}"
|
|
34
|
+
|
|
35
|
+
return @app.call(env) unless matches_prefix?(path, prefix)
|
|
36
|
+
|
|
37
|
+
remainder = path[prefix.length..] || ""
|
|
38
|
+
remainder = "/" if remainder.empty?
|
|
39
|
+
env["SCRIPT_NAME"] = prefix
|
|
40
|
+
env["PATH_INFO"] = remainder
|
|
41
|
+
|
|
42
|
+
dispatch.call(env)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def matches_prefix?(path, prefix)
|
|
48
|
+
path == prefix || path.start_with?("#{prefix}/")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The private route set wrapped in the host's session middleware, so a
|
|
52
|
+
# resilient-routed request has the same session support as one that
|
|
53
|
+
# reaches mbeditor through the normal mount. Built lazily and memoized;
|
|
54
|
+
# the middleware instance lives for the process, so a benign double-build
|
|
55
|
+
# under a startup race is harmless.
|
|
56
|
+
def dispatch
|
|
57
|
+
@dispatch ||= build_dispatch
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def build_dispatch
|
|
61
|
+
app = Mbeditor::PrivateRoutes.route_set
|
|
62
|
+
config = Rails.application.config
|
|
63
|
+
store = config.session_store
|
|
64
|
+
# config.session_store is the store class normally, but :disabled (a
|
|
65
|
+
# symbol) when sessions are off — in which case dispatch the bare set.
|
|
66
|
+
return app unless store.is_a?(Class)
|
|
67
|
+
|
|
68
|
+
app = ActionDispatch::Flash.new(app)
|
|
69
|
+
app = store.new(app, config.session_options)
|
|
70
|
+
ActionDispatch::Cookies.new(app)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mbeditor
|
|
4
|
+
# Single source of truth for the engine's routes.
|
|
5
|
+
#
|
|
6
|
+
# Both the engine's own route set (config/routes.rb via
|
|
7
|
+
# Mbeditor::Engine.routes.draw) and the (later) private, isolated route set
|
|
8
|
+
# draw from this same proc, so the two can never drift apart.
|
|
9
|
+
ROUTE_MAP = proc do
|
|
10
|
+
root to: 'editors#index'
|
|
11
|
+
|
|
12
|
+
get 'ping', to: 'editors#ping'
|
|
13
|
+
get 'workspace', to: 'editors#workspace'
|
|
14
|
+
get 'files', to: 'editors#files'
|
|
15
|
+
get 'file', to: 'editors#show'
|
|
16
|
+
get 'raw', to: 'editors#raw'
|
|
17
|
+
post 'file', to: 'editors#save'
|
|
18
|
+
post 'create_file', to: 'editors#create_file'
|
|
19
|
+
post 'create_dir', to: 'editors#create_dir'
|
|
20
|
+
patch 'rename', to: 'editors#rename'
|
|
21
|
+
delete 'delete', to: 'editors#destroy_path'
|
|
22
|
+
get 'state', to: 'editors#state'
|
|
23
|
+
post 'state', to: 'editors#save_state'
|
|
24
|
+
get 'branch_state', to: 'editors#branch_state'
|
|
25
|
+
post 'branch_state', to: 'editors#save_branch_state'
|
|
26
|
+
post 'prune_branch_states', to: 'editors#prune_branch_states'
|
|
27
|
+
get 'file_history', to: 'editors#file_history'
|
|
28
|
+
post 'file_history', to: 'editors#save_file_history'
|
|
29
|
+
get 'search', to: 'editors#search'
|
|
30
|
+
post 'replace_in_files', to: 'editors#replace_in_files'
|
|
31
|
+
get 'definition', to: 'editors#definition'
|
|
32
|
+
get 'js_definition', to: 'editors#js_definition'
|
|
33
|
+
get 'js_members', to: 'editors#js_members'
|
|
34
|
+
get 'module_members', to: 'editors#module_members'
|
|
35
|
+
get 'file_includes', to: 'editors#file_includes'
|
|
36
|
+
get 'client_config', to: 'editors#client_config'
|
|
37
|
+
get 'related_files', to: 'editors#related_files'
|
|
38
|
+
get 'model_schema', to: 'editors#model_schema'
|
|
39
|
+
get 'changelog', to: 'editors#changelog'
|
|
40
|
+
get 'git_info', to: 'editors#git_info'
|
|
41
|
+
get 'git_status', to: 'editors#git_status'
|
|
42
|
+
get 'manifest.webmanifest', to: 'editors#pwa_manifest', format: false
|
|
43
|
+
get 'sw.js', to: 'editors#pwa_sw', format: false
|
|
44
|
+
get 'mbeditor-icon.svg', to: 'editors#pwa_icon', format: false
|
|
45
|
+
get 'monaco_worker.js', to: 'editors#monaco_worker', format: false
|
|
46
|
+
get 'ts_worker.js', to: 'editors#ts_worker', format: false
|
|
47
|
+
get 'monaco-editor/*asset_path', to: 'editors#monaco_asset', format: false
|
|
48
|
+
get 'min-maps/*asset_path', to: 'editors#monaco_asset', format: false
|
|
49
|
+
post 'lint', to: 'editors#lint'
|
|
50
|
+
post 'quick_fix', to: 'editors#quick_fix'
|
|
51
|
+
post 'format', to: 'editors#format_file'
|
|
52
|
+
post 'test', to: 'editors#run_test'
|
|
53
|
+
|
|
54
|
+
# ── Git & Code Review ──────────────────────────────────────────────────────
|
|
55
|
+
get 'git/diff', to: 'git#diff'
|
|
56
|
+
get 'git/blame', to: 'git#blame'
|
|
57
|
+
get 'git/file_history', to: 'git#file_history'
|
|
58
|
+
get 'git/commit_graph', to: 'git#commit_graph'
|
|
59
|
+
get 'git/commit_detail', to: 'git#commit_detail'
|
|
60
|
+
get 'git/combined_diff', to: 'git#combined_diff'
|
|
61
|
+
|
|
62
|
+
# Redmine integration (enabled via config.mbeditor.redmine_enabled)
|
|
63
|
+
get 'redmine/issue/:id', to: 'git#redmine_issue', as: :redmine_issue
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/mbeditor/version.rb
CHANGED
data/lib/mbeditor.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mbeditor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oliver Noonan
|
|
@@ -121,8 +121,12 @@ files:
|
|
|
121
121
|
- lib/mbeditor/cable_log_filter.rb
|
|
122
122
|
- lib/mbeditor/configuration.rb
|
|
123
123
|
- lib/mbeditor/engine.rb
|
|
124
|
+
- lib/mbeditor/mount_path.rb
|
|
125
|
+
- lib/mbeditor/private_routes.rb
|
|
124
126
|
- lib/mbeditor/rack/handle_pending_migrations.rb
|
|
127
|
+
- lib/mbeditor/rack/resilient_router.rb
|
|
125
128
|
- lib/mbeditor/rack/silence_ping_request.rb
|
|
129
|
+
- lib/mbeditor/route_map.rb
|
|
126
130
|
- lib/mbeditor/version.rb
|
|
127
131
|
- mbeditor.gemspec
|
|
128
132
|
- public/mbeditor-icon.svg
|