ciyidogan commited on
Commit
cf134f3
·
verified ·
1 Parent(s): 25f9893

Update flare-ui/src/app/dialogs/intent-edit-dialog/intent-edit-dialog.component.ts

Browse files
flare-ui/src/app/dialogs/intent-edit-dialog/intent-edit-dialog.component.ts CHANGED
@@ -1,6 +1,6 @@
1
  import { Component, Inject, OnInit } from '@angular/core';
2
  import { CommonModule } from '@angular/common';
3
- import { FormBuilder, FormGroup, FormArray, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms'; // FormsModule EKLE
4
  import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
5
  import { MatFormFieldModule } from '@angular/material/form-field';
6
  import { MatInputModule } from '@angular/material/input';
@@ -14,6 +14,30 @@ import { MatTabsModule } from '@angular/material/tabs';
14
  import { MatExpansionModule } from '@angular/material/expansion';
15
  import { MatListModule } from '@angular/material/list';
16
  import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  @Component({
19
  selector: 'app-intent-edit-dialog',
@@ -21,7 +45,7 @@ import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
21
  imports: [
22
  CommonModule,
23
  ReactiveFormsModule,
24
- FormsModule, // BU SATIRI EKLE
25
  MatDialogModule,
26
  MatFormFieldModule,
27
  MatInputModule,
@@ -44,15 +68,23 @@ export default class IntentEditDialogComponent implements OnInit {
44
  availableAPIs: any[] = [];
45
  parameterTypes = ['str', 'int', 'float', 'bool', 'date'];
46
 
 
 
 
 
 
47
  newExample = '';
48
 
49
  constructor(
50
  private fb: FormBuilder,
51
  private snackBar: MatSnackBar,
 
52
  public dialogRef: MatDialogRef<IntentEditDialogComponent>,
53
  @Inject(MAT_DIALOG_DATA) public data: any
54
  ) {
55
  this.availableAPIs = data.apis || [];
 
 
56
  }
57
 
58
  ngOnInit() {
@@ -66,9 +98,7 @@ export default class IntentEditDialogComponent implements OnInit {
66
  this.form = this.fb.group({
67
  name: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9-]+$/)]],
68
  caption: ['', Validators.required],
69
- locale: ['tr-TR'],
70
  detection_prompt: ['', Validators.required],
71
- examples: this.fb.array([]),
72
  parameters: this.fb.array([]),
73
  action: ['', Validators.required],
74
  fallback_timeout_prompt: [''],
@@ -77,146 +107,191 @@ export default class IntentEditDialogComponent implements OnInit {
77
  }
78
 
79
  populateForm(intent: any) {
80
- // Önce basit alanları doldur
81
  this.form.patchValue({
82
  name: intent.name || '',
83
  caption: intent.caption || '',
84
- locale: intent.locale || 'tr-TR',
85
  detection_prompt: intent.detection_prompt || '',
86
  action: intent.action || '',
87
  fallback_timeout_prompt: intent.fallback_timeout_prompt || '',
88
  fallback_error_prompt: intent.fallback_error_prompt || ''
89
  });
90
 
91
- // Examples array'ini doldur
92
  if (intent.examples && Array.isArray(intent.examples)) {
93
- const examplesArray = this.form.get('examples') as FormArray;
94
- examplesArray.clear();
95
- intent.examples.forEach((example: string) => {
96
- if (typeof example === 'string') {
97
- examplesArray.push(this.fb.control(example));
98
- }
99
- });
 
 
 
100
  }
101
 
102
- // Parameters array'ini doldur
103
  if (intent.parameters && Array.isArray(intent.parameters)) {
104
- const parametersArray = this.form.get('parameters') as FormArray;
105
- parametersArray.clear();
 
106
  intent.parameters.forEach((param: any) => {
107
- parametersArray.push(this.createParameterFormGroup(param));
108
  });
109
  }
110
  }
111
 
112
- createParameterFormGroup(param: any = {}): FormGroup {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  return this.fb.group({
114
- name: [param.name || '', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_]+$/)]],
115
- caption: [param.caption || '', Validators.required], // ✅ Validators.required ekle
116
- type: [param.type || 'str', Validators.required],
117
- required: [param.required !== false],
118
- variable_name: [param.variable_name || '', Validators.required],
119
- extraction_prompt: [param.extraction_prompt || ''],
120
- validation_regex: [param.validation_regex || ''],
121
- invalid_prompt: [param.invalid_prompt || ''],
122
- type_error_prompt: [param.type_error_prompt || '']
123
  });
124
  }
125
 
126
- get examples() {
127
- return this.form.get('examples') as FormArray;
128
  }
129
 
130
- get parameters(): FormArray {
131
- return this.form.get('parameters') as FormArray || this.fb.array([]);
132
  }
133
 
134
- addExample() {
135
- const trimmedExample = this.newExample?.trim();
136
- if (trimmedExample) {
137
- this.examples.push(this.fb.control(trimmedExample));
138
- this.newExample = '';
139
- }
140
  }
141
-
142
- removeExample(index: number) {
143
- this.examples.removeAt(index);
 
144
  }
145
 
146
- addParameter() {
147
- const parametersArray = this.form.get('parameters') as FormArray;
148
- parametersArray.push(this.createParameterFormGroup());
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
150
-
151
- removeParameter(index: number) {
152
- this.parameters.removeAt(index);
 
 
 
 
 
153
  }
154
 
155
- moveParameter(index: number, direction: 'up' | 'down') {
156
- const parametersArray = this.form.get('parameters') as FormArray;
157
- const newIndex = direction === 'up' ? index - 1 : index + 1;
158
 
159
- if (newIndex >= 0 && newIndex < parametersArray.length) {
160
- const param = parametersArray.at(index);
161
- parametersArray.removeAt(index);
162
- parametersArray.insert(newIndex, param);
163
- }
 
164
  }
165
 
166
- async testRegex(index: number) {
167
- const param = this.parameters.at(index);
168
- const regex = param.get('validation_regex')?.value;
169
 
170
- if (!regex) {
171
- this.snackBar.open('No regex pattern to test', 'Close', { duration: 2000 });
172
- return;
173
- }
 
 
 
 
 
 
 
174
 
175
- const testValue = prompt('Enter a test value:');
176
- if (testValue !== null) {
177
- try {
178
- const pattern = new RegExp(regex);
179
- const matches = pattern.test(testValue);
180
-
181
- this.snackBar.open(
182
- matches ? '✓ Pattern matches!' : '✗ Pattern does not match',
183
- 'Close',
184
- { duration: 3000 }
185
- );
186
- } catch (error) {
187
- this.snackBar.open('Invalid regex pattern', 'Close', {
188
- duration: 3000,
189
- panelClass: 'error-snackbar'
190
- });
191
  }
192
- }
193
  }
194
 
195
- save() {
196
- if (this.form.invalid) {
197
- this.snackBar.open('Please fix all validation errors', 'Close', { duration: 3000 });
198
- return;
199
- }
200
-
201
- const formValue = this.form.value;
202
-
203
- // Form değerlerini güvenli bir şekilde al
204
- const result = {
205
- name: formValue.name || '',
206
- caption: formValue.caption || '',
207
- locale: formValue.locale || 'tr-TR',
208
- detection_prompt: formValue.detection_prompt || '',
209
- action: formValue.action || '',
210
- fallback_timeout_prompt: formValue.fallback_timeout_prompt || '',
211
- fallback_error_prompt: formValue.fallback_error_prompt || '',
212
- examples: Array.isArray(formValue.examples) ? formValue.examples : [],
213
- parameters: Array.isArray(formValue.parameters) ? formValue.parameters : []
214
  };
215
-
216
- this.dialogRef.close(result);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  }
218
 
219
  cancel() {
220
- this.dialogRef.close(null);
221
  }
222
  }
 
1
  import { Component, Inject, OnInit } from '@angular/core';
2
  import { CommonModule } from '@angular/common';
3
+ import { FormBuilder, FormGroup, FormArray, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
4
  import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
5
  import { MatFormFieldModule } from '@angular/material/form-field';
6
  import { MatInputModule } from '@angular/material/input';
 
14
  import { MatExpansionModule } from '@angular/material/expansion';
15
  import { MatListModule } from '@angular/material/list';
16
  import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
17
+ import { MatDialog } from '@angular/material/dialog';
18
+
19
+ // Interfaces for multi-language support
20
+ interface LocalizedExample {
21
+ locale_code: string;
22
+ example: string;
23
+ }
24
+
25
+ interface LocalizedCaption {
26
+ locale_code: string;
27
+ caption: string;
28
+ }
29
+
30
+ interface ParameterWithLocalizedCaption {
31
+ name: string;
32
+ caption: LocalizedCaption[];
33
+ type: string;
34
+ required: boolean;
35
+ variable_name: string;
36
+ extraction_prompt?: string;
37
+ validation_regex?: string;
38
+ invalid_prompt?: string;
39
+ type_error_prompt?: string;
40
+ }
41
 
42
  @Component({
43
  selector: 'app-intent-edit-dialog',
 
45
  imports: [
46
  CommonModule,
47
  ReactiveFormsModule,
48
+ FormsModule,
49
  MatDialogModule,
50
  MatFormFieldModule,
51
  MatInputModule,
 
68
  availableAPIs: any[] = [];
69
  parameterTypes = ['str', 'int', 'float', 'bool', 'date'];
70
 
71
+ // Multi-language support
72
+ supportedLocales: string[] = [];
73
+ selectedExampleLocale: string = '';
74
+ examples: LocalizedExample[] = [];
75
+
76
  newExample = '';
77
 
78
  constructor(
79
  private fb: FormBuilder,
80
  private snackBar: MatSnackBar,
81
+ private dialog: MatDialog,
82
  public dialogRef: MatDialogRef<IntentEditDialogComponent>,
83
  @Inject(MAT_DIALOG_DATA) public data: any
84
  ) {
85
  this.availableAPIs = data.apis || [];
86
+ this.supportedLocales = data.supportedLocales || ['tr'];
87
+ this.selectedExampleLocale = data.defaultLocale || this.supportedLocales[0] || 'tr';
88
  }
89
 
90
  ngOnInit() {
 
98
  this.form = this.fb.group({
99
  name: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9-]+$/)]],
100
  caption: ['', Validators.required],
 
101
  detection_prompt: ['', Validators.required],
 
102
  parameters: this.fb.array([]),
103
  action: ['', Validators.required],
104
  fallback_timeout_prompt: [''],
 
107
  }
108
 
109
  populateForm(intent: any) {
110
+ // Populate basic fields
111
  this.form.patchValue({
112
  name: intent.name || '',
113
  caption: intent.caption || '',
 
114
  detection_prompt: intent.detection_prompt || '',
115
  action: intent.action || '',
116
  fallback_timeout_prompt: intent.fallback_timeout_prompt || '',
117
  fallback_error_prompt: intent.fallback_error_prompt || ''
118
  });
119
 
120
+ // Populate localized examples
121
  if (intent.examples && Array.isArray(intent.examples)) {
122
+ if (intent.examples.length > 0 && typeof intent.examples[0] === 'object' && 'locale_code' in intent.examples[0]) {
123
+ // New format with LocalizedExample
124
+ this.examples = [...intent.examples];
125
+ } else if (typeof intent.examples[0] === 'string') {
126
+ // Old format - convert to new format using default locale
127
+ this.examples = intent.examples.map((ex: string) => ({
128
+ locale_code: this.selectedExampleLocale,
129
+ example: ex
130
+ }));
131
+ }
132
  }
133
 
134
+ // Populate parameters with localized captions
135
  if (intent.parameters && Array.isArray(intent.parameters)) {
136
+ const paramsArray = this.form.get('parameters') as FormArray;
137
+ paramsArray.clear();
138
+
139
  intent.parameters.forEach((param: any) => {
140
+ paramsArray.push(this.createParameterFormGroup(param));
141
  });
142
  }
143
  }
144
 
145
+ createParameterFormGroup(param?: any): FormGroup {
146
+ // Convert old caption format to new if needed
147
+ let captionArray: LocalizedCaption[] = [];
148
+ if (param?.caption) {
149
+ if (Array.isArray(param.caption)) {
150
+ captionArray = param.caption;
151
+ } else if (typeof param.caption === 'string') {
152
+ // Old format - convert to new
153
+ captionArray = [{
154
+ locale_code: this.selectedExampleLocale,
155
+ caption: param.caption
156
+ }];
157
+ }
158
+ }
159
+
160
  return this.fb.group({
161
+ name: [param?.name || '', Validators.required],
162
+ caption: [captionArray],
163
+ type: [param?.type || 'str', Validators.required],
164
+ required: [param?.required !== false],
165
+ variable_name: [param?.variable_name || '', Validators.required],
166
+ extraction_prompt: [param?.extraction_prompt || ''],
167
+ validation_regex: [param?.validation_regex || ''],
168
+ invalid_prompt: [param?.invalid_prompt || ''],
169
+ type_error_prompt: [param?.type_error_prompt || '']
170
  });
171
  }
172
 
173
+ get parameters() {
174
+ return this.form.get('parameters') as FormArray;
175
  }
176
 
177
+ addParameter() {
178
+ this.parameters.push(this.createParameterFormGroup());
179
  }
180
 
181
+ removeParameter(index: number) {
182
+ this.parameters.removeAt(index);
 
 
 
 
183
  }
184
+
185
+ // Multi-language example management
186
+ getExamplesForCurrentLocale(): LocalizedExample[] {
187
+ return this.examples.filter(ex => ex.locale_code === this.selectedExampleLocale);
188
  }
189
 
190
+ addExample() {
191
+ if (this.newExample.trim()) {
192
+ const existingIndex = this.examples.findIndex(
193
+ ex => ex.locale_code === this.selectedExampleLocale && ex.example === this.newExample.trim()
194
+ );
195
+
196
+ if (existingIndex === -1) {
197
+ this.examples.push({
198
+ locale_code: this.selectedExampleLocale,
199
+ example: this.newExample.trim()
200
+ });
201
+ this.newExample = '';
202
+ } else {
203
+ this.snackBar.open('This example already exists for this locale', 'Close', { duration: 3000 });
204
+ }
205
+ }
206
  }
207
+
208
+ removeExample(example: LocalizedExample) {
209
+ const index = this.examples.findIndex(
210
+ ex => ex.locale_code === example.locale_code && ex.example === example.example
211
+ );
212
+ if (index !== -1) {
213
+ this.examples.splice(index, 1);
214
+ }
215
  }
216
 
217
+ // Parameter caption management
218
+ getCaptionDisplay(captions: LocalizedCaption[]): string {
219
+ if (!captions || captions.length === 0) return '(No caption)';
220
 
221
+ // Try to find caption for default locale
222
+ const defaultCaption = captions.find(c => c.locale_code === (this.data.defaultLocale || 'tr'));
223
+ if (defaultCaption) return defaultCaption.caption;
224
+
225
+ // Return first available caption
226
+ return captions[0].caption;
227
  }
228
 
229
+ async openCaptionDialog(paramIndex: number) {
230
+ const param = this.parameters.at(paramIndex);
231
+ const currentCaptions = param.get('caption')?.value || [];
232
 
233
+ // Import and open caption dialog
234
+ const { default: CaptionDialogComponent } = await import('./caption-dialog.component');
235
+
236
+ const dialogRef = this.dialog.open(CaptionDialogComponent, {
237
+ width: '600px',
238
+ data: {
239
+ captions: [...currentCaptions],
240
+ supportedLocales: this.supportedLocales,
241
+ defaultLocale: this.data.defaultLocale
242
+ }
243
+ });
244
 
245
+ dialogRef.afterClosed().subscribe(result => {
246
+ if (result) {
247
+ param.patchValue({ caption: result });
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  }
249
+ });
250
  }
251
 
252
+ // Locale helpers
253
+ getLocaleName(localeCode: string): string {
254
+ const localeNames: { [key: string]: string } = {
255
+ 'tr': 'Türkçe',
256
+ 'en': 'English',
257
+ 'de': 'Deutsch',
258
+ 'fr': 'Français',
259
+ 'es': 'Español',
260
+ 'ar': 'العربية',
261
+ 'ru': 'Русский',
262
+ 'zh': '中文',
263
+ 'ja': '日本語',
264
+ 'ko': '한국어'
 
 
 
 
 
 
265
  };
266
+ return localeNames[localeCode] || localeCode;
267
+ }
268
+
269
+ onSubmit() {
270
+ if (this.form.valid) {
271
+ const formValue = this.form.value;
272
+
273
+ // Add examples to the result
274
+ formValue.examples = this.examples;
275
+
276
+ // Ensure all parameters have captions
277
+ formValue.parameters = formValue.parameters.map((param: any) => {
278
+ if (!param.caption || param.caption.length === 0) {
279
+ // Create default caption if missing
280
+ param.caption = [{
281
+ locale_code: this.data.defaultLocale || 'tr',
282
+ caption: param.name
283
+ }];
284
+ }
285
+ return param;
286
+ });
287
+
288
+ this.dialogRef.close(formValue);
289
+ } else {
290
+ this.snackBar.open('Please fill all required fields', 'Close', { duration: 3000 });
291
+ }
292
  }
293
 
294
  cancel() {
295
+ this.dialogRef.close();
296
  }
297
  }