@zambon-dev/shared 2.0.0 → 2.1.0
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.
- package/CHANGELOG.md +111 -1
- package/fesm2022/zambon-dev-shared.mjs +475 -10
- package/fesm2022/zambon-dev-shared.mjs.map +1 -1
- package/i18n/external-content/en.json +10 -0
- package/i18n/external-content/pt.json +10 -0
- package/index.d.ts +1 -0
- package/lib/features/external-content/external-content.component.d.ts +43 -0
- package/lib/features/external-content/external-content.routes.d.ts +25 -0
- package/lib/features/external-content/index.d.ts +2 -0
- package/lib/layouts/main-layout/main-layout.component.d.ts +3 -0
- package/lib/models/current-user-info.d.ts +15 -0
- package/lib/models/external-content.d.ts +28 -0
- package/lib/models/index.d.ts +1 -0
- package/lib/services/external-content.service.d.ts +35 -0
- package/lib/services/external-url-resolver.service.d.ts +49 -0
- package/lib/services/index.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,115 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
23
23
|
|
|
24
24
|
### ⚠ Breaking Changes / Migration
|
|
25
25
|
|
|
26
|
+
## [2.1.0] - 2026-09-08
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **External sidebar destinations are now opened, in either of two modes.** `MainLayoutComponent`
|
|
31
|
+
subscribes to `@zambon-dev/library`’s new `SidebarService.menuExternalUrlSelected`: an item whose
|
|
32
|
+
`openMode` is `ExternalNewTab` opens in a new browser tab (`noopener,noreferrer`), and one marked
|
|
33
|
+
`ExternalEmbedded` opens an application tab that displays the destination in a sandboxed iframe,
|
|
34
|
+
keeping the user inside the application. Internal routes are untouched.
|
|
35
|
+
|
|
36
|
+
- **`ExternalUrlResolverService`** — substitutes the runtime placeholders in an external menu URL
|
|
37
|
+
and vets the result. The placeholder set is closed and case-sensitive: `{email}`, `{language}`,
|
|
38
|
+
`{userId}`, `{userName}`. Every substituted value is `encodeURIComponent`-ed, so a name containing
|
|
39
|
+
`&` cannot inject a query parameter — which also means one placeholder must occupy one whole path
|
|
40
|
+
segment or query-parameter value. A supported placeholder with no value becomes an empty string
|
|
41
|
+
(with a console warning); an unrecognized `{…}` is left exactly as configured, so a report URL
|
|
42
|
+
that legitimately contains braces, such as `?filter={"a":1}`, is not corrupted.
|
|
43
|
+
|
|
44
|
+
No authentication token is ever substituted, and the set is closed by construction rather than
|
|
45
|
+
reflected off the stored user info — `AuthenticationService` persists the whole sign-in response
|
|
46
|
+
under `userInfo`, tokens included, so a reflective implementation would let a URL configured as
|
|
47
|
+
`?t={token}` hand the JWT to a third party.
|
|
48
|
+
|
|
49
|
+
`{language}` and `{userName}` work today. `{userId}` and `{email}` resolve to an empty string
|
|
50
|
+
until your `Authentication/SignIn` and `Authentication/RefreshToken` responses include `userID`
|
|
51
|
+
and `email` (see `ICurrentUserInfo` below).
|
|
52
|
+
|
|
53
|
+
- **`ExternalContentComponent` + `externalContentRoutes`** — the embedded view. Spread the routes
|
|
54
|
+
into `MainLayoutComponent`’s children:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
{ path: '', component: MainLayoutComponent, canActivate: [AuthGuard], children: [
|
|
58
|
+
...externalContentRoutes,
|
|
59
|
+
// your own features
|
|
60
|
+
] }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Register them even if you only plan to use `ExternalNewTab`: an embedded item configured without
|
|
64
|
+
them opens a tab that immediately bounces to the home route.
|
|
65
|
+
|
|
66
|
+
The view is an ordinary `TabViewBase` hosted by `DefaultTabViewComponent`, so its actions appear
|
|
67
|
+
in the application ribbon (a **Page** group with **Refresh** and **Open in a new browser tab**)
|
|
68
|
+
and look like every other screen’s — the shipped `externalContentRoutes` already wires that host
|
|
69
|
+
up, which is the other reason not to hand-write the routes. **Refresh** carries the same icon and
|
|
70
|
+
label as `framework-button-refresh`, because reloading a report is the same action as refreshing
|
|
71
|
+
a grid.
|
|
72
|
+
|
|
73
|
+
Refreshing genuinely tears the frame down and builds a new one — a cross-origin frame cannot be
|
|
74
|
+
navigated any other way — so the old render visibly goes away instead of sitting there while you
|
|
75
|
+
wonder whether anything happened. The button spins and the panel shows a loading overlay until
|
|
76
|
+
the destination reports `load`, or until the slow-frame delay elapses, so a destination that
|
|
77
|
+
never reports one cannot leave the controls stuck.
|
|
78
|
+
|
|
79
|
+
**Open in a new browser tab** is always available, because many sites refuse to be embedded
|
|
80
|
+
(`X-Frame-Options`, CSP `frame-ancestors`) and a browser gives JavaScript no reliable way to
|
|
81
|
+
detect that — if nothing has loaded after a few seconds the view also shows a hint saying so. An
|
|
82
|
+
`https` application cannot embed an `http` destination at all; the same button is the way out.
|
|
83
|
+
|
|
84
|
+
The tab URL is `/external-content/<menu id>` and never carries the destination, so no one can
|
|
85
|
+
hand-craft a link that makes your application frame an arbitrary site. Pressing F5 on an embedded
|
|
86
|
+
tab restores both the frame and the tab title from `sessionStorage`. Opening that URL in a *fresh*
|
|
87
|
+
browser tab can only work if your `SidebarService.getMenuFromUrl()` resolves
|
|
88
|
+
`/external-content/<id>`; otherwise the view says the content is unavailable and asks the user to
|
|
89
|
+
reopen it from the menu.
|
|
90
|
+
|
|
91
|
+
- **`EXTERNAL_CONTENT_CONFIGS`** — `allowedOrigins` (default `[]`, meaning any `http`/`https`
|
|
92
|
+
origin) and `slowFrameHintDelay` (default 5000 ms). **Populate `allowedOrigins` in production.**
|
|
93
|
+
Embedded and new-tab destinations are already rejected unless they are absolute `http`/`https`
|
|
94
|
+
URLs, which stops a `javascript:` or `data:` URL in your menu table from executing in your users’
|
|
95
|
+
session; an origin allowlist narrows what is left from “any site on the internet” to your known
|
|
96
|
+
report hosts. The iframe is sandboxed with a fixed, non-configurable token list that withholds
|
|
97
|
+
`allow-top-navigation`, so a framed site cannot navigate your application away. Do not point an
|
|
98
|
+
embedded item at your own application’s origin — use an internal route for that.
|
|
99
|
+
|
|
100
|
+
- **`ICurrentUserInfo.email`, `.userID`, `.username`** (all optional) — the values behind
|
|
101
|
+
`{email}`, `{userId}` and `{userName}`. `username` was already being persisted in the base64
|
|
102
|
+
`userInfo` entry and is now simply typed, so `{userName}` needs no backend change; `email` and
|
|
103
|
+
`userID` must be added to your sign-in and refresh responses.
|
|
104
|
+
|
|
105
|
+
- **Translations** for the embedded view under `i18n/external-content/`, already included in
|
|
106
|
+
`ZAMBON_SHARED_I18N_RESOURCES`.
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- **A deep link whose URL the menu API cannot resolve no longer surfaces an unhandled error.**
|
|
111
|
+
`MainLayoutComponent` resolves a deep-linked tab’s title through `SidebarService.getMenuFromUrl()`
|
|
112
|
+
and had no error handler, so a 404 became an unhandled rejection in the console. The title is
|
|
113
|
+
best-effort and the failure is now swallowed — which matters more now that the embedded-content
|
|
114
|
+
route is a URL shape most menu endpoints do not know.
|
|
115
|
+
|
|
116
|
+
### ⚠ Breaking Changes / Migration
|
|
117
|
+
|
|
118
|
+
- **Requires `@zambon-dev/library` 1.4.0 or later.** `SidebarMenuOpenMode`,
|
|
119
|
+
`toSidebarMenuOpenMode` and `SidebarService.menuExternalUrlSelected` ship in that release. The
|
|
120
|
+
declared peer range still allows older versions, so upgrade both packages together.
|
|
121
|
+
- **To use external menu items, register `externalContentRoutes`** as children of
|
|
122
|
+
`MainLayoutComponent` (snippet above), and make your menu endpoint return `openMode`. The
|
|
123
|
+
resolver accepts it as the camelCase string (`"internal"`, `"externalNewTab"`,
|
|
124
|
+
`"externalEmbedded"`, matched case-insensitively) or as the enum ordinal (`0`, `1`, `2`), so a
|
|
125
|
+
plain ASP.NET Core enum property works with no converter.
|
|
126
|
+
- **The embedded view needs both i18n bundles registered.** Its own strings ship in this package
|
|
127
|
+
(`ZAMBON_SHARED_I18N_RESOURCES`, under `assets/i18n/zambon-dev/shared/external-content/`), but the
|
|
128
|
+
ribbon reuses three keys owned by `@zambon-dev/framework` — `RibbonGroup-Page`, `Button-Refresh`
|
|
129
|
+
and `Loading` — so `ZAMBON_FRAMEWORK_I18N_RESOURCES` has to be registered too, or those render as
|
|
130
|
+
raw keys. Any application that already uses framework buttons registers it; if your
|
|
131
|
+
`TranslateLoader` hand-lists prefixes instead of spreading the two constants, add both.
|
|
132
|
+
- Nothing else changes: applications with no `openMode` on any menu item behave exactly as before
|
|
133
|
+
and need no action.
|
|
134
|
+
|
|
26
135
|
## [2.0.0] - 2026-07-30
|
|
27
136
|
|
|
28
137
|
### Added
|
|
@@ -191,7 +300,8 @@ URL) in `AppConfig`, and implement a hub that pushes the notification list to cl
|
|
|
191
300
|
available via [GitHub Releases](https://github.com/RicardoZambon/ZLibraries/releases) and the
|
|
192
301
|
`shared-v*` tags.
|
|
193
302
|
|
|
194
|
-
[Unreleased]: https://github.com/RicardoZambon/ZLibraries/compare/shared-v2.
|
|
303
|
+
[Unreleased]: https://github.com/RicardoZambon/ZLibraries/compare/shared-v2.1.0...HEAD
|
|
304
|
+
[2.1.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/shared-v2.1.0
|
|
195
305
|
[2.0.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/shared-v2.0.0
|
|
196
306
|
[1.2.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/shared-v1.2.0
|
|
197
307
|
[1.1.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/shared-v1.1.0
|