@happyvertical/smrt-svelte 0.57.15 → 0.57.17

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.
@@ -503,6 +503,9 @@ overview id — so the layout persists **per model kind**, not per record.
503
503
  `RecordScreen` renders it with `presentation="plain"` and extends the widget
504
504
  context with `record`.
505
505
 
506
+ Empty surfaces show authoring guidance only while editing. Read mode remains quiet;
507
+ customization controls and capability checks are unchanged.
508
+
506
509
  ## Host section presentation
507
510
 
508
511
  `OverviewGrid` defaults to framed cards. Pass `presentation="plain"` for
@@ -401,7 +401,7 @@ const headingTag = $derived(`h${headingLevel}`);
401
401
  </div>
402
402
  {/if}
403
403
 
404
- {#if rows.length === 0}
404
+ {#if editing && rows.length === 0}
405
405
  <p class="smrt-overview__empty">{t(M['ui.overview.empty'])}</p>
406
406
  {/if}
407
407
  <div
@@ -43,6 +43,11 @@ export interface SmrtManifestEntryLike {
43
43
  collection?: string;
44
44
  /** Base class name as written in source. */
45
45
  extends?: string;
46
+ /**
47
+ * Base class qualified from its import (`@package/name:ClassName`), when
48
+ * the scanner could resolve it. Wins over `extends` (#4176).
49
+ */
50
+ extendsQualified?: string;
46
51
  /**
47
52
  * Top-level visibility flag — `SmartObjectDefinition` hoists this out of
48
53
  * `decoratorConfig` so it can be read without parsing the raw config. The
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workspace/manifest-nav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;AAEzD,mEAAmE;AACnE,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAChB,EAAE,CAAC,EAAE;YACH,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;QACF;;;;;WAKG;QACH,GAAG,CAAC,EACA,OAAO,GACP;YAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC;QACvE;;;WAGG;QACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;QAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAChD;AAWD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC;AAEjC,uDAAuD;AACvD,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAWD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAevD;AAqPD,iFAAiF;AACjF,MAAM,WAAW,sBAAsB,CACrC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB;IAEvD,KAAK,EAAE,CAAC,CAAC;IACT,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,SAAS,EAAE,OAAO,CAAC;CACpB;AAgBD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,qBAAqB,EACtE,QAAQ,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;CAAE,EACxC,OAAO,GAAE;IAAE,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GACvD,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAc7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,0BAA+B,GACvC,UAAU,EAAE,CA4Dd"}
1
+ {"version":3,"file":"manifest-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workspace/manifest-nav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;AAEzD,mEAAmE;AACnE,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAChB,EAAE,CAAC,EAAE;YACH,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;QACF;;;;;WAKG;QACH,GAAG,CAAC,EACA,OAAO,GACP;YAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC;QACvE;;;WAGG;QACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;QAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAChD;AAWD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC;AAEjC,uDAAuD;AACvD,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAWD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAevD;AAsQD,iFAAiF;AACjF,MAAM,WAAW,sBAAsB,CACrC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB;IAEvD,KAAK,EAAE,CAAC,CAAC;IACT,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,SAAS,EAAE,OAAO,CAAC;CACpB;AAgBD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,qBAAqB,EACtE,QAAQ,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;CAAE,EACxC,OAAO,GAAE;IAAE,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GACvD,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAc7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,0BAA+B,GACvC,UAAU,EAAE,CA4Dd"}
@@ -124,29 +124,25 @@ function isPublicEntry(entry) {
124
124
  * ancestor in the manifest) stay visible — better to show one link
125
125
  * than none.
126
126
  *
127
- * Detection: starting at `entry.extends`, look up that className in
128
- * the manifest. If found and `collection` matches, suppress this
129
- * entry. Otherwise recurse into THAT entry's `extends` and try again.
127
+ * Detection: starting at the entry's parent (`extendsQualified`, else
128
+ * `extends` by className), look it up in the manifest. If found and `collection` matches, suppress this
129
+ * entry. Otherwise recurse into THAT entry's parent and try again.
130
130
  * Stop at `SmrtObject`/`SmrtClass`, when no manifest entry resolves,
131
131
  * or when a cycle is detected.
132
132
  */
133
133
  function looksLikeStiSubtypeOfParentRoute(entry, manifest) {
134
- const byClassName = entryIndexByClassName(manifest);
135
- const visited = new Set();
136
- let cursor = entry.extends;
137
- while (cursor && cursor !== 'SmrtObject' && cursor !== 'SmrtClass') {
138
- if (visited.has(cursor))
134
+ const visited = new Set([entry]);
135
+ let ancestor = parentEntry(entry, manifest);
136
+ while (ancestor) {
137
+ if (visited.has(ancestor))
139
138
  return false; // pathological cycle
140
- visited.add(cursor);
141
- const ancestor = byClassName.get(cursor);
142
- if (!ancestor)
143
- return false; // chain broken, keep this entry visible
139
+ visited.add(ancestor);
144
140
  if (ancestor.collection && ancestor.collection === entry.collection) {
145
141
  return true;
146
142
  }
147
- cursor = ancestor.extends;
143
+ ancestor = parentEntry(ancestor, manifest);
148
144
  }
149
- return false;
145
+ return false; // chain broken or ended, keep this entry visible
150
146
  }
151
147
  /**
152
148
  * Build a className → entry lookup over the manifest. Memoised per
@@ -170,6 +166,23 @@ function entryIndexByClassName(manifest) {
170
166
  manifestClassNameIndex.set(manifest, idx);
171
167
  return idx;
172
168
  }
169
+ /**
170
+ * The manifest entry `entry` extends, or `undefined` at a framework base or
171
+ * a broken chain. An import-qualified parent resolves to that package's
172
+ * entry only, never a same-named class of another package (#4176).
173
+ */
174
+ function parentEntry(entry, manifest) {
175
+ const qualified = entry.extendsQualified;
176
+ if (qualified) {
177
+ return (manifest.objects[qualified] ??
178
+ Object.values(manifest.objects).find((candidate) => entryQualifier(candidate) === qualified));
179
+ }
180
+ const parent = entry.extends;
181
+ if (!parent || parent === 'SmrtObject' || parent === 'SmrtClass') {
182
+ return undefined;
183
+ }
184
+ return entryIndexByClassName(manifest).get(parent);
185
+ }
173
186
  /**
174
187
  * Whether an entry exposes a `list` route through the REST generator.
175
188
  *
@@ -253,12 +266,10 @@ function entryQualifier(entry) {
253
266
  * threads through the inheritance chain (handles multi-level STI)
254
267
  * with a visited-set cycle guard.
255
268
  *
256
- * Pure: returns a new Set; never mutates the caller's set. The
257
- * className index is the same memoised one used by
258
- * `looksLikeStiSubtypeOfParentRoute`.
269
+ * Pure: returns a new Set; never mutates the caller's set. Ancestors
270
+ * resolve through `parentEntry`, as in `looksLikeStiSubtypeOfParentRoute`.
259
271
  */
260
272
  function expandPermittedThroughStiParents(permitted, manifest) {
261
- const byClassName = entryIndexByClassName(manifest);
262
273
  // Also need to resolve qualifier → entry, because permitted set
263
274
  // entries are qualified names (`@pkg/x:Class`), not raw classNames.
264
275
  const byQualifier = new Map();
@@ -270,21 +281,16 @@ function expandPermittedThroughStiParents(permitted, manifest) {
270
281
  const entry = byQualifier.get(qualifier);
271
282
  if (!entry)
272
283
  continue;
273
- const visited = new Set();
274
- let cursor = entry.extends;
284
+ const visited = new Set([entry]);
285
+ let ancestor = parentEntry(entry, manifest);
275
286
  let lastSeenCollection = entry.collection;
276
- while (cursor && cursor !== 'SmrtObject' && cursor !== 'SmrtClass') {
277
- if (visited.has(cursor))
278
- break;
279
- visited.add(cursor);
280
- const ancestor = byClassName.get(cursor);
281
- if (!ancestor)
282
- break;
287
+ while (ancestor && !visited.has(ancestor)) {
288
+ visited.add(ancestor);
283
289
  if (ancestor.collection && ancestor.collection === lastSeenCollection) {
284
290
  expanded.add(entryQualifier(ancestor));
285
291
  }
286
292
  lastSeenCollection = ancestor.collection ?? lastSeenCollection;
287
- cursor = ancestor.extends;
293
+ ancestor = parentEntry(ancestor, manifest);
288
294
  }
289
295
  }
290
296
  return expanded;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-svelte",
3
- "version": "0.57.15",
3
+ "version": "0.57.17",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Svelte 5 components for SMRT user management - auth, users, tenants, roles, permissions, groups",
6
6
  "type": "module",
@@ -210,11 +210,11 @@
210
210
  },
211
211
  "dependencies": {
212
212
  "@happyvertical/logger": "^0.105.5",
213
- "@happyvertical/smrt-languages": "0.57.15",
214
- "@happyvertical/smrt-mcp-apps": "0.57.15",
215
- "@happyvertical/smrt-types": "0.57.15",
216
- "@happyvertical/smrt-ui": "0.57.15",
217
- "@happyvertical/smrt-web": "0.57.15",
213
+ "@happyvertical/smrt-languages": "0.57.17",
214
+ "@happyvertical/smrt-mcp-apps": "0.57.17",
215
+ "@happyvertical/smrt-types": "0.57.17",
216
+ "@happyvertical/smrt-ui": "0.57.17",
217
+ "@happyvertical/smrt-web": "0.57.17",
218
218
  "@tanstack/db": "^0.6.14",
219
219
  "@tanstack/svelte-db": "^0.1.91",
220
220
  "esm-env": "^1.2.2"
@@ -249,14 +249,14 @@
249
249
  }
250
250
  },
251
251
  "devDependencies": {
252
- "@happyvertical/smrt-agents": "0.57.15",
253
- "@happyvertical/smrt-chat": "0.57.15",
254
- "@happyvertical/smrt-content": "0.57.15",
255
- "@happyvertical/smrt-core": "0.57.15",
256
- "@happyvertical/smrt-reports": "0.57.15",
257
- "@happyvertical/smrt-scanner": "0.57.15",
258
- "@happyvertical/smrt-tenancy": "0.57.15",
259
- "@happyvertical/smrt-users": "0.57.15",
252
+ "@happyvertical/smrt-agents": "0.57.17",
253
+ "@happyvertical/smrt-chat": "0.57.17",
254
+ "@happyvertical/smrt-content": "0.57.17",
255
+ "@happyvertical/smrt-core": "0.57.17",
256
+ "@happyvertical/smrt-reports": "0.57.17",
257
+ "@happyvertical/smrt-scanner": "0.57.17",
258
+ "@happyvertical/smrt-tenancy": "0.57.17",
259
+ "@happyvertical/smrt-users": "0.57.17",
260
260
  "@happyvertical/speech": "^0.105.5",
261
261
  "@sveltejs/package": "^2.5.8",
262
262
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
@@ -268,7 +268,7 @@
268
268
  "svelte": "^5.57.1",
269
269
  "svelte-check": "^4.7.6",
270
270
  "typescript": "6.0.3",
271
- "vite": "8.1.4",
271
+ "vite": "8.1.6",
272
272
  "vitest": "4.1.10"
273
273
  },
274
274
  "scripts": {