ffb-vector-search-dialog.component.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { Component, Inject, inject } from '@angular/core';
  2. import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
  3. import { HttpClient } from '@angular/common/http';
  4. import { FormControl, ReactiveFormsModule } from '@angular/forms';
  5. import { CommonModule } from '@angular/common';
  6. import { MatFormFieldModule } from '@angular/material/form-field';
  7. import { MatInputModule } from '@angular/material/input';
  8. import { MatButtonModule } from '@angular/material/button';
  9. import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
  10. import { MatTableModule } from '@angular/material/table';
  11. import { webConfig } from '../../config';
  12. import { MatIconModule } from '@angular/material/icon';
  13. import { FFBProduction } from '../../ffb/ffb-production.interface';
  14. import { CreateFfbProductionDialogComponent } from '../../components/ffb-production-dialog/create-ffb-production-dialog.component';
  15. @Component({
  16. selector: 'app-ffb-vector-search-dialog',
  17. templateUrl: './ffb-vector-search-dialog.component.html',
  18. styleUrls: ['./ffb-vector-search-dialog.component.css'],
  19. standalone: true,
  20. imports: [
  21. CommonModule,
  22. ReactiveFormsModule,
  23. MatFormFieldModule,
  24. MatInputModule,
  25. MatButtonModule,
  26. MatProgressSpinnerModule,
  27. MatTableModule,
  28. MatIconModule,
  29. MatDialogModule
  30. ],
  31. })
  32. export class FfbVectorSearchDialogComponent {
  33. private http = inject(HttpClient);
  34. private dialog = inject(MatDialog);
  35. dialogRef = inject(MatDialogRef<FfbVectorSearchDialogComponent>);
  36. queryControl = new FormControl('');
  37. kControl = new FormControl(5);
  38. loading = false;
  39. results: FFBProduction[] = [];
  40. displayedColumns: string[] = ['productionDate', 'site', 'phase', 'block', 'weight', 'quantity', 'score'];
  41. constructor(@Inject(MAT_DIALOG_DATA) public data: any) { }
  42. search() {
  43. const q = this.queryControl.value?.trim();
  44. const k = this.kControl.value || 5;
  45. if (!q) return;
  46. this.loading = true;
  47. this.results = [];
  48. this.http.get<FFBProduction[]>(`${webConfig.exposedUrl}/api/ffb-production/search?q=${encodeURIComponent(q)}&k=${k}`)
  49. .subscribe({
  50. next: (data) => {
  51. console.log(data)
  52. // Strip vector to save memory/UI
  53. this.results = data.map(h => ({ ...h, vector: undefined, productionDate: new Date(h.productionDate) }));
  54. this.loading = false;
  55. },
  56. error: (err) => {
  57. console.error(err);
  58. this.loading = false;
  59. }
  60. });
  61. }
  62. close() {
  63. this.dialogRef.close();
  64. }
  65. applyResults() {
  66. // Return results to parent
  67. this.dialogRef.close(this.results);
  68. }
  69. formatDate(date: Date | string) {
  70. const d = new Date(date);
  71. return d.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: '2-digit' });
  72. }
  73. openDetails(harvest: FFBProduction) {
  74. const dialogRef = this.dialog.open(CreateFfbProductionDialogComponent, {
  75. width: '800px',
  76. data: {
  77. harvest,
  78. allSites: this.data.allSites || [],
  79. allPhases: this.data.allPhases || [],
  80. allBlocks: this.data.allBlocks || [],
  81. }
  82. });
  83. dialogRef.afterClosed().subscribe(result => {
  84. // Ideally we might want to refresh the search results if edited,
  85. // but for now we just let them close it.
  86. if (result === 'refresh') {
  87. // We could re-trigger search if we want to reflect changes immediately
  88. this.search();
  89. }
  90. });
  91. }
  92. }