@axa-fr/slimfaas-planet-saver 0.37.0-pr.1061101 → 0.37.0-pr.1111153
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 +74 -7
- package/package.json +1 -1
- package/src/SlimFaasPlanetSaver.d.ts +33 -52
- package/src/SlimFaasPlanetSaver.js +81 -23
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
A Vanilla JS project to save the planet. SlimFaas (https://github.com/SlimPlanet/slimfaas) is the
|
|
7
|
+
A Vanilla JS project to save the planet. SlimFaas (https://github.com/SlimPlanet/slimfaas) is the slimmest and simplest Function As A Service on Kubernetes.
|
|
8
8
|
It works as a proxy that you can be deployed in your namespace.
|
|
9
9
|
|
|
10
10
|
SlimFaas API can give to the frontend information about the infrastructure state. **It is a mind changer !**
|
|
@@ -12,7 +12,7 @@ SlimFaas API can give to the frontend information about the infrastructure state
|
|
|
12
12
|
**Why?**
|
|
13
13
|
|
|
14
14
|
Because in production instead of setting up 2 replicas of your API backend, you can set up 0 replicas and use an UX that will show the user that the backend is down instead !
|
|
15
|
-
**@axa-fr/slimfaas-planet-saver** is here to for doing that
|
|
15
|
+
**@axa-fr/slimfaas-planet-saver** is here to for doing that easy.
|
|
16
16
|
|
|
17
17
|

|
|
18
18
|
|
|
@@ -25,9 +25,9 @@ npm install @axa-fr/slimfaas-planet-saver
|
|
|
25
25
|
Example usage with react :
|
|
26
26
|
```javascript
|
|
27
27
|
import React, { useState, useEffect, useRef } from 'react';
|
|
28
|
-
import { SlimFaasPlanetSaver } from
|
|
28
|
+
import { SlimFaasPlanetSaver } from '@axa-fr/slimfaas-planet-saver';
|
|
29
29
|
|
|
30
|
-
const PlanetSaver = ({ children, baseUrl, fetch }) => {
|
|
30
|
+
const PlanetSaver = ({ children, baseUrl, fetch, noActivityTimeout=60000, behavior={} }) => {
|
|
31
31
|
const [isFirstStart, setIsFirstStart] = useState(true);
|
|
32
32
|
const environmentStarterRef = useRef(null);
|
|
33
33
|
|
|
@@ -39,9 +39,18 @@ const PlanetSaver = ({ children, baseUrl, fetch }) => {
|
|
|
39
39
|
const instance = new SlimFaasPlanetSaver(baseUrl, {
|
|
40
40
|
interval: 2000,
|
|
41
41
|
fetch,
|
|
42
|
+
behavior,
|
|
42
43
|
updateCallback: (data) => {
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
// Filter only the items that block the UI (WakeUp+BlockUI)
|
|
45
|
+
const blockingItems = data.filter(
|
|
46
|
+
(item) => instance.getBehavior(item.Name) === 'WakeUp+BlockUI'
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// If all blocking items are ready, set isFirstStart to false
|
|
50
|
+
const allBlockingReady = blockingItems.every(
|
|
51
|
+
(item) => item.NumberReady >= 1
|
|
52
|
+
);
|
|
53
|
+
if (allBlockingReady && isFirstStart) {
|
|
45
54
|
setIsFirstStart(false);
|
|
46
55
|
}
|
|
47
56
|
},
|
|
@@ -53,7 +62,8 @@ const PlanetSaver = ({ children, baseUrl, fetch }) => {
|
|
|
53
62
|
overlayErrorMessage: 'An error occurred when starting environment. Please contact an administrator.',
|
|
54
63
|
overlaySecondaryMessage: 'Startup should be fast, but if no machines are available it can take several minutes.',
|
|
55
64
|
overlayLoadingIcon: '🌍',
|
|
56
|
-
overlayErrorSecondaryMessage: 'If the error persists, please contact an administrator.'
|
|
65
|
+
overlayErrorSecondaryMessage: 'If the error persists, please contact an administrator.',
|
|
66
|
+
noActivityTimeout
|
|
57
67
|
});
|
|
58
68
|
|
|
59
69
|
environmentStarterRef.current = instance;
|
|
@@ -78,8 +88,25 @@ const PlanetSaver = ({ children, baseUrl, fetch }) => {
|
|
|
78
88
|
export default PlanetSaver;
|
|
79
89
|
|
|
80
90
|
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Usage:
|
|
95
|
+
|
|
96
|
+
```jsx
|
|
97
|
+
const behavior: {
|
|
98
|
+
"api-speech-to-text": "WakeUp",
|
|
99
|
+
"heavy-pdf-service": "WakeUp+BlockUI",
|
|
100
|
+
"deprecated-service": "None"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
<PlanetSaver baseUrl="http://slimfaas.mycompany.com" fetch={window.fetch} behavior={behavior}>
|
|
104
|
+
<App />
|
|
105
|
+
</PlanetSaver>
|
|
81
106
|
```
|
|
82
107
|
|
|
108
|
+
---
|
|
109
|
+
|
|
83
110
|
## Run the demo
|
|
84
111
|
|
|
85
112
|
```javascript
|
|
@@ -88,3 +115,43 @@ cd slimfaas/src/SlimFaasPlanetSaver
|
|
|
88
115
|
npm i
|
|
89
116
|
npm run dev
|
|
90
117
|
```
|
|
118
|
+
This will launch a local dev server, letting you see `SlimFaasPlanetSaver` in action.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Configuration Options
|
|
123
|
+
When you create a `new SlimFaasPlanetSaver(baseUrl, options)`, you can provide the following optional properties in the `options` object:
|
|
124
|
+
|
|
125
|
+
| Property | Type | Default | Description |
|
|
126
|
+
|---------------------------|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
127
|
+
| updateCallback | `(data: any[]) => void` | `() => {}` | Function called after a successful fetch of the functions’ status. The array data includes objects with info about each function, for example: `[{ Name: 'myFunc', NumberReady: 1 }, ...]`. |
|
|
128
|
+
| errorCallback | `(errorMessage: string) => void` | `() => {}` | Function called if an error occurs during the status fetch (e.g., network error). Receives an errorMessage string. |
|
|
129
|
+
| interval | `number` | `5000` | How frequently (in ms) the polling should run. |
|
|
130
|
+
| overlayStartingMessage | `string` | `"🌳 Starting the environment.... 🌳"` | Main message shown on the overlay when the environment is waking up. |
|
|
131
|
+
| overlayNoActivityMessage | `string` | `"Waiting activity to start environment..."` | Message shown if there is no user activity (mouse movement) for too long, but the environment is not ready yet. |
|
|
132
|
+
| overlayErrorMessage | `string` | `"An error occurred while starting the environment."` | Main message shown on the overlay if an error occurs (e.g., network error). |
|
|
133
|
+
| overlaySecondaryMessage | `string` | `"Startup should be fast, but if no machines are available it can take several minutes."` | Secondary message shown on the overlay when the environment is waking up. |
|
|
134
|
+
| overlayErrorSecondaryMessage | `string` | `"If the error persists, please contact an administrator."` | Secondary message shown on the overlay when an error occurs. |
|
|
135
|
+
| overlayLoadingIcon | `string` | `"🌍"` | Text or icon shown on the overlay. By default, it is animated to spin. |
|
|
136
|
+
| noActivityTimeout | `number` | `60000` | How long (in ms) to wait for mouse movement before concluding there is no activity. If no activity is detected, a different overlay message is displayed. |
|
|
137
|
+
| wakeUpTimeout | `number` | `60000` | If a function was recently “woken up,” we’ll skip re-calling wake-up for that function within this timeout window (in ms). |
|
|
138
|
+
| fetch | `typeof fetch` | Global fetch | Custom fetch function if you want to provide your own (e.g., for SSR, or if your environment doesn't have a global fetch). |
|
|
139
|
+
| behavior | `{ [functionName: string]: 'WakeUp+BlockUI' \| 'WakeUp' \| 'None' }` | *Not set; defaults each function to "WakeUp+BlockUI" if unspecified* | Allows you to override how each function is handled: 1. `"WakeUp+BlockUI"`: wakes the function and blocks the UI with the overlay until it’s ready. 2. `"WakeUp"`: wakes without blocking the UI. 3. `"None"`: no wake-up call. |
|
|
140
|
+
|
|
141
|
+
### Notes on Behavior
|
|
142
|
+
If a function is **not** specified in the behavior map, it defaults to `"WakeUp+BlockUI"`.
|
|
143
|
+
|
|
144
|
+
- `"WakeUp+BlockUI"` means the overlay will be shown until that function is `NumberReady >= 1`.
|
|
145
|
+
- `"WakeUp"` means we attempt to wake up the function, but do not keep the overlay shown specifically for that function.
|
|
146
|
+
- `"None"` means the function will neither be woken up nor block the UI.
|
|
147
|
+
|
|
148
|
+
### Lifecycle
|
|
149
|
+
|
|
150
|
+
1. **Initialize**
|
|
151
|
+
Call `instance.initialize()` to create the overlay elements, inject styles, and bind event listeners (e.g., for mouse movement).
|
|
152
|
+
|
|
153
|
+
2. **Start Polling**
|
|
154
|
+
Call `instance.startPolling()` to begin the periodic checks of the environment. If the environment is not ready, the overlay will appear.
|
|
155
|
+
|
|
156
|
+
3. **Stop Polling / Cleanup**
|
|
157
|
+
When your component unmounts or you no longer need to monitor the environment, call `instance.cleanup()`. This removes the overlay, styles, and any timers or event listeners.
|
package/package.json
CHANGED
|
@@ -1,56 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
private baseUrl: string;
|
|
3
|
-
private updateCallback: (data: any) => void;
|
|
4
|
-
private errorCallback: (error: any) => void;
|
|
5
|
-
private interval: number;
|
|
6
|
-
private overlayStartingMessage: string;
|
|
7
|
-
private overlayNoActivityMessage: string;
|
|
8
|
-
private overlayErrorMessage: string;
|
|
9
|
-
private overlaySecondaryMessage: string;
|
|
10
|
-
private overlayErrorSecondaryMessage: string;
|
|
11
|
-
private overlayLoadingIcon: string;
|
|
12
|
-
private noActivityTimeout: number;
|
|
13
|
-
private wakeUpTimeout: number;
|
|
14
|
-
private fetch: typeof fetch;
|
|
15
|
-
private intervalId: number | null;
|
|
16
|
-
private isDocumentVisible: boolean;
|
|
17
|
-
private overlayElement: HTMLElement | null;
|
|
18
|
-
private spanElement: HTMLElement | null;
|
|
19
|
-
private styleElement: HTMLElement | null;
|
|
20
|
-
private isReady: boolean;
|
|
21
|
-
private id: number;
|
|
22
|
-
private cleanned: boolean;
|
|
23
|
-
private lastMouseMoveTime: number;
|
|
24
|
-
private handleMouseMove: () => void;
|
|
25
|
-
private handleVisibilityChange: () => void;
|
|
1
|
+
export type BehaviorValue = 'WakeUp+BlockUI' | 'WakeUp' | 'None';
|
|
26
2
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
interval?: number,
|
|
31
|
-
overlayStartingMessage?: string,
|
|
32
|
-
overlayNoActivityMessage?: string,
|
|
33
|
-
overlayErrorMessage?: string,
|
|
34
|
-
overlaySecondaryMessage?: string,
|
|
35
|
-
overlayErrorSecondaryMessage?: string,
|
|
36
|
-
overlayLoadingIcon?: string,
|
|
37
|
-
fetch?: typeof fetch
|
|
38
|
-
noActivityTimeout?: number
|
|
39
|
-
wakeUpTimeout?: number
|
|
40
|
-
});
|
|
3
|
+
export interface BehaviorMap {
|
|
4
|
+
[functionName: string]: BehaviorValue;
|
|
5
|
+
}
|
|
41
6
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
7
|
+
export interface SlimFaasPlanetSaverOptions {
|
|
8
|
+
updateCallback?: (data: any[]) => void;
|
|
9
|
+
errorCallback?: (errorMessage: string) => void;
|
|
10
|
+
interval?: number;
|
|
11
|
+
overlayStartingMessage?: string;
|
|
12
|
+
overlayNoActivityMessage?: string;
|
|
13
|
+
overlayErrorMessage?: string;
|
|
14
|
+
overlaySecondaryMessage?: string;
|
|
15
|
+
overlayErrorSecondaryMessage?: string;
|
|
16
|
+
overlayLoadingIcon?: string;
|
|
17
|
+
noActivityTimeout?: number;
|
|
18
|
+
wakeUpTimeout?: number;
|
|
19
|
+
fetch?: typeof fetch;
|
|
20
|
+
behavior?: BehaviorMap;
|
|
54
21
|
}
|
|
55
22
|
|
|
56
|
-
export default SlimFaasPlanetSaver
|
|
23
|
+
export default class SlimFaasPlanetSaver {
|
|
24
|
+
constructor(baseUrl: string, options?: SlimFaasPlanetSaverOptions);
|
|
25
|
+
initialize(): void;
|
|
26
|
+
startPolling(): void;
|
|
27
|
+
stopPolling(): void;
|
|
28
|
+
protected fetchStatus(): Promise<void>;
|
|
29
|
+
protected wakeUpPods(data: any[], lastWakeUpTime: number | null): Promise<boolean>;
|
|
30
|
+
protected setReadyState(isReady: boolean): void;
|
|
31
|
+
protected createOverlay(): void;
|
|
32
|
+
protected injectStyles(): void;
|
|
33
|
+
protected showOverlay(): void;
|
|
34
|
+
protected hideOverlay(): void;
|
|
35
|
+
protected updateOverlayMessage(newMessage: string, status?: string, secondaryMessage?: string | null): void;
|
|
36
|
+
cleanup(): void;
|
|
37
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
return tempUrl;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
let id =1;
|
|
7
|
+
let id = 1;
|
|
8
8
|
|
|
9
9
|
export default class SlimFaasPlanetSaver {
|
|
10
10
|
constructor(baseUrl, options = {}) {
|
|
@@ -21,6 +21,11 @@ export default class SlimFaasPlanetSaver {
|
|
|
21
21
|
this.noActivityTimeout = options.noActivityTimeout || 60000;
|
|
22
22
|
this.wakeUpTimeout = options.wakeUpTimeout || 60000;
|
|
23
23
|
this.fetch = options.fetch || fetch;
|
|
24
|
+
|
|
25
|
+
// Ajout de la configuration de comportement
|
|
26
|
+
// Les valeurs possibles sont "WakeUp+BlockUI", "WakeUp", "None"
|
|
27
|
+
this.behavior = options.behavior || {};
|
|
28
|
+
|
|
24
29
|
this.intervalId = null;
|
|
25
30
|
this.isDocumentVisible = !document.hidden;
|
|
26
31
|
this.overlayElement = null;
|
|
@@ -32,6 +37,14 @@ export default class SlimFaasPlanetSaver {
|
|
|
32
37
|
this.lastWakeUpTime = null;
|
|
33
38
|
}
|
|
34
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Retourne le comportement à appliquer pour une fonction donnée
|
|
42
|
+
* S'il n'est pas renseigné, renvoie "WakeUp+BlockUI" par défaut
|
|
43
|
+
*/
|
|
44
|
+
getBehavior(name) {
|
|
45
|
+
return this.behavior[name] || 'WakeUp+BlockUI';
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
initialize() {
|
|
36
49
|
this.cleanned = false;
|
|
37
50
|
this.lastMouseMoveTime = Date.now();
|
|
@@ -43,8 +56,8 @@ export default class SlimFaasPlanetSaver {
|
|
|
43
56
|
|
|
44
57
|
this.createOverlay();
|
|
45
58
|
this.injectStyles();
|
|
46
|
-
|
|
47
59
|
}
|
|
60
|
+
|
|
48
61
|
handleMouseMove() {
|
|
49
62
|
this.lastMouseMoveTime = Date.now();
|
|
50
63
|
}
|
|
@@ -53,11 +66,21 @@ export default class SlimFaasPlanetSaver {
|
|
|
53
66
|
this.isDocumentVisible = !document.hidden;
|
|
54
67
|
}
|
|
55
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Appelle le wake-up sur les fonctions dont le comportement n'est pas "None"
|
|
71
|
+
* et qui ne sont pas prêtes (NumberReady === 0), sauf si on a déjà fait
|
|
72
|
+
* un wake-up trop récemment (selon wakeUpTimeout).
|
|
73
|
+
*/
|
|
56
74
|
async wakeUpPods(data, lastWakeUpTime) {
|
|
57
75
|
const currentTime = Date.now();
|
|
58
76
|
let isWakeUpCallMade = false;
|
|
77
|
+
|
|
78
|
+
// On évite de rappeler trop souvent la même fonction
|
|
59
79
|
const shouldFilter = lastWakeUpTime && (currentTime - lastWakeUpTime) <= this.wakeUpTimeout;
|
|
80
|
+
|
|
81
|
+
// On ne fait un wake-up que pour les fonctions dont le comportement est "WakeUp" ou "WakeUp+BlockUI"
|
|
60
82
|
const wakePromises = data
|
|
83
|
+
.filter((item) => this.getBehavior(item.Name) !== 'None')
|
|
61
84
|
.filter((item) => item.NumberReady === 0 || !shouldFilter)
|
|
62
85
|
.map(async (item) => {
|
|
63
86
|
const response = await this.fetch(`${this.baseUrl}/wake-function/${item.Name}`, {
|
|
@@ -66,7 +89,7 @@ export default class SlimFaasPlanetSaver {
|
|
|
66
89
|
if (response.status >= 400) {
|
|
67
90
|
throw new Error(`HTTP Error! status: ${response.status} for function ${item.Name}`);
|
|
68
91
|
}
|
|
69
|
-
isWakeUpCallMade = true
|
|
92
|
+
isWakeUpCallMade = true;
|
|
70
93
|
return response;
|
|
71
94
|
});
|
|
72
95
|
|
|
@@ -79,6 +102,9 @@ export default class SlimFaasPlanetSaver {
|
|
|
79
102
|
return isWakeUpCallMade;
|
|
80
103
|
}
|
|
81
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Récupère le status de chaque fonction et met à jour l'UI et l'overlay
|
|
107
|
+
*/
|
|
82
108
|
async fetchStatus() {
|
|
83
109
|
try {
|
|
84
110
|
const response = await this.fetch(`${this.baseUrl}/status-functions`);
|
|
@@ -87,38 +113,48 @@ export default class SlimFaasPlanetSaver {
|
|
|
87
113
|
}
|
|
88
114
|
const data = await response.json();
|
|
89
115
|
|
|
90
|
-
|
|
91
|
-
this.
|
|
116
|
+
// On ne considère comme bloquantes que les fonctions dont le comportement est "WakeUp+BlockUI"
|
|
117
|
+
const blockingItems = data.filter((item) => this.getBehavior(item.Name) === 'WakeUp+BlockUI');
|
|
118
|
+
const allBlockingReady = blockingItems.every((item) => item.NumberReady >= 1);
|
|
119
|
+
|
|
120
|
+
// Si toutes les fonctions "bloquantes" sont prêtes, on estime que c'est "ready".
|
|
121
|
+
this.setReadyState(allBlockingReady);
|
|
92
122
|
|
|
123
|
+
// Callback pour l'extérieur
|
|
93
124
|
this.updateCallback(data);
|
|
94
125
|
|
|
126
|
+
// On vérifie l'activité de la souris pour "réveiller" (wakeUp) les fonctions
|
|
95
127
|
const now = Date.now();
|
|
96
|
-
const mouseMovedRecently = now - this.lastMouseMoveTime <= this.noActivityTimeout;
|
|
128
|
+
const mouseMovedRecently = now - this.lastMouseMoveTime <= this.noActivityTimeout;
|
|
97
129
|
|
|
98
|
-
if (!
|
|
130
|
+
if (!allBlockingReady && this.isDocumentVisible && !mouseMovedRecently) {
|
|
131
|
+
// Pas de mouvement de souris, document visible => message "no activity"
|
|
99
132
|
this.updateOverlayMessage(this.overlayNoActivityMessage, 'waiting-action');
|
|
100
|
-
} else if (mouseMovedRecently
|
|
101
|
-
|
|
133
|
+
} else if (mouseMovedRecently) {
|
|
134
|
+
// Il y a une activité de souris
|
|
135
|
+
if (!allBlockingReady && this.isDocumentVisible) {
|
|
102
136
|
this.updateOverlayMessage(this.overlayStartingMessage, 'waiting');
|
|
103
137
|
}
|
|
104
|
-
if(!this.lastWakeUpTime) {
|
|
138
|
+
if (!this.lastWakeUpTime) {
|
|
105
139
|
this.lastWakeUpTime = Date.now();
|
|
106
140
|
}
|
|
107
141
|
const isWakeUpCallMade = await this.wakeUpPods(data, this.lastWakeUpTime);
|
|
108
|
-
if(isWakeUpCallMade) {
|
|
142
|
+
if (isWakeUpCallMade) {
|
|
109
143
|
this.lastWakeUpTime = Date.now();
|
|
110
144
|
}
|
|
111
|
-
} else if(!this.isDocumentVisible && !
|
|
145
|
+
} else if (!this.isDocumentVisible && !allBlockingReady) {
|
|
146
|
+
// Document caché, pas prêt => message "no activity"
|
|
112
147
|
this.updateOverlayMessage(this.overlayNoActivityMessage, 'waiting');
|
|
113
148
|
}
|
|
114
149
|
} catch (error) {
|
|
115
150
|
const errorMessage = error.message;
|
|
151
|
+
// On garde l'état précédent de readiness en cas d'erreur
|
|
116
152
|
this.setReadyState(this.isReady);
|
|
117
153
|
this.updateOverlayMessage(this.overlayErrorMessage, 'error', this.overlayErrorSecondaryMessage);
|
|
118
154
|
this.errorCallback(errorMessage);
|
|
119
155
|
console.error('Error fetching slimfaas data:', errorMessage);
|
|
120
156
|
} finally {
|
|
121
|
-
if(this.intervalId)
|
|
157
|
+
if (this.intervalId) {
|
|
122
158
|
this.intervalId = setTimeout(() => {
|
|
123
159
|
this.fetchStatus();
|
|
124
160
|
}, this.interval);
|
|
@@ -126,6 +162,9 @@ export default class SlimFaasPlanetSaver {
|
|
|
126
162
|
}
|
|
127
163
|
}
|
|
128
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Met à jour l'état ready. Si ready = true => on cache l'overlay
|
|
167
|
+
*/
|
|
129
168
|
setReadyState(isReady) {
|
|
130
169
|
this.isReady = isReady;
|
|
131
170
|
if (isReady) {
|
|
@@ -135,16 +174,20 @@ export default class SlimFaasPlanetSaver {
|
|
|
135
174
|
}
|
|
136
175
|
}
|
|
137
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Lance le polling régulier
|
|
179
|
+
*/
|
|
138
180
|
startPolling() {
|
|
139
181
|
if (this.intervalId || !this.baseUrl || this.cleanned) return;
|
|
140
|
-
|
|
141
182
|
this.fetchStatus();
|
|
142
|
-
|
|
143
183
|
this.intervalId = setTimeout(() => {
|
|
144
184
|
this.fetchStatus();
|
|
145
185
|
}, this.interval);
|
|
146
186
|
}
|
|
147
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Arrête le polling
|
|
190
|
+
*/
|
|
148
191
|
stopPolling() {
|
|
149
192
|
if (this.intervalId) {
|
|
150
193
|
clearTimeout(this.intervalId);
|
|
@@ -152,6 +195,9 @@ export default class SlimFaasPlanetSaver {
|
|
|
152
195
|
}
|
|
153
196
|
}
|
|
154
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Injecte dans le DOM le style pour l'overlay
|
|
200
|
+
*/
|
|
155
201
|
injectStyles() {
|
|
156
202
|
const cssString = `
|
|
157
203
|
.slimfaas-environment-overlay {
|
|
@@ -222,48 +268,57 @@ export default class SlimFaasPlanetSaver {
|
|
|
222
268
|
document.head.appendChild(this.styleElement);
|
|
223
269
|
}
|
|
224
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Crée dans le DOM l'overlay en lui-même (sans l'ajouter encore)
|
|
273
|
+
*/
|
|
225
274
|
createOverlay() {
|
|
226
275
|
this.overlayElement = document.createElement('div');
|
|
227
276
|
this.overlayElement.className = 'slimfaas-environment-overlay';
|
|
228
277
|
this.overlayElement.id = `slimfaas-environment-overlay-${this.id}`;
|
|
229
278
|
|
|
230
|
-
//
|
|
279
|
+
// Élément icône
|
|
231
280
|
this.iconElement = document.createElement('div');
|
|
232
281
|
this.iconElement.className = 'slimfaas-environment-overlay__icon';
|
|
233
282
|
this.iconElement.innerText = this.overlayLoadingIcon;
|
|
234
283
|
|
|
235
|
-
//
|
|
284
|
+
// Message principal
|
|
236
285
|
this.spanElement = document.createElement('span');
|
|
237
286
|
this.spanElement.className = 'slimfaas-environment-overlay__main-message';
|
|
238
287
|
this.spanElement.innerHTML = `${this.overlayStartingMessage}`;
|
|
239
288
|
|
|
240
|
-
//
|
|
289
|
+
// Message secondaire
|
|
241
290
|
this.secondarySpanElement = document.createElement('span');
|
|
242
291
|
this.secondarySpanElement.className = 'slimfaas-environment-overlay__secondary-message';
|
|
243
292
|
this.secondarySpanElement.innerText = this.overlaySecondaryMessage;
|
|
244
293
|
|
|
245
|
-
//
|
|
294
|
+
// Ajout à l'overlay
|
|
246
295
|
this.overlayElement.appendChild(this.iconElement);
|
|
247
296
|
this.overlayElement.appendChild(this.spanElement);
|
|
248
297
|
this.overlayElement.appendChild(this.secondarySpanElement);
|
|
249
|
-
|
|
250
|
-
// Ne pas ajouter l'overlay au DOM ici
|
|
251
|
-
// document.body.appendChild(this.overlayElement);
|
|
252
298
|
}
|
|
253
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Affiche l'overlay dans la page si nécessaire
|
|
302
|
+
*/
|
|
254
303
|
showOverlay() {
|
|
255
|
-
if(this.cleanned) return;
|
|
304
|
+
if (this.cleanned) return;
|
|
256
305
|
if (this.overlayElement && !document.body.contains(this.overlayElement)) {
|
|
257
306
|
document.body.appendChild(this.overlayElement);
|
|
258
307
|
}
|
|
259
308
|
}
|
|
260
309
|
|
|
310
|
+
/**
|
|
311
|
+
* Cache l'overlay
|
|
312
|
+
*/
|
|
261
313
|
hideOverlay() {
|
|
262
314
|
if (this.overlayElement && document.body.contains(this.overlayElement)) {
|
|
263
315
|
document.body.removeChild(this.overlayElement);
|
|
264
316
|
}
|
|
265
317
|
}
|
|
266
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Met à jour le message affiché dans l'overlay
|
|
321
|
+
*/
|
|
267
322
|
updateOverlayMessage(newMessage, status = 'waiting', secondaryMessage = null) {
|
|
268
323
|
if (this.spanElement) {
|
|
269
324
|
this.spanElement.innerHTML = `${newMessage}`;
|
|
@@ -283,6 +338,9 @@ export default class SlimFaasPlanetSaver {
|
|
|
283
338
|
}
|
|
284
339
|
}
|
|
285
340
|
|
|
341
|
+
/**
|
|
342
|
+
* Nettoie le composant : retire listeners, styles et overlay
|
|
343
|
+
*/
|
|
286
344
|
cleanup() {
|
|
287
345
|
this.cleanned = true;
|
|
288
346
|
this.stopPolling();
|