Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,28 @@ object WorkflowResource {

case class WorkflowIDs(wids: List[UInteger], pid: Option[UInteger])

private def updateWorkflowField(
workflow: Workflow,
sessionUser: SessionUser,
updateFunction: Workflow => Unit
): Unit = {
val wid = workflow.getWid
val user = sessionUser.getUser

if (
workflowOfUserExists(wid, user.getUid) || WorkflowAccessResource.hasWriteAccess(
wid,
user.getUid
)
) {
val userWorkflow = workflowDao.fetchOneByWid(wid)
updateFunction(userWorkflow)
workflowDao.update(userWorkflow)
} else {
throw new ForbiddenException("No sufficient access privilege.")
}
}

}
@Produces(Array(MediaType.APPLICATION_JSON))
@RolesAllowed(Array("REGULAR", "ADMIN"))
Expand Down Expand Up @@ -466,11 +488,6 @@ class WorkflowResource extends LazyLogging {
}
}

/**
* This method updates the name of a given workflow
*
* @return Response
*/
@POST
@Consumes(Array(MediaType.APPLICATION_JSON))
@Produces(Array(MediaType.APPLICATION_JSON))
Expand All @@ -479,18 +496,7 @@ class WorkflowResource extends LazyLogging {
workflow: Workflow,
@Auth sessionUser: SessionUser
): Unit = {
val wid = workflow.getWid
val name = workflow.getName
val user = sessionUser.getUser
if (!WorkflowAccessResource.hasWriteAccess(wid, user.getUid)) {
throw new ForbiddenException("No sufficient access privilege.")
} else if (!workflowOfUserExists(wid, user.getUid)) {
throw new BadRequestException("The workflow does not exist.")
} else {
val userWorkflow = workflowDao.fetchOneByWid(wid)
userWorkflow.setName(name)
workflowDao.update(userWorkflow)
}
updateWorkflowField(workflow, sessionUser, _.setName(workflow.getName))
}

@POST
Expand All @@ -501,19 +507,7 @@ class WorkflowResource extends LazyLogging {
workflow: Workflow,
@Auth sessionUser: SessionUser
): Unit = {
val wid = workflow.getWid
val description = workflow.getDescription
val user = sessionUser.getUser

if (!WorkflowAccessResource.hasWriteAccess(wid, user.getUid)) {
throw new ForbiddenException("No sufficient access privilege.")
} else if (!workflowOfUserExists(wid, user.getUid)) {
throw new BadRequestException("The workflow does not exist.")
} else {
val userWorkflow = workflowDao.fetchOneByWid(wid)
userWorkflow.setDescription(description)
workflowDao.update(userWorkflow)
}
updateWorkflowField(workflow, sessionUser, _.setDescription(workflow.getDescription))
}

@PUT
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ListItemComponent } from "./list-item.component";
import { WorkflowPersistService } from "src/app/common/service/workflow-persist/workflow-persist.service";
import { HttpClientTestingModule } from "@angular/common/http/testing";
import { NzModalService } from "ng-zorro-antd/modal";
import { of, throwError } from "rxjs";
import { NO_ERRORS_SCHEMA } from "@angular/core";

