@scania-nl/tegel-angular-extensions 0.0.4 → 0.0.6
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 +390 -33
- package/docker/docker-entrypoint.sh +13 -0
- package/docker/extract-env-vars.sh +114 -0
- package/docker/nginx.conf +69 -0
- package/esm2022/index.mjs +24 -5
- package/esm2022/lib/components/tae-footer/tae-footer.component.mjs +48 -0
- package/esm2022/lib/directives/hard-refresh.directive.mjs +83 -0
- package/esm2022/lib/env/angular/provide-runtime-config.mjs +161 -0
- package/esm2022/lib/env/angular/provide-static-config.mjs +44 -0
- package/esm2022/lib/env/core/create-env-kit.mjs +81 -0
- package/esm2022/lib/env/core/env-types.mjs +2 -0
- package/esm2022/lib/env/core/parse-env-file.mjs +140 -0
- package/esm2022/lib/toast/toast.component.mjs +5 -5
- package/esm2022/lib/toast/toast.service.mjs +3 -3
- package/index.d.ts +547 -4
- package/package.json +18 -6
- package/lib/toast/models/toast-state.enum.d.ts +0 -17
- package/lib/toast/models/toast-type.d.ts +0 -8
- package/lib/toast/models/toast.model.d.ts +0 -73
- package/lib/toast/provide-toast.d.ts +0 -3
- package/lib/toast/toast.component.d.ts +0 -24
- package/lib/toast/toast.config.d.ts +0 -35
- package/lib/toast/toast.service.d.ts +0 -98
- package/lib/utils/bootstrap-global-component.d.ts +0 -23
package/README.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
1
6
|
# @scania-nl/tegel-angular-extensions
|
|
2
7
|
|
|
3
8
|
Angular services for working with the [Tegel Angular 17](https://www.npmjs.com/package/@scania/tegel-angular-17) component library.
|
|
@@ -7,38 +12,260 @@ Provides simple wrappers for toast and modal (TBC) functionality using Angular 1
|
|
|
7
12
|
|
|
8
13
|
## ✨ Features
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
15
|
+
1. **Runtime environment configuration**
|
|
16
|
+
- Schema-driven configuration and validation using Zod
|
|
17
|
+
- Deep-partial runtime overrides
|
|
18
|
+
- Runtime-required key enforcements
|
|
19
|
+
- Strong TypeScript inference
|
|
20
|
+
2. **ToastService**
|
|
21
|
+
- Drop-in UI integrations for Tegel Angular
|
|
22
|
+
- Signal-based `ToastService` for displaying toasts
|
|
23
|
+
- Customizable toast appearance and behavior
|
|
24
|
+
3. **Default Nginx config**
|
|
25
|
+
|
|
26
|
+
- Zero boilerplate - no Angular modules required
|
|
27
|
+
- Fully typed and configurable via DI
|
|
28
|
+
- Built for Angular 19+ standalone architecture
|
|
14
29
|
|
|
15
30
|
---
|
|
16
31
|
|
|
17
|
-
|
|
32
|
+
# 📘 Table of Contents
|
|
33
|
+
|
|
34
|
+
1. [Installation](#-installation)
|
|
35
|
+
2. [Environment Configuration Overview](#-environment-configuration-overview)
|
|
36
|
+
1. [Defining your schema with createEnvKit](#defining-your-schema-with-createenvkit)
|
|
37
|
+
2. [Defining Static Environments (Dev/Prod)](#defining-static-environments-devprod)
|
|
38
|
+
3. [Providing Runtime Configuration](#providing-runtime-configuration)
|
|
39
|
+
4. [Using the ENV_CONFIG Token](#using-the-env_config-token)
|
|
40
|
+
5. [Runtime Configuration Binaries](#runtime-configuration-binaries)
|
|
41
|
+
1. [`docker-entrypoint.sh`](#docker-entrypointsh)
|
|
42
|
+
2. [`extract-env-vars.sh`](#extract-env-varssh)
|
|
43
|
+
3. [`nginx.conf`](#nginxconf)
|
|
44
|
+
4. [Example Docker Commands](#example-docker-commands)
|
|
45
|
+
3. [Toasts](#-toasts)
|
|
46
|
+
1. [Quick Start](#-quick-start)
|
|
47
|
+
1. [Add Providers](#add-providers)
|
|
48
|
+
2. [Use in components](#use-in-components)
|
|
49
|
+
2. [Configuration Options](#️-configuration-options)
|
|
50
|
+
3. [ToastService API](#-toastservice-api)
|
|
51
|
+
1. [ToastService Properties](#-toastservice-properties)
|
|
52
|
+
2. [ToastService Methods](#-toastservice-methods)
|
|
53
|
+
3. [Toast Lifecycle Hooks](#-toast-lifecycle-hooks)
|
|
54
|
+
4. [Components & Directives](#-components--directives)
|
|
55
|
+
1. [Components](#-components)
|
|
56
|
+
1. [Footer](#footer-component-tae-footer)
|
|
57
|
+
2. [Directives](#-directives)
|
|
58
|
+
1. [Hard Refresh](#hard-refresh-directive-taehardrefresh)
|
|
59
|
+
5. [Appendix](#appendix)
|
|
60
|
+
1. [Dockerfile Example](#runtime-config-dockerfile-example)
|
|
61
|
+
6. [License](#-license)
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
# 📦 Installation
|
|
18
66
|
|
|
19
67
|
```bash
|
|
20
|
-
npm install @scania-nl/tegel-angular-extensions @scania/tegel-angular-17
|
|
68
|
+
npm install @scania-nl/tegel-angular-extensions @scania/tegel-angular-17 @traversable/zod zod
|
|
21
69
|
```
|
|
22
70
|
|
|
23
|
-
> Note: `@scania/tegel-angular-17`
|
|
71
|
+
> Note: `@scania/tegel-angular-17`, `@traversable/zod`, and `zod` are peer dependencies and must be installed separately.
|
|
24
72
|
|
|
25
|
-
|
|
73
|
+
When creating an Angular project, the following dependencies already should have been installed:
|
|
26
74
|
|
|
27
75
|
```json
|
|
28
76
|
{
|
|
29
77
|
"@angular/common": "^19.0.0",
|
|
30
78
|
"@angular/core": "^19.0.0",
|
|
31
79
|
"@angular/router": "^19.0.0",
|
|
32
|
-
"rxjs": "
|
|
80
|
+
"rxjs": ">=7.8.0"
|
|
33
81
|
}
|
|
34
82
|
```
|
|
35
83
|
|
|
36
84
|
---
|
|
37
85
|
|
|
86
|
+
# 🌍 Environment Configuration Overview
|
|
87
|
+
|
|
88
|
+
The runtime-config system provides:
|
|
89
|
+
|
|
90
|
+
- Type-safe configuration via Zod schemas
|
|
91
|
+
- Static environment validation
|
|
92
|
+
- Runtime overrides via .env files (shell scripts included)
|
|
93
|
+
- Guaranteed config availability before app bootstrap
|
|
94
|
+
|
|
95
|
+
## Defining your schema with createEnvKit
|
|
96
|
+
|
|
97
|
+
Create a local file: `src/environments/environment-config.ts`
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { InjectionToken } from '@angular/core';
|
|
101
|
+
import { createEnvKit } from '@scania-nl/tegel-angular-extensions';
|
|
102
|
+
import { z } from 'zod';
|
|
103
|
+
|
|
104
|
+
// Create the EnvKit by defining a Zod-schema
|
|
105
|
+
export const EnvKit = createEnvKit({
|
|
106
|
+
schema: z
|
|
107
|
+
.object({
|
|
108
|
+
envType: z.enum(['dev', 'preprod', 'staging', 'prod']),
|
|
109
|
+
production: z.boolean(),
|
|
110
|
+
apiUrl: z.url(),
|
|
111
|
+
})
|
|
112
|
+
.strict(),
|
|
113
|
+
runtimeRequiredKeys: ['apiUrl'],
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Re-export for static env files
|
|
117
|
+
type EnvConfig = typeof EnvKit.types.EnvConfig;
|
|
118
|
+
export type StaticEnv = typeof EnvKit.types.StaticEnv;
|
|
119
|
+
|
|
120
|
+
// Injection Token for EnvConfig
|
|
121
|
+
export const ENV_CONFIG = new InjectionToken<EnvConfig>('ENV_CONFIG');
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
## Defining Static Environments (Dev/Prod)
|
|
127
|
+
|
|
128
|
+
Initialize the environments using Nx:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
nx g environments
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This will create two files: `environment.ts` for the production environment configuration and `environment.development.ts` for the local development environment configuration.
|
|
135
|
+
|
|
136
|
+
`environment.development.ts`:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { StaticEnv } from './environment-config';
|
|
140
|
+
|
|
141
|
+
export const environment: StaticEnv = {
|
|
142
|
+
envType: 'dev',
|
|
143
|
+
production: false,
|
|
144
|
+
apiUrl: 'https://www.company.com/api/',
|
|
145
|
+
} satisfies StaticEnv;
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`environment.ts`:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { StaticEnv } from './environment-config';
|
|
152
|
+
|
|
153
|
+
export const environment: StaticEnv = {
|
|
154
|
+
envType: 'prod',
|
|
155
|
+
production: true,
|
|
156
|
+
// apiUrl: 'https://www.company.com/api/' // apiUrl cannot be defined here
|
|
157
|
+
} satisfies StaticEnv;
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
## Providing Runtime Configuration
|
|
163
|
+
|
|
164
|
+
Add to `app.config.ts`:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { provideRuntimeConfig } from '@scania-nl/tegel-angular-extensions';
|
|
168
|
+
import { EnvKit, ENV_CONFIG } from '../environments/environment-config';
|
|
169
|
+
import { environment } from '../environments/environment';
|
|
170
|
+
|
|
171
|
+
export const appConfig: ApplicationConfig = {
|
|
172
|
+
providers: [
|
|
173
|
+
// ...
|
|
174
|
+
provideRuntimeConfig(EnvKit, environment, {
|
|
175
|
+
envPath: '/env/runtime.env', // Default
|
|
176
|
+
debug: !isDevMode(), // Defaults to false
|
|
177
|
+
stopOnError: true, // Default
|
|
178
|
+
token: ENV_CONFIG,
|
|
179
|
+
}),
|
|
180
|
+
],
|
|
181
|
+
};
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
## Using the ENV_CONFIG Token
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { inject } from '@angular/core';
|
|
190
|
+
import { ENV_CONFIG } from '../environments/environment-config';
|
|
191
|
+
|
|
192
|
+
@Injectable()
|
|
193
|
+
export class ApiService {
|
|
194
|
+
private readonly envConfig = inject(ENV_CONFIG);
|
|
195
|
+
|
|
196
|
+
constructor() {
|
|
197
|
+
console.log('API base URL:', this.envConfig.apiUrl);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
This setup involves several key steps:
|
|
204
|
+
|
|
205
|
+
- At application startup, the code loads `/env/runtime.env`, parses any overrides using Zod (via a deep-partial schema), and merges them with the static configuration.
|
|
206
|
+
- Required configuration keys are enforced **only** in production.
|
|
207
|
+
- The validated configuration is exposed through Angular DI using the `ENV_CONFIG` InjectionToken.
|
|
208
|
+
- The `environment` file is referenced directly here. Angular’s build process replaces the `development` environment with the `production` environment via file replacement based on the selected build configuration.
|
|
209
|
+
|
|
210
|
+
> The `/env/runtime.env` file must be generated by the container during startup.
|
|
211
|
+
> Shell script binaries to support this are included the package.
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
## Runtime Configuration Binaries
|
|
216
|
+
|
|
217
|
+
This package ships with two lightweight shell scripts used to generate a runtime configuration file inside the container. They enable true runtime configurability without rebuilding the Angular image. Additionally, the package contains a default `nginx.conf` optimized for Angular application. The files are located in the `/docker` directory.
|
|
218
|
+
|
|
219
|
+
### `docker-entrypoint.sh`
|
|
220
|
+
|
|
221
|
+
- Entry point executed every time the container starts
|
|
222
|
+
- Calls the `extract-env-vars.sh` to generate a fresh `runtime.env`
|
|
223
|
+
- Lastly, executes the provided Dockerfile `CMD`
|
|
224
|
+
|
|
225
|
+
### `extract-env-vars.sh`
|
|
226
|
+
|
|
227
|
+
- Reads all container environment variables matching a prefix (default: `NG__`)
|
|
228
|
+
- Strips the prefix and writes cleaned `KEY=VALUE` pairs to `runtime.env`
|
|
229
|
+
- Supports nested keys via ** (e.g., `NG**myFeature\_\_myThreshold`)
|
|
230
|
+
- Defaults output to `/usr/share/nginx/html/env/runtime.env`
|
|
231
|
+
|
|
232
|
+
### `nginx.conf`
|
|
233
|
+
|
|
234
|
+
A default Nginx configuration optimized for Angular applications. It provides:
|
|
235
|
+
|
|
236
|
+
- Performance tuning for static file serving
|
|
237
|
+
- Browser caching of compiled assets
|
|
238
|
+
- Gzip compression where supported
|
|
239
|
+
- Automatic fallback to `index.html` for client-side routing
|
|
240
|
+
|
|
241
|
+
### **Example Docker Commands**
|
|
242
|
+
|
|
243
|
+
```Dockerfile
|
|
244
|
+
# Copy the shell scripts to /usr/local/bin
|
|
245
|
+
COPY --from=build /app/node_modules/@scania-nl/tegel-angular-extensions/docker/*.sh /usr/local/bin/
|
|
246
|
+
# Ensure they shell scripts are executable
|
|
247
|
+
RUN chmod +x /usr/local/bin/*
|
|
248
|
+
# Use the shared entrypoint from the @scania-nl/tegel-angular-extensions npm package
|
|
249
|
+
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
|
250
|
+
# Start the nginx web server in the foreground and keep it running
|
|
251
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
For a complete Dockerfile example with the shipped `nginx.conf` config, refer to [Runtime Config Dockerfile Example](#runtime-config-dockerfile-example)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
# 🔔 Toasts
|
|
261
|
+
|
|
262
|
+
A lightweight, standalone toast system that integrates seamlessly with Tegel Angular. Provides configurable, signal-driven notifications for success, error, warning, and information messages.
|
|
263
|
+
|
|
38
264
|
## 🚀 Quick Start
|
|
39
265
|
|
|
40
|
-
###
|
|
41
|
-
|
|
266
|
+
### Add Providers
|
|
267
|
+
|
|
268
|
+
In your `app.config.ts`, specify the provider with `provideToast()`:
|
|
42
269
|
|
|
43
270
|
```ts
|
|
44
271
|
import { provideToast } from '@scania-nl/tegel-angular-extensions';
|
|
@@ -46,19 +273,21 @@ import { provideToast } from '@scania-nl/tegel-angular-extensions';
|
|
|
46
273
|
export const appConfig: ApplicationConfig = {
|
|
47
274
|
providers: [
|
|
48
275
|
provideToast({
|
|
49
|
-
type: 'information',
|
|
50
|
-
title: 'Notification',
|
|
51
|
-
description: '',
|
|
52
|
-
duration: 7500,
|
|
53
|
-
closeDuration: 300,
|
|
54
|
-
closable: true,
|
|
276
|
+
type: 'information', // Default toast type
|
|
277
|
+
title: 'Notification', // Default title
|
|
278
|
+
description: '', // Default description
|
|
279
|
+
duration: 7500, // Auto-dismiss delay (ms)
|
|
280
|
+
closeDuration: 300, // Fade-out animation duration (ms)
|
|
281
|
+
closable: true, // Show a close button
|
|
55
282
|
}),
|
|
56
283
|
],
|
|
57
284
|
};
|
|
58
285
|
```
|
|
286
|
+
|
|
59
287
|
> Note: The configuration is optional, all values shown above are the default settings.
|
|
60
288
|
|
|
61
|
-
###
|
|
289
|
+
### Use in components
|
|
290
|
+
|
|
62
291
|
In any standalone component:
|
|
63
292
|
|
|
64
293
|
```ts
|
|
@@ -72,9 +301,9 @@ export class MyToastDemoComponent {
|
|
|
72
301
|
|
|
73
302
|
showToast() {
|
|
74
303
|
this.toastService.create({
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
304
|
+
type: 'success',
|
|
305
|
+
title: 'Hello Toast',
|
|
306
|
+
description: 'Toast created successfully!',
|
|
78
307
|
});
|
|
79
308
|
}
|
|
80
309
|
}
|
|
@@ -82,6 +311,8 @@ export class MyToastDemoComponent {
|
|
|
82
311
|
|
|
83
312
|
---
|
|
84
313
|
|
|
314
|
+
|
|
315
|
+
|
|
85
316
|
## ⚙️ Configuration Options
|
|
86
317
|
|
|
87
318
|
You can configure the default appearance and behavior of toasts by passing a `ToastConfig` object to `provideToast()` in your `app.config.ts`.
|
|
@@ -101,13 +332,15 @@ All options are optional. Defaults will be applied if values are not provided.
|
|
|
101
332
|
|
|
102
333
|
---
|
|
103
334
|
|
|
335
|
+
|
|
336
|
+
|
|
104
337
|
## 🧩 ToastService API
|
|
105
338
|
|
|
106
339
|
The `ToastService` provides a signal-based API to create, manage, and dismiss toast notifications in Angular standalone apps. It is automatically available after registering `provideToast()` in your `app.config.ts`.
|
|
107
340
|
|
|
108
341
|
---
|
|
109
342
|
|
|
110
|
-
### 📦 Properties
|
|
343
|
+
### 📦 ToastService Properties
|
|
111
344
|
|
|
112
345
|
| Property | Type | Description |
|
|
113
346
|
| -------------- | ----------------- | ----------------------------------------------------- |
|
|
@@ -116,7 +349,7 @@ The `ToastService` provides a signal-based API to create, manage, and dismiss to
|
|
|
116
349
|
|
|
117
350
|
---
|
|
118
351
|
|
|
119
|
-
### 🔧 Methods
|
|
352
|
+
### 🔧 ToastService Methods
|
|
120
353
|
|
|
121
354
|
#### `create(toastOptions: Partial<ToastOptions>): number`
|
|
122
355
|
|
|
@@ -135,7 +368,7 @@ toastService.create({
|
|
|
135
368
|
|
|
136
369
|
Returns the unique toast ID.
|
|
137
370
|
|
|
138
|
-
|
|
371
|
+
|
|
139
372
|
|
|
140
373
|
#### Convenience Methods
|
|
141
374
|
|
|
@@ -148,13 +381,13 @@ toastService.warning({ title: 'Heads up!' });
|
|
|
148
381
|
toastService.info({ title: 'FYI' });
|
|
149
382
|
```
|
|
150
383
|
|
|
151
|
-
|
|
384
|
+
|
|
152
385
|
|
|
153
386
|
#### `getToast(id: number): Toast | undefined`
|
|
154
387
|
|
|
155
388
|
Gets a toast by its ID.
|
|
156
389
|
|
|
157
|
-
|
|
390
|
+
|
|
158
391
|
|
|
159
392
|
#### `createRandomToast(props?: Partial<ToastOptions>): number`
|
|
160
393
|
|
|
@@ -164,25 +397,25 @@ Creates a random toast with random type and title. Useful for testing. Returns t
|
|
|
164
397
|
toastService.createRandomToast();
|
|
165
398
|
```
|
|
166
399
|
|
|
167
|
-
|
|
400
|
+
|
|
168
401
|
|
|
169
402
|
#### `close(id: number): void`
|
|
170
403
|
|
|
171
404
|
Triggers the fade-out animation and schedules removal.
|
|
172
405
|
|
|
173
|
-
|
|
406
|
+
|
|
174
407
|
|
|
175
408
|
#### `closeAll(): void`
|
|
176
409
|
|
|
177
410
|
Closes all currently open toasts.
|
|
178
411
|
|
|
179
|
-
|
|
412
|
+
|
|
180
413
|
|
|
181
414
|
#### `remove(id: number): void`
|
|
182
415
|
|
|
183
416
|
Immediately removes a toast (no animation).
|
|
184
417
|
|
|
185
|
-
|
|
418
|
+
|
|
186
419
|
|
|
187
420
|
#### `removeAll(): void`
|
|
188
421
|
|
|
@@ -206,12 +439,136 @@ Example:
|
|
|
206
439
|
toastService.success({
|
|
207
440
|
title: 'Logged out',
|
|
208
441
|
duration: 5000,
|
|
209
|
-
onRemoved: (toast) => console.log(`Toast ${toast.id} removed`)
|
|
442
|
+
onRemoved: (toast) => console.log(`Toast ${toast.id} removed`),
|
|
210
443
|
});
|
|
211
444
|
```
|
|
212
445
|
|
|
213
446
|
---
|
|
214
447
|
|
|
215
|
-
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
# 🧩 Components & Directives
|
|
451
|
+
|
|
452
|
+
This library includes a set of standalone UI components and utility directives, all prefixed with **`tae`**, designed to extend and complement the Tegel Angular ecosystem. Each piece is lightweight, fully typed, and easy to import into any Angular 19+ application.
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
## 🧱 Components
|
|
456
|
+
|
|
457
|
+
### Footer Component (`tae-footer`)
|
|
458
|
+
|
|
459
|
+
`TaeFooterComponent` is an enhanced footer based on the Tegel `TdsFooterComponent`. It preserves the same visual appearance while adding two key improvements:
|
|
460
|
+
|
|
461
|
+
- A **compact “small” variant** for constrained layouts.
|
|
462
|
+
- An optional **version display**, allowing applications to show their build or release version directly in the footer.
|
|
463
|
+
|
|
464
|
+
This makes it ideal for full-viewport layouts that benefit from space efficiency and clear version visibility.
|
|
465
|
+
|
|
466
|
+
**Inputs:**
|
|
467
|
+
|
|
468
|
+
| Input | Type | Default | Description |
|
|
469
|
+
| ------- | --------------------- | ------- | ------------------------------------------------------------------------------------------ |
|
|
470
|
+
| variant | `'normal' \| 'small'` | normal | Layout style of the footer. `'small'` produces a more compact version. |
|
|
471
|
+
| version | `string \| undefined` | — | Optional application version string. If provided, it is displayed left of the Scania logo. |
|
|
472
|
+
|
|
473
|
+
**Example:**
|
|
474
|
+
|
|
475
|
+
```html
|
|
476
|
+
<tae-footer variant="small" version="v1.0.0" />
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
## ⚡ Directives
|
|
482
|
+
|
|
483
|
+
### Hard Refresh Directive (`taeHardRefresh`)
|
|
484
|
+
|
|
485
|
+
The `HardRefreshDirective` provides a small UX shortcut: it performs a **full page reload** when the host element is clicked **N times in rapid succession**, where each click must occur within `clickWindowMs` milliseconds of the previous one.
|
|
486
|
+
|
|
487
|
+
This is especially useful for hard-reloading tablet or mobile applications which are locked in full-screen mode, and thus have no browser buttons like refresh.
|
|
488
|
+
|
|
489
|
+
**Inputs:**
|
|
490
|
+
|
|
491
|
+
| Input | Type | Default | Description |
|
|
492
|
+
| -------------- | ------ | ------- | ---------------------------------------------------------------------- |
|
|
493
|
+
| clicksRequired | number | 3 | Number of clicks required within the window to trigger a hard refresh. |
|
|
494
|
+
| clickWindowMs | number | 500 | Time window in milliseconds between two subsequent clicks. |
|
|
495
|
+
|
|
496
|
+
**Example:**
|
|
497
|
+
|
|
498
|
+
```html
|
|
499
|
+
<tds-header-brand-symbol
|
|
500
|
+
taeHardRefresh
|
|
501
|
+
[clicksRequired]="3"
|
|
502
|
+
[clickWindowMs]="500"
|
|
503
|
+
>
|
|
504
|
+
<a aria-label="Scania - red gryphon on blue shield"></a>
|
|
505
|
+
</tds-header-brand-symbol>
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
# Appendix
|
|
513
|
+
|
|
514
|
+
## Runtime Config Dockerfile Example
|
|
515
|
+
|
|
516
|
+
```Dockerfile
|
|
517
|
+
ARG NODE_VERSION=25-alpine
|
|
518
|
+
ARG NGINX_VERSION=1.29.3-alpine
|
|
519
|
+
|
|
520
|
+
# Stage 1: Build the Angular Application
|
|
521
|
+
FROM node:${NODE_VERSION} AS build
|
|
522
|
+
|
|
523
|
+
WORKDIR /app
|
|
524
|
+
|
|
525
|
+
# Copy package-related files
|
|
526
|
+
COPY package*.json ./
|
|
527
|
+
|
|
528
|
+
# Install project dependencies using npm ci (ensures a clean, reproducible install)
|
|
529
|
+
RUN --mount=type=cache,target=/root/.npm npm ci
|
|
530
|
+
|
|
531
|
+
# Copy the rest of the application source code into the container
|
|
532
|
+
COPY . .
|
|
533
|
+
|
|
534
|
+
# Build the Angular application with the specified app version
|
|
535
|
+
RUN npm run build
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
# Stage 2: Prepare Nginx to Serve Static Files
|
|
539
|
+
FROM nginx:${NGINX_VERSION}
|
|
540
|
+
|
|
541
|
+
# Copy the static build output from the build stage to Nginx's default HTML serving directory
|
|
542
|
+
COPY --from=build /app/dist/*/browser /usr/share/nginx/html
|
|
543
|
+
|
|
544
|
+
# Copy the shell scripts from the @scania-nl/tegel-angular-extensions npm package
|
|
545
|
+
COPY --from=build /app/node_modules/@scania-nl/tegel-angular-extensions/docker/*.sh /usr/local/bin/
|
|
546
|
+
# Copy the custom Nginx configuration file from the @scania-nl/tegel-angular-extensions npm package
|
|
547
|
+
COPY --from=build /app/node_modules/@scania-nl/tegel-angular-extensions/docker/nginx.conf /etc/nginx/nginx.conf
|
|
548
|
+
|
|
549
|
+
# Ensure the shell scripts are executable
|
|
550
|
+
RUN chmod +x /usr/local/bin/*
|
|
551
|
+
|
|
552
|
+
# Expose ports 80 and 443 to allow HTTP and HTTPS traffic
|
|
553
|
+
EXPOSE 80 443
|
|
554
|
+
|
|
555
|
+
# Use the shared entrypoint from the @scania-nl/tegel-angular-extensions npm package
|
|
556
|
+
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
|
557
|
+
|
|
558
|
+
# Start the nginx web server with custom config in the foreground and keep it running
|
|
559
|
+
CMD ["nginx", "-c", "/etc/nginx/nginx.conf", "-g", "daemon off;"]
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
# 📄 License
|
|
565
|
+
|
|
566
|
+
Copyright 2025 Scania CV AB.
|
|
567
|
+
|
|
568
|
+
All files are available under the MIT license. The Scania brand identity, logos and photographs found in this repository are copyrighted Scania CV AB and are not available on an open source basis or to be used as examples or in any other way, if not specifically ordered by Scania CV AB.
|
|
569
|
+
|
|
570
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
571
|
+
|
|
572
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
216
573
|
|
|
217
|
-
|
|
574
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
ENV_OUTPUT_PATH="/usr/share/nginx/html/env/runtime.env"
|
|
4
|
+
|
|
5
|
+
rm -f "$ENV_OUTPUT_PATH" # Remove the runtime config if it exists
|
|
6
|
+
|
|
7
|
+
# Generate the runtime config from env vars
|
|
8
|
+
if ! /usr/local/bin/extract-env-vars.sh "" "$ENV_OUTPUT_PATH"; then
|
|
9
|
+
echo "Failed to extract runtime environment variables, continuing with defaults..."
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Then start Nginx
|
|
13
|
+
exec "$@"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# --------------
|
|
4
|
+
# Configuration
|
|
5
|
+
# --------------
|
|
6
|
+
|
|
7
|
+
PREFIX="${1:-NG__}" # First argument = prefix, defaults to NG__
|
|
8
|
+
OUTPUT_FILE="${2:-./runtime.env}" # Second argument = output path, defaults to current dir
|
|
9
|
+
shift 2 # Remaining arguments = manual test vars like NG__key=value
|
|
10
|
+
|
|
11
|
+
OUTPUT_DIR=$(dirname "$OUTPUT_FILE") # Output directory
|
|
12
|
+
TMP_FILE="/tmp/runtime_env_$$.tmp" # Temp file for writing
|
|
13
|
+
: > "$TMP_FILE" # Create/empty the temp file
|
|
14
|
+
|
|
15
|
+
# --------------
|
|
16
|
+
# Logging Helpers
|
|
17
|
+
# --------------
|
|
18
|
+
|
|
19
|
+
log_info() { echo "[INFO] $*"; }
|
|
20
|
+
log_warn() { echo "[WARN] $*"; }
|
|
21
|
+
log_debug() { echo "[DEBUG] $*"; }
|
|
22
|
+
|
|
23
|
+
# --------------
|
|
24
|
+
# Validation
|
|
25
|
+
# --------------
|
|
26
|
+
|
|
27
|
+
validate_var() {
|
|
28
|
+
raw="$1"
|
|
29
|
+
key="${raw%%=*}"
|
|
30
|
+
|
|
31
|
+
# Must start with prefix
|
|
32
|
+
case "$key" in
|
|
33
|
+
"$PREFIX") return 1 ;; # only prefix, no key
|
|
34
|
+
"$PREFIX"*) ;;
|
|
35
|
+
*) return 1 ;;
|
|
36
|
+
esac
|
|
37
|
+
|
|
38
|
+
# Strip prefix
|
|
39
|
+
trimmed="${key#$PREFIX}"
|
|
40
|
+
|
|
41
|
+
# Key must not start with a digit
|
|
42
|
+
first_segment=$(printf '%s' "$trimmed" | cut -d'_' -f1)
|
|
43
|
+
case "$first_segment" in
|
|
44
|
+
[0-9]*)
|
|
45
|
+
return 1 ;;
|
|
46
|
+
esac
|
|
47
|
+
|
|
48
|
+
return 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
strip_prefix() {
|
|
52
|
+
printf '%s\n' "$1" | sed "s/^$PREFIX//"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# --------------
|
|
56
|
+
# Extract ENV vars
|
|
57
|
+
# --------------
|
|
58
|
+
|
|
59
|
+
log_info "Using prefix: '$PREFIX'"
|
|
60
|
+
log_info "Output file: $OUTPUT_FILE"
|
|
61
|
+
|
|
62
|
+
env | grep "^$PREFIX" | while IFS= read -r line; do
|
|
63
|
+
if validate_var "$line"; then
|
|
64
|
+
key="${line%%=*}"
|
|
65
|
+
val="${line#*=}"
|
|
66
|
+
clean_key=$(strip_prefix "$key")
|
|
67
|
+
printf '%s=%s\n' "$clean_key" "$val" >> "$TMP_FILE"
|
|
68
|
+
log_debug "Added from environment: $clean_key=$val"
|
|
69
|
+
else
|
|
70
|
+
log_warn "Skipped invalid env var: $line"
|
|
71
|
+
fi
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
# --------------
|
|
75
|
+
# Manual vars
|
|
76
|
+
# --------------
|
|
77
|
+
|
|
78
|
+
for var in "$@"; do
|
|
79
|
+
if validate_var "$var"; then
|
|
80
|
+
key="${var%%=*}"
|
|
81
|
+
val="${var#*=}"
|
|
82
|
+
clean_key=$(strip_prefix "$key")
|
|
83
|
+
printf '%s=%s\n' "$clean_key" "$val" >> "$TMP_FILE"
|
|
84
|
+
log_debug "Added from CLI: $clean_key=$val"
|
|
85
|
+
else
|
|
86
|
+
log_warn "Skipped invalid manual var: $var"
|
|
87
|
+
fi
|
|
88
|
+
done
|
|
89
|
+
|
|
90
|
+
# --------------
|
|
91
|
+
# Output
|
|
92
|
+
# --------------
|
|
93
|
+
# Ensure the output directory exists
|
|
94
|
+
if [ ! -d "$OUTPUT_DIR" ]; then
|
|
95
|
+
log_info "Creating output directory: $OUTPUT_DIR"
|
|
96
|
+
if ! mkdir -p "$OUTPUT_DIR"; then
|
|
97
|
+
log_warn "Failed to create directory '$OUTPUT_DIR'"
|
|
98
|
+
rm -f "$TMP_FILE"
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
if [ -s "$TMP_FILE" ]; then
|
|
104
|
+
if mv "$TMP_FILE" "$OUTPUT_FILE"; then
|
|
105
|
+
log_info "Wrote cleaned env vars to $OUTPUT_FILE"
|
|
106
|
+
else
|
|
107
|
+
log_warn "Failed to move temp file to $OUTPUT_FILE"
|
|
108
|
+
rm -f "$TMP_FILE"
|
|
109
|
+
exit 1
|
|
110
|
+
fi
|
|
111
|
+
else
|
|
112
|
+
rm -f "$TMP_FILE"
|
|
113
|
+
log_warn "No valid env vars found with prefix '$PREFIX'. Skipping output."
|
|
114
|
+
fi
|