1
- import { Component , OnDestroy , OnInit } from '@angular/core' ;
1
+ import { Component , OnDestroy , OnInit , TemplateRef , ViewChild } from '@angular/core' ;
2
2
import { StateService } from '../../core-nlp/state.service' ;
3
3
import { RestService } from '../../core-nlp/rest/rest.service' ;
4
4
import { NbDialogService , NbToastrService , NbWindowService } from '@nebular/theme' ;
5
5
import { BotConfigurationService } from '../../core/bot-configuration.service' ;
6
6
import { Observable , Subject , debounceTime , takeUntil } from 'rxjs' ;
7
7
import { BotApplicationConfiguration } from '../../core/model/configuration' ;
8
8
import { FormControl , FormGroup , Validators } from '@angular/forms' ;
9
- import { ObservabilityProvider , ProvidersConfiguration , ProvidersConfigurations } from './models/providers-configuration' ;
9
+ import {
10
+ ObservabilityProvider ,
11
+ ProvidersConfiguration ,
12
+ ProvidersConfigurationParam ,
13
+ ProvidersConfigurations
14
+ } from './models/providers-configuration' ;
10
15
import { ObservabilitySettings } from './models/observability-settings' ;
11
- import { deepCopy } from '../../shared/utils' ;
16
+ import { deepCopy , getExportFileName , readFileAsText } from '../../shared/utils' ;
12
17
import { ChoiceDialogComponent , DebugViewerWindowComponent } from '../../shared/components' ;
18
+ import { saveAs } from 'file-saver-es' ;
19
+ import { FileValidators } from '../../shared/validators' ;
13
20
14
21
interface ObservabilitySettingsForm {
15
22
id : FormControl < string > ;
@@ -36,6 +43,9 @@ export class ObservabilitySettingsComponent implements OnInit, OnDestroy {
36
43
37
44
settingsBackup : ObservabilitySettings ;
38
45
46
+ @ViewChild ( 'exportConfirmationModal' ) exportConfirmationModal : TemplateRef < any > ;
47
+ @ViewChild ( 'importModal' ) importModal : TemplateRef < any > ;
48
+
39
49
constructor (
40
50
private state : StateService ,
41
51
private rest : RestService ,
@@ -59,9 +69,14 @@ export class ObservabilitySettingsComponent implements OnInit, OnDestroy {
59
69
60
70
this . botConfiguration . configurations . pipe ( takeUntil ( this . destroy$ ) ) . subscribe ( ( confs : BotApplicationConfiguration [ ] ) => {
61
71
delete this . settingsBackup ;
72
+
73
+ // Reset form on configuration change
74
+ this . form . reset ( ) ;
75
+ // Reset formGroup control too, if any
76
+ this . resetFormGroupControls ( ) ;
77
+
62
78
this . loading = true ;
63
79
this . configurations = confs ;
64
- this . form . reset ( ) ;
65
80
66
81
if ( confs . length ) {
67
82
this . getObservabilitySettingsLoader ( ) . subscribe ( ( res ) => {
@@ -136,10 +151,7 @@ export class ObservabilitySettingsComponent implements OnInit, OnDestroy {
136
151
137
152
if ( requiredConfiguration ) {
138
153
// Purge existing controls that may contain values incompatible with a new control with the same name if provider change
139
- const existingGroupKeys = Object . keys ( this . form . controls [ 'setting' ] . controls ) ;
140
- existingGroupKeys . forEach ( ( key ) => {
141
- this . form . controls [ 'setting' ] . removeControl ( key ) ;
142
- } ) ;
154
+ this . resetFormGroupControls ( ) ;
143
155
144
156
requiredConfiguration . params . forEach ( ( param ) => {
145
157
this . form . controls [ 'setting' ] . addControl ( param . key , new FormControl ( param . defaultValue , Validators . required ) ) ;
@@ -149,6 +161,13 @@ export class ObservabilitySettingsComponent implements OnInit, OnDestroy {
149
161
}
150
162
}
151
163
164
+ resetFormGroupControls ( ) {
165
+ const existingGroupKeys = Object . keys ( this . form . controls [ 'setting' ] . controls ) ;
166
+ existingGroupKeys . forEach ( ( key ) => {
167
+ this . form . controls [ 'setting' ] . removeControl ( key ) ;
168
+ } ) ;
169
+ }
170
+
152
171
cancel ( ) : void {
153
172
this . initForm ( this . settingsBackup ) ;
154
173
}
@@ -196,6 +215,144 @@ export class ObservabilitySettingsComponent implements OnInit, OnDestroy {
196
215
}
197
216
}
198
217
218
+ get hasExportableData ( ) : boolean {
219
+ if ( this . observabilityProvider . value ) return true ;
220
+
221
+ const formValue : ObservabilitySettings = deepCopy ( this . form . value ) as unknown as ObservabilitySettings ;
222
+
223
+ return Object . values ( formValue ) . some ( ( entry ) => {
224
+ return entry && ( typeof entry !== 'object' || Object . keys ( entry ) . length !== 0 ) ;
225
+ } ) ;
226
+ }
227
+
228
+ sensitiveParams : { label : string ; key : string ; include : boolean ; param : ProvidersConfigurationParam } [ ] ;
229
+
230
+ exportSettings ( ) {
231
+ this . sensitiveParams = [ ] ;
232
+
233
+ const shouldConfirm =
234
+ this . observabilityProvider . value &&
235
+ this . currentObservabilityProvider . params . some ( ( entry ) => {
236
+ return entry . confirmExport ;
237
+ } ) ;
238
+
239
+ if ( shouldConfirm ) {
240
+ this . currentObservabilityProvider . params . forEach ( ( entry ) => {
241
+ if ( entry . confirmExport ) {
242
+ this . sensitiveParams . push ( { label : 'Observability provider' , key : 'setting' , include : false , param : entry } ) ;
243
+ }
244
+ } ) ;
245
+
246
+ this . exportConfirmationModalRef = this . nbDialogService . open ( this . exportConfirmationModal ) ;
247
+ } else {
248
+ this . downloadSettings ( ) ;
249
+ }
250
+ }
251
+
252
+ exportConfirmationModalRef ;
253
+
254
+ closeExportConfirmationModal ( ) {
255
+ this . exportConfirmationModalRef . close ( ) ;
256
+ }
257
+
258
+ confirmExportSettings ( ) {
259
+ this . downloadSettings ( ) ;
260
+ this . closeExportConfirmationModal ( ) ;
261
+ }
262
+
263
+ downloadSettings ( ) {
264
+ const formValue : ObservabilitySettings = deepCopy ( this . form . value ) as unknown as ObservabilitySettings ;
265
+ delete formValue [ 'observabilityProvider' ] ;
266
+ delete formValue [ 'id' ] ;
267
+ delete formValue [ 'enabled' ] ;
268
+
269
+ if ( this . sensitiveParams ?. length ) {
270
+ this . sensitiveParams . forEach ( ( sensitiveParam ) => {
271
+ if ( ! sensitiveParam . include ) {
272
+ delete formValue [ sensitiveParam . key ] [ sensitiveParam . param . key ] ;
273
+ }
274
+ } ) ;
275
+ }
276
+
277
+ const jsonBlob = new Blob ( [ JSON . stringify ( formValue ) ] , {
278
+ type : 'application/json'
279
+ } ) ;
280
+
281
+ const exportFileName = getExportFileName (
282
+ this . state . currentApplication . namespace ,
283
+ this . state . currentApplication . name ,
284
+ 'Observability settings' ,
285
+ 'json'
286
+ ) ;
287
+
288
+ saveAs ( jsonBlob , exportFileName ) ;
289
+
290
+ this . toastrService . show ( `Observability settings dump provided` , 'Observability settings dump' , {
291
+ duration : 3000 ,
292
+ status : 'success'
293
+ } ) ;
294
+ }
295
+
296
+ importModalRef ;
297
+
298
+ importSettings ( ) {
299
+ this . isImportSubmitted = false ;
300
+ this . importForm . reset ( ) ;
301
+ this . importModalRef = this . nbDialogService . open ( this . importModal ) ;
302
+ }
303
+
304
+ closeImportModal ( ) {
305
+ this . importModalRef . close ( ) ;
306
+ }
307
+
308
+ isImportSubmitted : boolean = false ;
309
+
310
+ importForm : FormGroup = new FormGroup ( {
311
+ fileSource : new FormControl < File [ ] > ( [ ] , {
312
+ nonNullable : true ,
313
+ validators : [ Validators . required , FileValidators . mimeTypeSupported ( [ 'application/json' ] ) ]
314
+ } )
315
+ } ) ;
316
+
317
+ get fileSource ( ) : FormControl {
318
+ return this . importForm . get ( 'fileSource' ) as FormControl ;
319
+ }
320
+
321
+ get canSaveImport ( ) : boolean {
322
+ return this . isImportSubmitted ? this . importForm . valid : this . importForm . dirty ;
323
+ }
324
+
325
+ submitImportSettings ( ) {
326
+ this . isImportSubmitted = true ;
327
+ if ( this . canSaveImport ) {
328
+ const file = this . fileSource . value [ 0 ] ;
329
+
330
+ readFileAsText ( file ) . then ( ( fileContent ) => {
331
+ const settings = JSON . parse ( fileContent . data ) ;
332
+
333
+ const hasCompatibleProvider =
334
+ settings . setting ?. provider && Object . values ( ObservabilityProvider ) . includes ( settings . setting . provider ) ;
335
+
336
+ if ( ! hasCompatibleProvider ) {
337
+ this . toastrService . show (
338
+ `The file supplied does not reference a compatible provider. Please check the file.` ,
339
+ 'Observability settings import fails' ,
340
+ {
341
+ duration : 6000 ,
342
+ status : 'danger'
343
+ }
344
+ ) ;
345
+ return ;
346
+ }
347
+
348
+ this . initForm ( settings ) ;
349
+ this . form . markAsDirty ( ) ;
350
+
351
+ this . closeImportModal ( ) ;
352
+ } ) ;
353
+ }
354
+ }
355
+
199
356
confirmSettingsDeletion ( ) {
200
357
const confirmAction = 'Delete' ;
201
358
const cancelAction = 'Cancel' ;
0 commit comments