oip-common 0.6.4 → 0.7.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/README.md CHANGED
@@ -1,68 +1,189 @@
1
- # OipCommon
2
-
3
- Add assets in angular.json
4
-
5
- ```json
6
- {
7
- "glob": "**/*",
8
- "input": "node_modules/oip-common/assets",
9
- "output": "/assets"
10
- }
11
- ```
12
-
13
- Add tailwind config
14
-
15
- ```js
16
- const primeui = require("tailwindcss-primeui");
17
- module.exports = {
18
- /* Your config */
19
- content: [, /* Your config */ "./node_modules/oip-common/**/*.{html,ts,scss,css,js,mjs}"]
20
- /* Your config */
21
- };
22
- ```
23
-
24
- Add scss
25
-
26
- ```sass
27
- @use "../../../node_modules/oip-common/assets/oip-common";
28
- ```
29
-
30
- Init L10nService to AppComponent
31
-
32
- ```ts
33
- import { Component, inject, OnInit } from "@angular/core";
34
- import { SecurityService } from "oip-common";
35
- import { RouterOutlet } from "@angular/router";
36
- import { ToastModule } from "primeng/toast";
37
- import { L10nService } from "../../../oip-common/src/services/l10n.service";
38
-
39
- @Component({
40
- selector: "app-root",
41
- template: `
42
- <p-toast />
43
- <router-outlet></router-outlet>
44
- `,
45
- standalone: true,
46
- imports: [ToastModule, RouterOutlet]
47
- })
48
- export class AppComponent implements OnInit {
49
- private readonly securityService = inject(SecurityService);
50
- private readonly translateService = inject(L10nService);
51
-
52
- ngOnInit() {
53
- this.securityService.auth();
54
- this.translateService.init([
55
- {
56
- code: "en",
57
- name: "English",
58
- icon: "flag flag-gb"
59
- },
60
- {
61
- code: "ru",
62
- name: "Русский",
63
- icon: "flag flag-ru"
64
- }
65
- ]);
66
- }
67
- }
68
- ```
1
+ # OipCommon
2
+
3
+ Add assets in angular.json
4
+
5
+ ```json
6
+ {
7
+ "glob": "**/*",
8
+ "input": "node_modules/oip-common/assets",
9
+ "output": "/assets"
10
+ }
11
+ ```
12
+
13
+ Add tailwind config
14
+
15
+ ```js
16
+ const primeui = require("tailwindcss-primeui");
17
+ module.exports = {
18
+ /* Your config */
19
+ content: [, /* Your config */ "./node_modules/oip-common/**/*.{html,ts,scss,css,js,mjs}"]
20
+ /* Your config */
21
+ };
22
+ ```
23
+
24
+ Add scss
25
+
26
+ ```sass
27
+ @use "../../../node_modules/oip-common/assets/oip-common";
28
+ ```
29
+
30
+ Init L10nService to AppComponent
31
+
32
+ ```ts
33
+ import { Component, inject, OnInit } from "@angular/core";
34
+ import { SecurityService } from "oip-common";
35
+ import { RouterOutlet } from "@angular/router";
36
+ import { ToastModule } from "primeng/toast";
37
+ import { L10nService } from "../../../oip-common/src/services/l10n.service";
38
+
39
+ @Component({
40
+ selector: "app-root",
41
+ template: `
42
+ <p-toast />
43
+ <router-outlet></router-outlet>
44
+ `,
45
+ standalone: true,
46
+ imports: [ToastModule, RouterOutlet]
47
+ })
48
+ export class AppComponent implements OnInit {
49
+ private readonly securityService = inject(SecurityService);
50
+ private readonly translateService = inject(L10nService);
51
+
52
+ ngOnInit() {
53
+ this.securityService.auth();
54
+ this.translateService.init([
55
+ {
56
+ code: "en",
57
+ name: "English",
58
+ icon: "flag flag-gb"
59
+ },
60
+ {
61
+ code: "ru",
62
+ name: "Русский",
63
+ icon: "flag flag-ru"
64
+ }
65
+ ]);
66
+ }
67
+ }
68
+ ```
69
+
70
+ Set up routing
71
+
72
+ `provideOipRoutes` builds the standard route tree: an authenticated shell (`AppLayoutComponent`
73
+ guarded by `AuthGuardService` and `moduleAccessGuard`) holding your routes and the built-in pages,
74
+ followed by the `unauthorized`, `notfound` and `**` routes. It keeps `**` last, so do not append
75
+ anything after the returned array.
76
+
77
+ ```ts
78
+ import { oipAuthGuard, provideOipRoutes } from "oip-common";
79
+
80
+ export const appRoutes = provideOipRoutes({
81
+ children: [
82
+ {
83
+ path: "dashboard/:id",
84
+ loadComponent: () => import("./app/components/dashboard/dashboard.component").then((m) => m.DashboardComponent),
85
+ canActivate: [oipAuthGuard]
86
+ }
87
+ ]
88
+ });
89
+ ```
90
+
91
+ Use `oipAuthGuard` on every route of your own that requires a signed in user.
92
+
93
+ All built-in routes are registered by default. Pass `false` to drop one, or a string to move it to
94
+ another path — the path must keep the same route parameters:
95
+
96
+ ```ts
97
+ provideOipRoutes({
98
+ children: [
99
+ /* ... */
100
+ ],
101
+ features: {
102
+ dbMigration: "rtds-meta-data-context-migration-module/:id",
103
+ modules: false
104
+ }
105
+ });
106
+ ```
107
+
108
+ | `features` key | Default path | Notes |
109
+ | -------------- | ------------------------------ | -------------------------------------------------- |
110
+ | `access` | `access` | Redirect target of both guards, keep it registered |
111
+ | `error` | `error` | |
112
+ | `profile` | `profile` | |
113
+ | `config` | `config` | |
114
+ | `applications` | `applications` | Administrators only |
115
+ | `modules` | `modules` | Administrators only |
116
+ | `discussion` | `discussion/:id` | |
117
+ | `dbMigration` | `db-migration/:id` | |
118
+ | `iframeModule` | `iframe-module/:id` | |
119
+ | `extensions` | `extensions/:extensionKey/:id` | |
120
+ | `noModules` | `no-modules` | Shown when the user has no module available |
121
+ | `start` | `` (the shell root) | Redirects to the start module, see below |
122
+
123
+ The remaining options: `layout` replaces the shell component, `rootRoutes` adds routes outside the
124
+ shell, `notFoundPath` and `unauthorizedPath` rename those two pages, and `wildcard: false` drops the
125
+ `**` route when your application registers its own catch-all.
126
+
127
+ Open a module by default
128
+
129
+ The empty path is claimed by a redirect route that resolves the module instance the user lands on.
130
+ It picks, in order: the `startRoute` of the host application, the module the user marked as their
131
+ start page, the first module of their menu, and finally the `no-modules` page. The menu returned by
132
+ the backend is already filtered by rights, so the resolved module is always one the user may open —
133
+ a module that was deleted or whose rights were revoked simply drops out and the next candidate wins.
134
+
135
+ ```ts
136
+ provideOipRoutes({
137
+ children: [
138
+ /* ... */
139
+ ],
140
+ startRoute: "/dashboard/1"
141
+ });
142
+ ```
143
+
144
+ Leave `startRoute` unset to follow the user's own choice. Users pick it from the sidebar: right
145
+ click a menu item and choose *Set as start page*, which stores it per user on the backend and marks
146
+ the item with a star. The route is skipped when `children` already declares its own empty path, and
147
+ `features: { start: false }` drops it entirely.
148
+
149
+ `StartPageService` backs all of this — `resolveStartUrl()` returns the target as a `UrlTree` (or
150
+ `null` when nothing is available), `setStartModule(id)` and `clearStartModule()` change the choice.
151
+ Results are cached per user and dropped when the session or the choice changes.
152
+
153
+ Every built-in route is also exported on its own — `oipConfigRoute`, `oipModulesRoute` and so on —
154
+ for applications that assemble the route tree by hand instead of calling `provideOipRoutes`.
155
+
156
+ Block the UI during module transitions
157
+
158
+ `AppLayoutComponent` renders `BlockLoaderComponent`, a full screen blocker driven by
159
+ `ModuleLoadingService`. It covers router navigation on its own, plus the module bootstrap that
160
+ `BaseModuleComponent` runs after `NavigationEnd` — rights, settings, `onModuleInstanceChange()` and
161
+ extension loading — so nothing is clickable while a module is still coming up. Applications using
162
+ the standard shell get it for free; only a custom `layout` component has to render
163
+ `<block-loader />`, and it must sit outside `.layout-wrapper`, which the blocker marks `inert`
164
+ while it is visible.
165
+
166
+ Register your own long running work with `ModuleLoadingService` when it must block the same way:
167
+
168
+ ```ts
169
+ import { Component, inject } from "@angular/core";
170
+ import { BaseModuleComponent, ModuleLoadingService } from "oip-common";
171
+
172
+ @Component({
173
+ /* ... */
174
+ })
175
+ export class ReportModuleComponent extends BaseModuleComponent<ReportSettings, void> {
176
+ private readonly moduleLoadingService = inject(ModuleLoadingService);
177
+
178
+ protected async runReport(): Promise<void> {
179
+ await this.moduleLoadingService.track(this.reportApi.build(this.id));
180
+ }
181
+ }
182
+ ```
183
+
184
+ `track()` releases the blocker when the promise rejects, so an error never leaves the UI locked. The
185
+ `begin()` / `end()` pair is available for work that is not a promise; balance it from a `finally`
186
+ block. A `begin()` that is never released is dropped after 30 seconds with a console warning.
187
+
188
+ The blocker appears only when a transition lasts longer than 150 ms and then stays for at least
189
+ 300 ms, so fast navigation does not flash a spinner.
@@ -1,17 +1,17 @@
1
- pre.app-code {
2
- background-color: var(--code-background);
3
- margin: 0 0 1rem 0;
4
- padding: 0;
5
- border-radius: var(--content-border-radius);
6
- overflow: auto;
7
-
8
- code {
9
- color: var(--code-color);
10
- padding: 1rem;
11
- margin: 0;
12
- line-height: 1.5;
13
- display: block;
14
- font-weight: semibold;
15
- font-family: monaco, Consolas, monospace;
16
- }
17
- }
1
+ pre.app-code {
2
+ background-color: var(--code-background);
3
+ margin: 0 0 1rem 0;
4
+ padding: 0;
5
+ border-radius: var(--content-border-radius);
6
+ overflow: auto;
7
+
8
+ code {
9
+ color: var(--code-color);
10
+ padding: 1rem;
11
+ margin: 0;
12
+ line-height: 1.5;
13
+ display: block;
14
+ font-weight: semibold;
15
+ font-family: monaco, Consolas, monospace;
16
+ }
17
+ }
@@ -1,2 +1,2 @@
1
- @use "./code.scss";
2
- @use "./flags/flags";
1
+ @use "./code.scss";
2
+ @use "./flags/flags";