gracecluvohio commented on code in PR #4331:
URL: https://github.com/apache/texera/pull/4331#discussion_r3036246295


##########
frontend/src/app/dashboard/component/user/user-computing-unit/user-computing-unit.component.ts:
##########
@@ -17,11 +17,371 @@
  * under the License.
  */
 
-import { Component } from "@angular/core";
+import { Component, Input, OnInit } from "@angular/core";
+import { ComputingUnitStatusService } from 
"../../../../workspace/service/computing-unit-status/computing-unit-status.service";
+import { DashboardEntry } from "../../../type/dashboard-entry";
+import {
+  DashboardWorkflowComputingUnit,
+  WorkflowComputingUnitType,
+} from "../../../../workspace/types/workflow-computing-unit";
+import { extractErrorMessage } from "../../../../common/util/error";
+import { NotificationService } from 
"../../../../common/service/notification/notification.service";
+import { NzModalService } from "ng-zorro-antd/modal";
+import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";
+import { UserService } from "../../../../common/service/user/user.service";
+import { WorkflowComputingUnitManagingService } from 
"../../../../workspace/service/workflow-computing-unit/workflow-computing-unit-managing.service";
+import {
+  parseResourceUnit,
+  parseResourceNumber,
+  findNearestValidStep,
+  unitTypeMessageTemplate,
+} from "../../../../common/util/computing-unit.util";
 
+@UntilDestroy()
 @Component({
   selector: "texera-computing-unit-section",
   templateUrl: "user-computing-unit.component.html",
   styleUrls: ["user-computing-unit.component.scss"],
 })
