This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/release/v1.3/pr-8620-fa0d7ee53079e8ae92c5168779156c513a341ad0 in repository https://gitbox.apache.org/repos/asf/texera.git
commit de57530e9e3ee2176600cdd42d6c85bf0bde4355 Author: Meng Wang <[email protected]> AuthorDate: Mon Sep 21 20:07:41 2026 +0000 fix(frontend, v1.3): refresh a dataset's paths after a rename, and block renaming mid-upload (#8620) ### What changes were proposed in this PR? Backport of #8347 to `release/v1.3`: a clean cherry-pick of its squash commit, no adaptations — the backport commit reuses the squash message and author, as the automated fast path would. See #8347 for the change itself (after a rename the detail page kept serving the old paths, so file preview and single-file download 404'd until a reload; renaming during an upload was also allowed). Opened manually by the v1.3 release manager: the automated fast path cherry-picked this cleanly and then pushed it straight to `release/v1.3`, where the Merge Queue ruleset rejected the push (`GH013`, [run 33706287941](https://github.com/apache/texera/actions/runs/33706287941)). The Actions-app bypass meant to unblock that path (#8379) was never created — asfyaml rejects an `Integration` bypass actor — and the failing job's notification 403s for want of `pull-requests: write`, so the loss left neither a backport PR nor a comment on #8347. See #8377. Source: 4ff0b8b4ac415c4d60bfd73f37da5e3039ade2ec ### Any related issues, documentation, discussions? Backport of #8347. Originally linked #8345. ### How was this PR tested? The change is identical to #8347, which carries the specs (`dataset-detail.component.spec.ts`); the backport tree is verified byte-identical to cherry-picking the squash commit onto `release/v1.3`, and release-branch CI runs the full matrix on this PR. It touches the same three files as #8343's backport; the two apply cleanly onto this branch in either order. ### Was this PR authored or co-authored using generative AI tooling? Yes. Generated-by: Claude Code (claude-opus-5) Co-authored-by: Tanishq Gandhi <[email protected]> --- .../dataset-detail.component.html | 11 +++++- .../dataset-detail.component.spec.ts | 43 ++++++++++++++++++++++ .../dataset-detail.component.ts | 11 ++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.html b/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.html index 5263213bbb..1053ea7c27 100644 --- a/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.html +++ b/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.html @@ -455,7 +455,8 @@ [resourceName]="datasetName" [endpoint]="datasetEndpoint" [createVersion]="createDatasetVersion" - (versionCreated)="onVersionCreated()"> + (versionCreated)="onVersionCreated()" + (uploadsInFlightChange)="uploadsInFlight = $event"> </texera-version-uploader> </div> </nz-sider> @@ -473,14 +474,22 @@ <div class="settings-name-label"> <label>Dataset name</label> <p class="settings-hint">Lowercase letters, numbers and hyphens.</p> + <p + *ngIf="uploadsInFlight" + class="settings-hint"> + An upload is in progress — finish or cancel it in Versions & Files first, or it will be left + incomplete. + </p> </div> <div class="settings-name-controls"> <input nz-input + [disabled]="uploadsInFlight" [(ngModel)]="editedDatasetName" /> <button nz-button nzType="primary" + [disabled]="uploadsInFlight" (click)="onSaveDatasetName()"> Save </button> diff --git a/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.spec.ts b/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.spec.ts index 617ae66559..11be93b137 100644 --- a/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.spec.ts +++ b/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.spec.ts @@ -1544,6 +1544,37 @@ describe("DatasetDetailComponent behavior", () => { expect(datasetServiceStub.updateDatasetName).not.toHaveBeenCalled(); }); + + it("refetches the file tree and the latest-version facts, which both embed the old name", () => { + datasetServiceStub.updateDatasetName.mockReturnValue(of({})); + createComponent(); + component.did = 5; + component.selectedVersion = makeVersion({ dvid: 12 }); + component.editedDatasetName = "new-name"; + datasetServiceStub.retrieveDatasetVersionFileTree.mockClear(); + datasetServiceStub.retrieveDatasetLatestVersion.mockClear(); + + component.onSaveDatasetName(); + + expect(datasetServiceStub.retrieveDatasetVersionFileTree).toHaveBeenCalledWith(5, 12, component.isLogin); + expect(datasetServiceStub.retrieveDatasetLatestVersion).toHaveBeenCalledWith(5); + // The browsed version stays put: a rename is not a reason to jump to the newest one. + expect(component.selectedVersion?.dvid).toBe(12); + }); + + it("refuses to rename while an upload is in flight, which would strand it", () => { + createComponent(); + component.did = 5; + component.uploadsInFlight = true; + component.editedDatasetName = "new-name"; + + component.onSaveDatasetName(); + + expect(datasetServiceStub.updateDatasetName).not.toHaveBeenCalled(); + expect(notificationServiceStub.error).toHaveBeenCalledWith( + "Finish or cancel the upload in progress before renaming this dataset" + ); + }); }); describe("onDeleteDataset", () => { @@ -2521,6 +2552,18 @@ describe("DatasetDetailComponent rendered template", () => { expect(datasetService.updateDatasetDescription).toHaveBeenCalledWith(5, "brand new"); }); + it("locks the name field while an upload is in flight", () => { + const el = render({ did: 5, datasetName: "ds", userDatasetAccessLevel: "WRITE" }); + openTab("Versions & Files"); + + fixture.debugElement.query(By.css("texera-version-uploader")).triggerEventHandler("uploadsInFlightChange", true); + flush(); + openTab("Settings"); + + expect(q<HTMLInputElement>(el, ".settings-name-controls input").disabled).toBe(true); + expect(q<HTMLButtonElement>(el, ".settings-name-controls button").disabled).toBe(true); + }); + it("deletes the dataset only once the confirmation is accepted", () => { const el = render({ did: 5, datasetName: "ds", userDatasetAccessLevel: "WRITE", isOwner: true }); openTab("Settings"); diff --git a/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts b/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts index 72f89eb57b..9d38dab9ad 100644 --- a/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts +++ b/frontend/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts @@ -141,6 +141,7 @@ export class DatasetDetailComponent implements OnInit { public versions: ReadonlyArray<DatasetVersion> = []; public selectedVersion: DatasetVersion | undefined; + public uploadsInFlight = false; public fileTreeNodeList: DatasetFileNode[] = []; public selectedVersionCreationTime: string = ""; // The following three fields describe the latest version for the Data Card, all @@ -599,6 +600,10 @@ export class DatasetDetailComponent implements OnInit { if (!this.did) { return; } + if (this.uploadsInFlight) { + this.notificationService.error("Finish or cancel the upload in progress before renaming this dataset"); + return; + } // Reject invalid names outright instead of silently rewriting them, matching // the shared validation used by the other rename entry points (PR #6426). const name = this.editedDatasetName; @@ -615,6 +620,12 @@ export class DatasetDetailComponent implements OnInit { next: () => { this.datasetName = name; this.editedDatasetName = name; + // Every file path embeds the dataset name, and preview and single-file download resolve + // a dataset by (owner, name) — a stale tree 404s until reload. + if (this.selectedVersion) { + this.onVersionSelected(this.selectedVersion); + } + this.retrieveLatestVersionFile(); this.notificationService.success(`Dataset name updated to '${name}'`); }, error: (err: unknown) => {
