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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8e586fb734529e92147e9fb6935782e79baeb9722c833e8df0a97cc2c86c637
4
- data.tar.gz: 5da9242367bd195c715af433c8fb12fa440a610cacb5a1ff871cb8361c82233a
3
+ metadata.gz: b6645751ebceaf2b9754d5aabb417549334518db35027e1bd6c08d9fede2d7a5
4
+ data.tar.gz: edb2a8a2696f5aac16fcdcd4bbbf728f5d05a7af14ffca326a59ec7c0d40b860
5
5
  SHA512:
6
- metadata.gz: f403b63083bc139fc6546477c42fb476283213f0409a287ec3ffe46cc1a90cb10f197d6521216efce8121d910fdb8b2c94eefd8cd0abd8829725c852f043e57a
7
- data.tar.gz: 219a64ac7ecf5e2ded2081058f64f0bb4b0ce8373eac4f3cdcd8f9ca87aacd887676e680c31f360848dbcc255cfcdd176eaf67389569c64143639bf2643538f6
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 and laying them out radially around whichever model has
54
- the most associations. Search centres the view on a model; hovering an edge
55
- names the relation.
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`, `current_user`, etc. — e.g. `proc { current_user&.name }`. When `nil` or it returns a blank value, each browser falls back to a generated, locally-persisted, user-editable name. Collaboration activates once another participant actually connects, not merely when Action Cable is up (see [Collaborative pairing](#collaborative-pairing-optional)). |
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
- collabEnabled && collabIdentity && React.createElement(
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" }),