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 +189 -68
- package/assets/demo/code.scss +17 -17
- package/assets/demo/demo.scss +2 -2
- package/assets/demo/flags/flags.scss +984 -984
- package/assets/i18n/extensions.en.json +1 -1
- package/assets/layout/_core.scss +30 -30
- package/assets/layout/_footer.scss +8 -8
- package/assets/layout/_main.scss +12 -12
- package/assets/layout/_menu.scss +148 -148
- package/assets/layout/_mixins.scss +15 -15
- package/assets/layout/_preloading.scss +49 -49
- package/assets/layout/_responsive.scss +108 -108
- package/assets/layout/_topbar.scss +168 -168
- package/assets/layout/_typography.scss +68 -68
- package/assets/layout/_utils.scss +25 -25
- package/assets/layout/layout.scss +13 -13
- package/assets/layout/variables/_common.scss +20 -20
- package/assets/layout/variables/_dark.scss +5 -5
- package/assets/layout/variables/_light.scss +5 -5
- package/assets/oip-common.scss +6 -6
- package/assets/tailwind.css +3 -3
- package/fesm2022/oip-common.mjs +1033 -241
- package/fesm2022/oip-common.mjs.map +1 -1
- package/index.d.ts +319 -5
- package/package.json +1 -1
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.
|
package/assets/demo/code.scss
CHANGED
|
@@ -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
|
+
}
|
package/assets/demo/demo.scss
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
@use "./code.scss";
|
|
2
|
-
@use "./flags/flags";
|
|
1
|
+
@use "./code.scss";
|
|
2
|
+
@use "./flags/flags";
|