mbeditor 0.12.0 → 0.12.1
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 +65 -3
- data/README.md +38 -1
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +6 -1
- data/app/assets/javascripts/mbeditor/components/ModelGraph.js +590 -221
- data/app/assets/stylesheets/mbeditor/editor.css +94 -2
- data/app/controllers/mbeditor/editors_controller.rb +31 -4
- data/lib/mbeditor/configuration.rb +6 -2
- data/lib/mbeditor/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6645751ebceaf2b9754d5aabb417549334518db35027e1bd6c08d9fede2d7a5
|
|
4
|
+
data.tar.gz: edb2a8a2696f5aac16fcdcd4bbbf728f5d05a7af14ffca326a59ec7c0d40b860
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f9d7559b69d80a1d8d9d094d5513a69048ce62ea385630ca59811e0dafd50ca65afa988e1f560cc32d78fc7b71dceedb78b30f1ba190e00b465d1026e3554d5
|
|
7
|
+
data.tar.gz: a8a3de31439ff3a937db30a04dbfd631694f50ccbcce4c3fb3571dfa66cd798cf8df29b45855467a9ff783a919893829472b241523d7230468944a3accad04f9
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,68 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.12.1] - 2026-08-03
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **The collaboration name now comes from the signed-in user automatically.**
|
|
14
|
+
Previously it required a `user_name_callback`; with none set the editor fell
|
|
15
|
+
straight through to a generated name like "Witty Operator" even on an
|
|
16
|
+
authenticated instance. When no callback is configured, the name is now read
|
|
17
|
+
off `current_user`, trying `name`, `full_name`, `display_name`, `username`,
|
|
18
|
+
`login` and `email` in order. New `config.user_name_methods` names your own
|
|
19
|
+
column instead — `%w[preferred_name]` — so the common case no longer needs a
|
|
20
|
+
callback at all. An explicit `user_name_callback` still wins.
|
|
21
|
+
|
|
22
|
+
This works when your auth library exposes `current_user` to an
|
|
23
|
+
`ActionController::Base` subclass, which Devise and Sorcery do. A
|
|
24
|
+
`current_user` written by hand on your own `ApplicationController` is **not**
|
|
25
|
+
reachable — the engine's controllers do not inherit from it — so that case
|
|
26
|
+
still needs a callback reading `session` directly.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **The model graph is laid out by dependency, not by traversal order.** It now
|
|
30
|
+
uses the Sugiyama layered method — break cycles, layer by longest path, cut
|
|
31
|
+
crossings with the median heuristic, then straighten — which is what Graphviz
|
|
32
|
+
`dot`, and so Rails ERD, uses for this picture. The previous radial layout
|
|
33
|
+
became one enormous circle on a real schema, fitted so far out that no box was
|
|
34
|
+
legible. A model's position now tells you something: depth reads left to
|
|
35
|
+
right, and each connected part of the schema is drawn as its own area.
|
|
36
|
+
|
|
37
|
+
- **Your own presence chip only appears once someone else is connected.** Action
|
|
38
|
+
Cable is up in any normal dev setup, so it used to sit in the toolbar
|
|
39
|
+
permanently announcing a session of one.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- **The model graph was unusable on a large schema.** On 300 models and 513
|
|
43
|
+
associations a single zoom tick cost 27 ms; it is now 0.2 ms. Three causes,
|
|
44
|
+
all compounding: the entire layout ran on every render, the pan/zoom transform
|
|
45
|
+
sat in the render output so each tick rebuilt ~7,000 SVG elements, and the
|
|
46
|
+
wheel handler read `getBoundingClientRect()` per tick, forcing a synchronous
|
|
47
|
+
reflow of the whole scene.
|
|
48
|
+
- **Fit-to-pane produced a zoom the controls refused to honour.** It clamped to
|
|
49
|
+
`min(1, ...)` but not to the minimum zoom, so a large graph fitted at ~0.04
|
|
50
|
+
against a 0.2 floor — and the first scroll snapped up to the floor, a fivefold
|
|
51
|
+
jump anchored on the cursor that looked like the diagram leaping somewhere
|
|
52
|
+
random. The floor is now low enough to frame a few hundred models, and the fit
|
|
53
|
+
clamps to the same range the wheel enforces. Opening the tab also no longer
|
|
54
|
+
leaves the graph unfitted when the pane has not been sized yet.
|
|
55
|
+
- **Hovering a model now shows what its associations actually are** — macro,
|
|
56
|
+
name, direction and `through:` — and dims every unrelated edge, which is the
|
|
57
|
+
only way to follow one model's relationships among hundreds of lines.
|
|
58
|
+
- **Clicking a model zooms to it** instead of opening its schema; the schema is
|
|
59
|
+
an explicit button in the model's header, so navigating no longer throws a
|
|
60
|
+
modal at you.
|
|
61
|
+
- **The model-graph search field drew its text over a magnifier icon.** The icon
|
|
62
|
+
comes from the vendored Pico stylesheet, whose selector outranks a plain class
|
|
63
|
+
rule — disabling the browser's own `type="search"` decorations did not touch
|
|
64
|
+
it.
|
|
65
|
+
- **A failing `user_name_callback` was swallowed silently.** Any exception
|
|
66
|
+
returned a bare `nil`, which made a broken callback indistinguishable from an
|
|
67
|
+
unconfigured one: you got the generated name and no clue why. The usual cause
|
|
68
|
+
is a `NameError` on a `current_user` the engine cannot see. It is now logged
|
|
69
|
+
as `[mbeditor] user name lookup failed: ...` and still never breaks the
|
|
70
|
+
request.
|
|
71
|
+
|
|
10
72
|
## [0.12.0] - 2026-07-31
|
|
11
73
|
|
|
12
74
|
### Added
|
|
@@ -50,9 +112,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
50
112
|
|
|
51
113
|
- **A model graph — an entity diagram of the host app's ActiveRecord models.**
|
|
52
114
|
The activity-bar button opens it as a full-width editor tab, drawing each
|
|
53
|
-
model with its fields
|
|
54
|
-
the
|
|
55
|
-
|
|
115
|
+
model with its fields. Search centres the view on a model; hovering an edge
|
|
116
|
+
names the relation. (Released with a radial layout; replaced by a layered one
|
|
117
|
+
in the next version — see Unreleased.)
|
|
56
118
|
|
|
57
119
|
Associations are read by **reflection, not by parsing model files**. mbeditor
|
|
58
120
|
runs inside the host app, so `reflect_on_all_associations` is right there and
|
data/README.md
CHANGED
|
@@ -162,7 +162,8 @@ See [Resilient Routing](#resilient-routing) for details.
|
|
|
162
162
|
|
|
163
163
|
| Option | Default | Description |
|
|
164
164
|
|--------|---------|-------------|
|
|
165
|
-
| `user_name_callback` | `nil` | Proc resolving the display name shown on your caret during realtime collaboration. Executed via `instance_exec` inside the controller (like `authenticate_with`), so it can read `session`, `cookies`, `
|
|
165
|
+
| `user_name_callback` | `nil` | Proc resolving the display name shown on your caret during realtime collaboration. Only needed when the automatic lookup can't reach your user — see `user_name_methods` below. Executed via `instance_exec` inside the engine's controller (like `authenticate_with`), so it can read `session`, `cookies`, `params`, and anything your auth library exposes to an `ActionController::Base` subclass — e.g. `proc { User.find_by(id: session[:user_id])&.name }`. **It cannot see helper methods defined on your own `ApplicationController`**, because the engine's controllers do not inherit from it; a hand-rolled `current_user` living there will raise `NameError`, which is logged as `[mbeditor] user name lookup failed` and falls back to the generated name. |
|
|
166
|
+
| `user_name_methods` | `%w[name full_name display_name username login email]` | Attributes tried on `current_user`, in order, when no `user_name_callback` is set — the first non-blank one becomes your collaboration display name. This is what makes an authenticated editor show real names with no extra wiring, provided your auth library exposes `current_user` to `ActionController::Base` (Devise and Sorcery do; a `current_user` you wrote yourself on `ApplicationController` does not). Set it to your own column instead of writing a callback, e.g. `%w[preferred_name]`. |
|
|
166
167
|
|
|
167
168
|
## JavaScript intelligence
|
|
168
169
|
|
|
@@ -376,6 +377,42 @@ common cause of *"the other person's edits never show up."* For pairing, run a s
|
|
|
376
377
|
worker (`WEB_CONCURRENCY=0`, or `bundle exec rails server` which is single-process by
|
|
377
378
|
default). A multi-worker setup would additionally need a cross-process cable adapter, but
|
|
378
379
|
the in-memory buffer still would not be shared — single-process is the supported mode.
|
|
380
|
+
|
|
381
|
+
#### Showing real usernames
|
|
382
|
+
|
|
383
|
+
Each participant's caret and presence chip are labelled. With no configuration
|
|
384
|
+
the label is a generated name like *Witty Operator*, persisted per browser and
|
|
385
|
+
editable by clicking your own chip.
|
|
386
|
+
|
|
387
|
+
**If your auth library exposes `current_user` to controllers** — Devise and
|
|
388
|
+
Sorcery both do, because they include their helpers into `ActionController::Base`
|
|
389
|
+
— it already works with no configuration at all. mbeditor reads the first
|
|
390
|
+
non-blank of `name`, `full_name`, `display_name`, `username`, `login`, `email`.
|
|
391
|
+
|
|
392
|
+
To point it at a different column:
|
|
393
|
+
|
|
394
|
+
```ruby
|
|
395
|
+
Mbeditor.configure do |c|
|
|
396
|
+
c.user_name_methods = %w[preferred_name email]
|
|
397
|
+
end
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**If `current_user` is your own method on `ApplicationController`**, mbeditor
|
|
401
|
+
cannot see it — the engine's controllers inherit from `ActionController::Base`,
|
|
402
|
+
not from your `ApplicationController`. Resolve the user yourself instead; the
|
|
403
|
+
proc runs in the engine's controller, so `session`, `cookies` and `params` are
|
|
404
|
+
all available:
|
|
405
|
+
|
|
406
|
+
```ruby
|
|
407
|
+
Mbeditor.configure do |c|
|
|
408
|
+
c.user_name_callback = proc { User.find_by(id: session[:user_id])&.name }
|
|
409
|
+
end
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
An explicit `user_name_callback` always wins over the automatic lookup. If it
|
|
413
|
+
raises or returns blank you get the generated name, and the reason is logged as
|
|
414
|
+
`[mbeditor] user name lookup failed: …` rather than silently swallowed.
|
|
415
|
+
|
|
379
416
|
## Search performance
|
|
380
417
|
|
|
381
418
|
Project search and JS definition lookups pick a backend per call:
|
|
@@ -4217,7 +4217,12 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
4217
4217
|
!toolbarIconOnly && " Git"
|
|
4218
4218
|
)
|
|
4219
4219
|
),
|
|
4220
|
-
|
|
4220
|
+
// Your own chip appears only once someone else is actually connected.
|
|
4221
|
+
// Alone it told you nothing — Action Cable is up in any normal dev setup,
|
|
4222
|
+
// so it sat in the toolbar permanently announcing a session of one. While
|
|
4223
|
+
// pairing it earns its place: it is how your peers see you, and it is the
|
|
4224
|
+
// control for renaming yourself.
|
|
4225
|
+
collabEnabled && collabIdentity && collabPeerIds.length > 0 && React.createElement(
|
|
4221
4226
|
React.Fragment,
|
|
4222
4227
|
null,
|
|
4223
4228
|
React.createElement("div", { className: "statusbar-sep" }),
|