describe("ListItemComponent", () => {
let component: ListItemComponent;
let fixture: ComponentFixture<ListItemComponent>;
let workflowPersistService: jasmine.SpyObj<WorkflowPersistService>;
let nzModalService: jasmine.SpyObj<NzModalService>;

beforeEach(async () => {
const workflowPersistServiceSpy = jasmine.createSpyObj("WorkflowPersistService", [
"updateWorkflowName",
"updateWorkflowDescription",
]);
const nzModalServiceSpy = jasmine.createSpyObj("NzModalService", ["create"]);

await TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
declarations: [ListItemComponent],
providers: [
{ provide: WorkflowPersistService, useValue: workflowPersistServiceSpy },
{ provide: NzModalService, useValue: nzModalServiceSpy },
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();

fixture = TestBed.createComponent(ListItemComponent);
component = fixture.componentInstance;
workflowPersistService = TestBed.inject(WorkflowPersistService) as jasmine.SpyObj<WorkflowPersistService>;
nzModalService = TestBed.inject(NzModalService) as jasmine.SpyObj<NzModalService>;
});

it("should update workflow name successfully", () => {
const newName = "New Workflow Name";
component.entry = { id: 1, name: "Old Name" } as any;
workflowPersistService.updateWorkflowName.and.returnValue(of({} as Response));

component.confirmUpdateWorkflowCustomName(newName);

expect(workflowPersistService.updateWorkflowName).toHaveBeenCalledWith(1, newName);
expect(component.entry.name).toBe(newName);
expect(component.editingName).toBeFalse();
});

it("should handle error when updating workflow name", () => {
const newName = "New Workflow Name";
component.entry = { id: 1, name: "Old Name" } as any;
component.originalName = "Old Name";
workflowPersistService.updateWorkflowName.and.returnValue(throwError(() => new Error("Error")));

component.confirmUpdateWorkflowCustomName(newName);

expect(workflowPersistService.updateWorkflowName).toHaveBeenCalledWith(1, newName);
expect(component.entry.name).toBe("Old Name");
expect(component.editingName).toBeFalse();
});

it("should update workflow description successfully", () => {
const newDescription = "New Description";
component.entry = { id: 1, description: "Old Description" } as any;
workflowPersistService.updateWorkflowDescription.and.returnValue(of({} as Response));

component.confirmUpdateWorkflowCustomDescription(newDescription);

expect(workflowPersistService.updateWorkflowDescription).toHaveBeenCalledWith(1, newDescription);
expect(component.entry.description).toBe(newDescription);
expect(component.editingDescription).toBeFalse();
});

it("should handle error when updating workflow description", () => {
const newDescription = "New Description";
component.entry = { id: 1, description: "Old Description" } as any;
component.originalDescription = "Old Description";
workflowPersistService.updateWorkflowDescription.and.returnValue(throwError(() => new Error("Error")));

component.confirmUpdateWorkflowCustomDescription(newDescription);

expect(workflowPersistService.updateWorkflowDescription).toHaveBeenCalledWith(1, newDescription);
expect(component.entry.description).toBe("Old Description");
expect(component.editingDescription).toBeFalse();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import { formatSize } from "src/app/common/util/size-formatter.util";
})
export class ListItemComponent implements OnInit, OnChanges {
private owners: number[] = [];
public originalName: string = "";
public originalDescription: string | undefined = undefined;
@Input() currentUid: number | undefined;
@ViewChild("nameInput") nameInput!: ElementRef;
@ViewChild("descriptionInput") descriptionInput!: ElementRef;
Expand Down Expand Up @@ -159,6 +161,7 @@ export class ListItemComponent implements OnInit, OnChanges {
};

onEditName(): void {
this.originalName = this.entry.name;
this.editingName = true;
setTimeout(() => {
if (this.nameInput) {
Expand All @@ -171,6 +174,7 @@ export class ListItemComponent implements OnInit, OnChanges {
}

onEditDescription(): void {
this.originalDescription = this.entry.description;
this.editingDescription = true;
setTimeout(() => {
if (this.descriptionInput) {
Expand All @@ -182,30 +186,56 @@ export class ListItemComponent implements OnInit, OnChanges {
}, 0);
}

public confirmUpdateWorkflowCustomName(name: string): void {
this.workflowPersistService
.updateWorkflowName(this.entry.id, name || DEFAULT_WORKFLOW_NAME)
private updateWorkflowProperty(
updateMethod: (id: number | undefined, value: string) => any,
propertyName: "name" | "description",
newValue: string,
originalValue: string | undefined
): void {
updateMethod(this.entry.id, newValue)
.pipe(untilDestroyed(this))
.subscribe(() => {
this.entry.name = name || DEFAULT_WORKFLOW_NAME;
})
.add(() => {
this.editingName = false;
.subscribe({
next: () => {
this.entry[propertyName] = newValue;
},
error: (err: unknown) => {
console.error(`Failed to update workflow ${propertyName}:`, err);
// Use a fallback empty string if originalValue is undefined
this.entry[propertyName] = originalValue ?? "";
this.setEditingState(propertyName, false);
},
complete: () => {
this.setEditingState(propertyName, false);
},
});
}

public confirmUpdateWorkflowCustomDescription(description: string | undefined): void {
const updatedDescription = description !== undefined ? description : "";
private setEditingState(propertyName: "name" | "description", state: boolean): void {
if (propertyName === "name") {
this.editingName = state;
} else if (propertyName === "description") {
this.editingDescription = state;
}
}

this.workflowPersistService
.updateWorkflowDescription(this.entry.id, updatedDescription)
.pipe(untilDestroyed(this))
.subscribe(() => {
this.entry.description = updatedDescription;
})
.add(() => {
this.editingDescription = false;
});
public confirmUpdateWorkflowCustomName(name: string): void {
const workflowName = name || DEFAULT_WORKFLOW_NAME;
this.updateWorkflowProperty(
this.workflowPersistService.updateWorkflowName.bind(this.workflowPersistService),
"name",
workflowName,
this.originalName
);
}

public confirmUpdateWorkflowCustomDescription(description: string | undefined): void {
const updatedDescription = description ?? "";
this.updateWorkflowProperty(
this.workflowPersistService.updateWorkflowDescription.bind(this.workflowPersistService),
"description",
updatedDescription,
this.originalDescription
);
}

formatTime(timestamp: number | undefined): string {
Expand Down