-export class UserComputingUnitComponent {}
+export class UserComputingUnitComponent implements OnInit {
+  public entries: DashboardEntry[] = [];
+  public isLogin = this.userService.isLogin();
+  public currentUid = this.userService.getCurrentUser()?.uid;
+  @Input() editable = false;
+
+  allComputingUnits: DashboardWorkflowComputingUnit[] = [];
+
+  // variables for creating a computing unit
+  addComputeUnitModalVisible = false;
+  newComputingUnitName: string = "";
+  selectedMemory: string = "";
+  selectedCpu: string = "";
+  selectedGpu: string = "0"; // Default to no GPU
+  selectedJvmMemorySize: string = "1G"; // Initial JVM memory size
+  selectedComputingUnitType?: WorkflowComputingUnitType; // Selected computing 
unit type
+  selectedShmSize: string = "64Mi"; // Shared memory size
+  shmSizeValue: number = 64; // default to 64
+  shmSizeUnit: "Mi" | "Gi" = "Mi"; // default unit
+  availableComputingUnitTypes: WorkflowComputingUnitType[] = [];
+  localComputingUnitUri: string = ""; // URI for local computing unit
+
+  // JVM memory slider configuration
+  jvmMemorySliderValue: number = 1; // Initial value in GB
+  jvmMemoryMarks: { [key: number]: string } = { 1: "1G" };
+  jvmMemoryMax: number = 1;
+  jvmMemorySteps: number[] = [1]; // Available steps in binary progression 
(1,2,4,8...)
+  showJvmMemorySlider: boolean = false; // Whether to show the slider
+
+  // cpu&memory limit options from backend
+  cpuOptions: string[] = [];
+  memoryOptions: string[] = [];
+  gpuOptions: string[] = []; // Add GPU options array
+
+  constructor(
+    private notificationService: NotificationService,
+    private modalService: NzModalService,
+    private userService: UserService,
+    private computingUnitService: WorkflowComputingUnitManagingService,
+    private computingUnitStatusService: ComputingUnitStatusService
+  ) {
+    this.userService
+      .userChanged()
+      .pipe(untilDestroyed(this))
+      .subscribe(() => {
+        this.isLogin = this.userService.isLogin();
+        this.currentUid = this.userService.getCurrentUser()?.uid;
+      });
+  }
+
+  ngOnInit() {
+    this.newComputingUnitName = "My Computing Unit";
+    this.computingUnitService
+      .getComputingUnitTypes()
+      .pipe(untilDestroyed(this))
+      .subscribe({
+        next: ({ typeOptions }) => {
+          this.availableComputingUnitTypes = typeOptions;
+          // Set default selected type if available
+          if (typeOptions.includes("kubernetes")) {
+            this.selectedComputingUnitType = "kubernetes";
+          } else if (typeOptions.length > 0) {
+            this.selectedComputingUnitType = typeOptions[0];
+          }
+        },
+        error: (err: unknown) =>
+          this.notificationService.error(`Failed to fetch computing unit 
types: ${extractErrorMessage(err)}`),
+      });
+
+    this.computingUnitService
+      .getComputingUnitLimitOptions()
+      .pipe(untilDestroyed(this))
+      .subscribe({
+        next: ({ cpuLimitOptions, memoryLimitOptions, gpuLimitOptions }) => {
+          this.cpuOptions = cpuLimitOptions;
+          this.memoryOptions = memoryLimitOptions;
+          this.gpuOptions = gpuLimitOptions;
+
+          // fallback defaults
+          this.selectedCpu = this.cpuOptions[0] ?? "1";
+          this.selectedMemory = this.memoryOptions[0] ?? "1Gi";
+          this.selectedGpu = this.gpuOptions[0] ?? "0";
+
+          // Initialize JVM memory slider based on selected memory
+          this.updateJvmMemorySlider();
+        },
+        error: (err: unknown) =>
+          this.notificationService.error(`Failed to fetch resource options: 
${extractErrorMessage(err)}`),
+      });
+
+    this.computingUnitStatusService
+      .getAllComputingUnits()
+      .pipe(untilDestroyed(this))
+      .subscribe(units => {
+        this.allComputingUnits = units;
+        this.entries = units.map(u => new DashboardEntry(u));
+      });
+  }
+
+  terminateComputingUnit(cuid: number): void {
+    const unit = this.allComputingUnits.find(u => u.computingUnit.cuid === 
cuid);
+
+    if (!unit || !unit.computingUnit.uri) {
+      this.notificationService.error("Invalid computing unit.");
+      return;
+    }
+
+    const unitName = unit.computingUnit.name;
+    const unitType = unit?.computingUnit.type || "kubernetes"; // fallback
+    const templates = unitTypeMessageTemplate[unitType];
+
+    // Show confirmation modal
+    this.modalService.confirm({
+      nzTitle: templates.terminateTitle,
+      nzContent: templates.terminateWarning
+        ? `
+      <p>Are you sure you want to terminate <strong>${unitName}</strong>?</p>
+      ${templates.terminateWarning}
+    `
+        : `
+      <p>Are you sure you want to disconnect from 
<strong>${unitName}</strong>?</p>
+    `,
+      nzOkText: unitType === "local" ? "Disconnect" : "Terminate",
+      nzOkType: "primary",
+      nzOnOk: () => {
+        // Use the ComputingUnitStatusService to handle termination
+        // This will properly close the websocket before terminating the unit
+        this.computingUnitStatusService
+          .terminateComputingUnit(cuid)
+          .pipe(untilDestroyed(this))
+          .subscribe({
+            next: (success: boolean) => {
+              if (success) {
+                this.notificationService.success(`Terminated Computing Unit: 
${unitName}`);
+              } else {
+                this.notificationService.error("Failed to terminate computing 
unit");
+              }
+            },
+            error: (err: unknown) => {
+              this.notificationService.error(`Failed to terminate computing 
unit: ${extractErrorMessage(err)}`);
+            },
+          });
+      },
+      nzCancelText: "Cancel",
+    });
+  }
+
+  startComputingUnit(): void {
+    // Validate based on computing unit type
+    if (this.selectedComputingUnitType === "kubernetes") {
+      if (this.newComputingUnitName.trim() == "") {
+        this.notificationService.error("Name of the computing unit cannot be 
empty");
+        return;
+      }
+
+      this.selectedShmSize = `${this.shmSizeValue}${this.shmSizeUnit}`;
+
+      this.computingUnitService
+        .createKubernetesBasedComputingUnit(
+          this.newComputingUnitName,
+          this.selectedCpu,
+          this.selectedMemory,
+          this.selectedGpu,
+          this.selectedJvmMemorySize,
+          this.selectedShmSize
+        )

Review Comment:
   There is already a check for this



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to