This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-8693-fcaf27a561bc0d29bad052b191062019f75eafa1
in repository https://gitbox.apache.org/repos/asf/texera.git

commit 662387be647006356ed45e45ab988140bf178b94
Author: Xinyuan Lin <[email protected]>
AuthorDate: Sun Sep 27 22:07:51 2026 +0000

    refactor(frontend): remove the legacy user-file types (#8693)
    
    ### What changes were proposed in this PR?
    
    Removes the frontend type layer for "user files", a dashboard entry kind
    the backend has not served since #2781. **+127/−337 lines.** There is no
    behaviour change for workflow, dataset or model entries.
    
    - **Types:** `DashboardFile`, `UserFile` and the duplicate `SortMethod`
    enum in `dashboard-file.interface.ts`. `FileUploadItem` stays, since the
    uploaders use it.
    - **Dashboard entry:** `isDashboardFile`, the file branch and `file`
    getter of `DashboardEntry`, and `SearchResultItem.file` with its two
    readers (search-bar `convertToName`, search-service result filter).
    - **Registry:** `FileResourceDescriptor` and its wiring in
    `ResourceRegistryService`, plus `EntityType.File`.
    - **Search types:** `"file"` in the search resource-type unions and
    their JSDoc. `DashboardResource` throws `Unknown resource type: file`
    for it.
    
    ### History
    
    | | |
    | --- | --- |
    | **Introduced by** | #756 (2020-05-26), "User System File Uploading"
    (`UserFile`). Wired into the dashboard by #1251 (2021-08-05,
    `DashboardFile`) and #1966 / #1982 (June 2023, unified search +
    `DashboardEntry` file branch) |
    | **Usage removed by** | #2781 (2024-08-20), "Remove File-Related
    Components". It deleted `UserFileResource`, `UserFileAccessResource`,
    the file search query builder and the user-file components |
    
    It has been dead for about two years: no file entry can reach the
    frontend. #8068 (2026-08-28) later registered `FileResourceDescriptor`
    for a kind that could no longer appear.
    
    > Reviewer note: most of the spec churn is not coverage loss. The File
    descriptor was the only registered kind without rename, description,
    share, download or publish support, so several specs used a File entry
    to reach those guard branches. They now reach the same branches with a
    stand-in descriptor instead:
    > - `stubBareDescriptor()` in the card-item and list-item specs;
    > - an injected `ModelResourceDescriptor` override in the registry spec;
    > - `UNPUBLISHABLE_DESCRIPTOR` in the share-access spec.
    >
    > Only the cases that asserted File-specific behaviour were deleted.
    
    ### Any related issues, documentation, discussions?
    
    Closes #8692
    
    ### How was this PR tested?
    
    No new tests. The guard-branch specs are kept and re-pointed at a
    stand-in descriptor, as described above.
    
    From `frontend/`:
    
    - `npx ng test --watch=false --include='src/app/dashboard/**/*.spec.ts'
    --include='src/app/hub/**/*.spec.ts'`: 72 spec files, all pass.
    - `yarn format:ci`: clean.
    - `npx ng build`: success.
    
    To re-check:
    
    ```
    git grep -nwE 
"DashboardFile|UserFile|isDashboardFile|FileResourceDescriptor" -- frontend   # 
no hits
    ```
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 5.5)
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
 .../card-item/card-item.component.spec.ts          | 63 ++++++-----------
 .../user/list-item/list-item.component.spec.ts     | 43 ++++++++----
 .../user/search-bar/search-bar.component.spec.ts   | 20 ------
 .../user/search-bar/search-bar.component.ts        |  2 -
 .../search-results.component.spec.ts               |  4 +-
 .../share-access/share-access.component.spec.ts    | 25 ++++++-
 .../resource-registry/file-resource.descriptor.ts  | 33 ---------
 .../resource-registry.service.spec.ts              | 79 ++++++++++------------
 .../resource-registry/resource-registry.service.ts |  4 +-
 .../app/dashboard/service/user/search.service.ts   | 12 ++--
 .../dashboard/service/user/stub-search.service.ts  |  4 +-
 .../src/app/dashboard/type/dashboard-entry.spec.ts | 40 +----------
 frontend/src/app/dashboard/type/dashboard-entry.ts | 31 +--------
 .../app/dashboard/type/dashboard-file.interface.ts | 34 ----------
 .../app/dashboard/type/search-filter-parameters.ts |  4 +-
 frontend/src/app/dashboard/type/search-result.ts   |  4 +-
 .../src/app/dashboard/type/type-predicates.spec.ts | 56 +--------------
 frontend/src/app/dashboard/type/type-predicates.ts |  5 --
 frontend/src/app/hub/service/hub.service.ts        |  1 -
 19 files changed, 127 insertions(+), 337 deletions(-)

diff --git 
a/frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts
index dd243bc9c8..69f036b19b 100644
--- 
a/frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/list-item/card-item/card-item.component.spec.ts
@@ -47,6 +47,7 @@ import { GuiConfigService } from 
"../../../../../common/service/gui-config.servi
 import { DefaultView } from 
"src/app/dashboard/type/workflow-metadata.interface";
 import { DatasetService, DEFAULT_DATASET_NAME } from 
"../../../../service/user/dataset/dataset.service";
 import { DownloadService } from 
"src/app/dashboard/service/user/download/download.service";
+import { ResourceRegistryService } from 
"src/app/dashboard/service/user/resource-registry/resource-registry.service";
 
 function makeWorkflowEntry(overrides: Partial<DashboardEntry> = {}): 
DashboardEntry {
   return {
@@ -80,6 +81,19 @@ function makeDatasetEntry(overrides: Partial<DashboardEntry> 
= {}): DashboardEnt
   } as unknown as DashboardEntry;
 }
 
+/**
+ * Makes the registry answer every lookup with a descriptor that has none of 
the optional
+ * capabilities. Every shipped kind can be renamed, re-described and shared, 
so the checks for those
+ * capabilities need one that cannot.
+ */
+function stubBareDescriptor(): void {
+  vi.spyOn(TestBed.inject(ResourceRegistryService), "get").mockReturnValue({
+    type: EntityType.Workflow,
+    iconType: "project",
+    isOwner: () => true,
+  });
+}
+
 describe("CardItemComponent", () => {
   let component: CardItemComponent;
   let fixture: ComponentFixture<CardItemComponent>;
@@ -444,21 +458,6 @@ describe("CardItemComponent", () => {
     expect(component.isLiked).toBe(true);
   });
 
-  it("initializeEntry uses the folder-open icon for a file entry", () => {
-    component.entry = {
-      id: 8,
-      name: "f",
-      type: "file",
-      likeCount: 0,
-      viewCount: 0,
-      isLiked: false,
-    } as unknown as DashboardEntry;
-
-    component.initializeEntry();
-
-    expect(component.iconType).toBe("folder-open");
-  });
-
   it("initializeEntry throws for an unexpected entry type", () => {
     component.entry = {
       id: 1,
@@ -758,14 +757,8 @@ describe("CardItemComponent", () => {
     it("onClickOpenShareAccess does not open a modal for a non-shareable entry 
type", async () => {
       const modalService = TestBed.inject(NzModalService);
       const createSpy = vi.spyOn(modalService, "create");
-      component.entry = {
-        id: 3,
-        name: "f",
-        type: "file",
-        likeCount: 0,
-        viewCount: 0,
-        isLiked: false,
-      } as unknown as DashboardEntry;
+      stubBareDescriptor();
+      component.entry = makeWorkflowEntry({ id: 3 });
 
       await component.onClickOpenShareAccess();
 
@@ -1086,22 +1079,6 @@ describe("CardItemComponent", () => {
   });
 
   describe("guard paths", () => {
-    /** Files are the one registered kind with neither a rename nor a 
description endpoint. */
-    function makeFileEntry(overrides: Partial<DashboardEntry> = {}): 
DashboardEntry {
-      return {
-        id: 3,
-        name: "notes.txt",
-        description: "",
-        type: EntityType.File,
-        accessibleUserIds: [],
-        likeCount: 0,
-        viewCount: 0,
-        isLiked: false,
-        size: 0,
-        ...overrides,
-      } as unknown as DashboardEntry;
-    }
-
     it("ngOnChanges ignores a change set that does not carry the entry", () => 
{
       // initializeEntry resets the cover and the counters; re-running it on 
an unrelated input
       // change would discard a cover that had just finished loading.
@@ -1129,8 +1106,9 @@ describe("CardItemComponent", () => {
       // mocked so a regression fails on the assertion rather than on a 
TypeError out of
       // updateProperty.
       workflowPersistService.updateWorkflowName.mockReturnValue(of({} as 
Response));
-      component.entry = makeFileEntry({ name: "typed" });
-      component.originalName = "notes.txt";
+      stubBareDescriptor();
+      component.entry = makeWorkflowEntry({ name: "typed" });
+      component.originalName = "wf";
       component.editingName = true;
 
       component.confirmUpdateCustomName("typed");
@@ -1144,7 +1122,8 @@ describe("CardItemComponent", () => {
       // Mocked so that a regression here fails on the assertion below rather 
than on a TypeError
       // thrown out of updateProperty.
       workflowPersistService.updateWorkflowDescription.mockReturnValue(of({} 
as Response));
-      component.entry = makeFileEntry({ description: "typed" });
+      stubBareDescriptor();
+      component.entry = makeWorkflowEntry({ description: "typed" });
       component.originalDescription = "";
       component.editingDescription = true;
 
diff --git 
a/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
index ce4a2310ef..997c0996b9 100644
--- 
a/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
@@ -28,7 +28,7 @@ import {
 import { HttpClientTestingModule } from "@angular/common/http/testing";
 import { NzModalService } from "ng-zorro-antd/modal";
 import { of, Subject, throwError } from "rxjs";
-import { ActionType, HubService } from "../../../../hub/service/hub.service";
+import { ActionType, EntityType, HubService } from 
"../../../../hub/service/hub.service";
 import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
 import { RouterTestingModule } from "@angular/router/testing";
 import { StubUserService } from 
"../../../../common/service/user/stub-user.service";
@@ -46,6 +46,20 @@ import {
   USER_DATASET,
   USER_WORKSPACE,
 } from "../../../../app-routing.constant";
+import { ResourceRegistryService } from 
"../../../service/user/resource-registry/resource-registry.service";
+
+/**
+ * Makes the registry answer every lookup with a descriptor that has none of 
the optional
+ * capabilities. Every shipped kind can be shared and downloaded, so the 
checks for those
+ * capabilities need one that cannot.
+ */
+function stubBareDescriptor(): void {
+  vi.spyOn(TestBed.inject(ResourceRegistryService), "get").mockReturnValue({
+    type: EntityType.Workflow,
+    iconType: "project",
+    isOwner: () => true,
+  });
+}
 
 describe("ListItemComponent", () => {
   let component: ListItemComponent;
@@ -519,9 +533,6 @@ describe("ListItemComponent", () => {
 
       feed(entryOf({ type: "dataset", dataset: { isOwner: true } }));
       expect(component.iconType).toBe("database");
-
-      feed(entryOf({ type: "file" }));
-      expect(component.iconType).toBe("folder-open");
     });
 
     it("refuses an entry kind it does not know", () => {
@@ -538,13 +549,19 @@ describe("ListItemComponent", () => {
     });
 
     it("reduces a description to a plain preview, and blanks an empty one", () 
=> {
-      feed(entryOf({ type: "file", description: undefined }));
+      feed(entryOf({ type: "dataset", dataset: { isOwner: true }, description: 
undefined }));
       expect(component.renderedDescription).toBe("");
 
-      feed(entryOf({ type: "file", description: "   " }));
+      feed(entryOf({ type: "dataset", dataset: { isOwner: true }, description: 
"   " }));
       expect(component.renderedDescription).toBe("");
 
-      feed(entryOf({ type: "file", description: "# Title with [a 
link](http://x)  and\n*emphasis*" }));
+      feed(
+        entryOf({
+          type: "dataset",
+          dataset: { isOwner: true },
+          description: "# Title with [a link](http://x)  and\n*emphasis*",
+        })
+      );
       expect(component.renderedDescription).toBe("Title with a link and 
emphasis");
     });
 
@@ -596,7 +613,8 @@ describe("ListItemComponent", () => {
 
       it("opens nothing for an entry kind that cannot be shared", async () => {
         const create = vi.spyOn(modalService, "create");
-        feed(entryOf({ type: "file" }));
+        stubBareDescriptor();
+        feed(entryOf({ type: "workflow", workflow: { isOwner: true } }));
 
         await component.onClickOpenShareAccess();
 
@@ -669,7 +687,7 @@ describe("ListItemComponent", () => {
     });
 
     it("ignores a change that is not the entry", () => {
-      feed(entryOf({ type: "file", description: "kept" }));
+      feed(entryOf({ type: "dataset", dataset: { isOwner: true }, description: 
"kept" }));
       const before = component.renderedDescription;
 
       component.ngOnChanges({ editable: {} as any });
@@ -722,7 +740,7 @@ describe("ListItemComponent", () => {
 
       it("downloads nothing for an entry that was never persisted", () => {
         const workflow = vi.spyOn(TestBed.inject(DownloadService), 
"downloadWorkflow");
-        feed(entryOf({ type: "file", id: 0 }));
+        feed(entryOf({ type: "workflow", id: 0, workflow: { isOwner: true } 
}));
 
         component.onClickDownload();
 
@@ -877,7 +895,7 @@ describe("ListItemComponent", () => {
       expect(deleted).toBe(1);
     });
 
-    it("offers the download button to workflows and datasets only", () => {
+    it("offers the download button only to kinds that can be downloaded", () 
=> {
       const download = vi.spyOn(component, 
"onClickDownload").mockImplementation(() => {});
 
       render();
@@ -887,7 +905,8 @@ describe("ListItemComponent", () => {
       render({ type: "dataset" });
       expect(button("Download")).not.toBeNull();
 
-      render({ type: "file" });
+      stubBareDescriptor();
+      render();
       expect(button("Download")).toBeNull();
     });
 
diff --git 
a/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.spec.ts
index 5160af331f..4bc8f1f8fe 100644
--- 
a/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.spec.ts
@@ -171,26 +171,6 @@ describe("SearchBarComponent", () => {
       expect(component.convertToName(makeWorkflowItem("wf-name", 
7))).toBe("wf-name");
     });
 
-    it("returns the file's name", () => {
-      const item: SearchResultItem = {
-        resourceType: "file",
-        file: {
-          ownerEmail: "[email protected]",
-          accessLevel: "WRITE",
-          file: {
-            fid: 1,
-            ownerUid: 1,
-            name: "file-name",
-            size: 0,
-            path: "",
-            description: "",
-            uploadTime: 0,
-          },
-        } as any,
-      };
-      expect(component.convertToName(item)).toBe("file-name");
-    });
-
     it("returns the dataset's name", () => {
       const item: SearchResultItem = {
         resourceType: "dataset",
diff --git 
a/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.ts 
b/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.ts
index 9238731060..c768ee56d6 100644
--- 
a/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.ts
+++ 
b/frontend/src/app/dashboard/component/user/search-bar/search-bar.component.ts
@@ -142,8 +142,6 @@ export class SearchBarComponent {
   convertToName(resultItem: SearchResultItem): string {
     if (resultItem.workflow) {
       return new DashboardEntry(resultItem.workflow).name;
-    } else if (resultItem.file) {
-      return new DashboardEntry(resultItem.file).name;
     } else if (resultItem.dataset) {
       return new DashboardEntry(resultItem.dataset).name;
     } else {
diff --git 
a/frontend/src/app/dashboard/component/user/search-results/search-results.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/search-results/search-results.component.spec.ts
index d1445ccd7c..df98d5ebe6 100644
--- 
a/frontend/src/app/dashboard/component/user/search-results/search-results.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/search-results/search-results.component.spec.ts
@@ -129,7 +129,7 @@ describe("SearchResultsComponent", () => {
     it("clears entries and stores the provided loadMoreFunction", async () => {
       component.entries = [makeEntry("workflow", 1), makeEntry("dataset", 2)];
 
-      const loadMoreFunction: LoadMoreFunction = vi.fn(async () => ({ entries: 
[makeEntry("file", 3)], more: false }));
+      const loadMoreFunction: LoadMoreFunction = vi.fn(async () => ({ entries: 
[makeEntry("model", 3)], more: false }));
       component.reset(loadMoreFunction);
 
       expect(component.entries).toEqual([]);
@@ -138,7 +138,7 @@ describe("SearchResultsComponent", () => {
       // The stored function is the one loadMore invokes.
       await component.loadMore();
       expect(loadMoreFunction).toHaveBeenCalledTimes(1);
-      expect(component.entries).toEqual([makeEntry("file", 3)]);
+      expect(component.entries).toEqual([makeEntry("model", 3)]);
     });
   });
 
diff --git 
a/frontend/src/app/dashboard/component/user/share-access/share-access.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/share-access/share-access.component.spec.ts
index 94f20b2cbd..ec41db898c 100644
--- 
a/frontend/src/app/dashboard/component/user/share-access/share-access.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/share-access/share-access.component.spec.ts
@@ -36,14 +36,29 @@ import { DatasetService } from 
"../../../service/user/dataset/dataset.service";
 import { WorkflowPersistService } from 
"src/app/common/service/workflow-persist/workflow-persist.service";
 import { WorkflowActionService } from 
"src/app/workspace/service/workflow-graph/model/workflow-action.service";
 import { Privilege } from "../../../type/share-access.interface";
+import { ResourceRegistryService } from 
"../../../service/user/resource-registry/resource-registry.service";
+import { ResourceDescriptor } from "../../../type/resource-descriptor";
+import { EntityType } from "../../../../hub/service/hub.service";
 
 interface SetupOptions {
   type?: string;
   id?: number;
   inWorkspace?: boolean;
   currentEmail?: string | undefined;
+  /** What the registry answers for the kind, in place of the shipped 
descriptor. */
+  descriptor?: ResourceDescriptor;
 }
 
+/**
+ * A registered kind that cannot be published. Every shipped kind can, so the 
checks for publishing
+ * need this one.
+ */
+const UNPUBLISHABLE_DESCRIPTOR: ResourceDescriptor = {
+  type: EntityType.Dataset,
+  iconType: "database",
+  isOwner: () => true,
+};
+
 describe("ShareAccessComponent", () => {
   let gmailSpy: { sendEmail: ReturnType<typeof vi.fn> };
   let accessServiceSpy: {
@@ -105,6 +120,9 @@ describe("ShareAccessComponent", () => {
         { provide: WorkflowActionService, useValue: workflowActionSpy },
       ],
     });
+    if (opts.descriptor) {
+      vi.spyOn(TestBed.inject(ResourceRegistryService), 
"find").mockReturnValue(opts.descriptor);
+    }
     fixture = TestBed.createComponent(ShareAccessComponent);
     fixture.detectChanges();
     return fixture.componentInstance;
@@ -215,8 +233,8 @@ describe("ShareAccessComponent", () => {
       expect(c.isPublic).toBe(true);
     });
 
-    it("does not query publish state for non-workflow/dataset types", () => {
-      setupComponent({ type: "file", id: 4 });
+    it("does not query publish state for a kind that cannot be published", () 
=> {
+      setupComponent({ type: "dataset", id: 4, descriptor: 
UNPUBLISHABLE_DESCRIPTOR });
       expect(workflowPersistSpy.getWorkflowIsPublished).not.toHaveBeenCalled();
       expect(datasetServiceSpy.getDataset).not.toHaveBeenCalled();
     });
@@ -601,10 +619,11 @@ describe("ShareAccessComponent", () => {
     });
 
     it("does nothing for a registered kind that cannot be published", () => {
-      const c = setupComponent({ type: "file", id: 4 });
+      const c = setupComponent({ type: "dataset", id: 4, descriptor: 
UNPUBLISHABLE_DESCRIPTOR });
       c.setPublished(true);
       expect(c.isPublic).toBeNull();
       expect(notificationSpy.success).not.toHaveBeenCalled();
+      expect(datasetServiceSpy.updateDatasetPublicity).not.toHaveBeenCalled();
     });
 
     it("does nothing for a kind the registry does not carry at all", () => {
diff --git 
a/frontend/src/app/dashboard/service/user/resource-registry/file-resource.descriptor.ts
 
b/frontend/src/app/dashboard/service/user/resource-registry/file-resource.descriptor.ts
deleted file mode 100644
index ba90117b27..0000000000
--- 
a/frontend/src/app/dashboard/service/user/resource-registry/file-resource.descriptor.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { Injectable } from "@angular/core";
-import { ResourceDescriptor } from "../../../type/resource-descriptor";
-import { EntityType } from "../../../../hub/service/hub.service";
-
-@Injectable({
-  providedIn: "root",
-})
-export class FileResourceDescriptor implements ResourceDescriptor {
-  readonly type = EntityType.File;
-  readonly iconType = "folder-open";
-  // Files have no page of their own, so entries of this kind stay unrouted.
-
-  isOwner = (): boolean => true;
-}
diff --git 
a/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.spec.ts
 
b/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.spec.ts
index 4e83312d7a..72f4d042a3 100644
--- 
a/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.spec.ts
+++ 
b/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.spec.ts
@@ -28,7 +28,8 @@ import { DatasetService } from "../dataset/dataset.service";
 import { ModelService } from "../model/model.service";
 import { WorkflowPersistService } from 
"../../../../common/service/workflow-persist/workflow-persist.service";
 import { DownloadService } from "../download/download.service";
-import { FileResourceDescriptor } from "./file-resource.descriptor";
+import { ModelResourceDescriptor } from "./model-resource.descriptor";
+import { ResourceDescriptor } from "../../../type/resource-descriptor";
 import {
   HUB_DATASET_RESULT_DETAIL,
   HUB_MODEL_RESULT_DETAIL,
@@ -151,7 +152,6 @@ describe("ResourceRegistryService", () => {
   it("resolves every kind the dashboard renders", () => {
     expect(registry.get(EntityType.Workflow).iconType).toBe("project");
     expect(registry.get(EntityType.Dataset).iconType).toBe("database");
-    expect(registry.get(EntityType.File).iconType).toBe("folder-open");
     expect(registry.get(EntityType.Model).iconType).toBe(MODEL_ICON);
   });
 
@@ -169,38 +169,29 @@ describe("ResourceRegistryService", () => {
 
   // ─── capability checks ────────────────────────────────────────────────────
 
-  it("exposes rename and description only for the kinds that support them", () 
=> {
+  it("exposes rename and description for every kind", () => {
     for (const type of [EntityType.Workflow, EntityType.Dataset, 
EntityType.Model]) {
       expect(registry.get(type).rename).toBeDefined();
       expect(registry.get(type).updateDescription).toBeDefined();
     }
-    for (const type of [EntityType.File]) {
-      expect(registry.get(type).rename).toBeUndefined();
-      expect(registry.get(type).updateDescription).toBeUndefined();
-    }
   });
 
-  it("offers a download and a file preview only for the kinds that hold 
files", () => {
+  it("offers a download for every kind and a file preview only for the kinds 
that hold files", () => {
     for (const type of [EntityType.Workflow, EntityType.Dataset, 
EntityType.Model]) {
       expect(registry.get(type).download).toBeDefined();
     }
-    for (const type of [EntityType.File]) {
-      expect(registry.get(type).download).toBeUndefined();
-    }
     // Workflows are one file, not a version tree, so nothing previews them.
     
expect(registry.get(EntityType.Workflow).retrieveSingleFile).toBeUndefined();
     expect(registry.get(EntityType.Dataset).retrieveSingleFile).toBeDefined();
     expect(registry.get(EntityType.Model).retrieveSingleFile).toBeDefined();
   });
 
-  it("offers publishing and covers only to the kinds the backend supports", () 
=> {
+  it("offers publishing to every kind and covers only to the file-backed 
kinds", () => {
     for (const type of [EntityType.Workflow, EntityType.Dataset, 
EntityType.Model]) {
       expect(registry.get(type).retrieveOwners).toBeDefined();
       expect(registry.get(type).isPublic).toBeDefined();
       expect(registry.get(type).setPublished).toBeDefined();
     }
-    expect(registry.get(EntityType.File).isPublic).toBeUndefined();
-    expect(registry.get(EntityType.File).setPublished).toBeUndefined();
     // A workflow cover is a data URL on the entry, so only the file-backed 
kinds resolve one.
     expect(registry.get(EntityType.Workflow).coverUrl).toBeUndefined();
     expect(registry.get(EntityType.Dataset).coverUrl).toBeDefined();
@@ -271,8 +262,6 @@ describe("ResourceRegistryService", () => {
     expect(registry.get(EntityType.Workflow).isOwner(entry({ workflow: { 
isOwner: false } }))).toBe(false);
     expect(registry.get(EntityType.Dataset).isOwner(entry({ dataset: { 
isOwner: true } }))).toBe(true);
     expect(registry.get(EntityType.Model).isOwner(entry({ model: { isOwner: 
false } }))).toBe(false);
-    // File entries carry no ownership payload at all, so theirs must not read 
one.
-    expect(registry.get(EntityType.File).isOwner(entry({}))).toBe(true);
   });
 
   // ─── entryLink ────────────────────────────────────────────────────────────
@@ -295,20 +284,12 @@ describe("ResourceRegistryService", () => {
     expect(registry.entryLink(model, 99)).toEqual([HUB_MODEL_RESULT_DETAIL, 
"9"]);
   });
 
-  it("leaves an unroutable or unsaved entry unlinked", () => {
-    expect(registry.entryLink(entry({ type: EntityType.File, id: 8 }), 
42)).toEqual([]);
-    expect(registry.entryLink(entry({ type: EntityType.Dataset, id: undefined 
}), 42)).toEqual([]);
-    expect(registry.entryLink(entry({ type: EntityType.Workflow, id: "draft" 
}), 42)).toEqual([]);
-  });
-
   /**
-   * `hubRoute` is optional on the descriptor contract, and the shipped kinds 
happen to declare
-   * both routes or neither — so nothing had ever asked what a 
private-page-only kind links to.
-   * The answer must not depend on the viewer: with nowhere else to send them, 
the private page is
-   * the only link there is, and the access check further down would otherwise 
route an outsider to
-   * `undefined`. Descriptors reach the registry by injection, so the kind is 
supplied as one.
+   * Both routes are optional on the descriptor contract, but every shipped 
kind declares both, so
+   * only a stand-in descriptor can exercise a kind that lacks one. 
Descriptors reach the registry by
+   * injection, so the stand-in is supplied in place of the model descriptor.
    */
-  it("links a kind with a private page and no hub page straight to its private 
page", () => {
+  const registryWithModelAs = (descriptor: ResourceDescriptor): 
ResourceRegistryService => {
     TestBed.resetTestingModule();
     TestBed.configureTestingModule({
       imports: [HttpClientTestingModule],
@@ -317,24 +298,38 @@ describe("ResourceRegistryService", () => {
         { provide: WorkflowPersistService, useValue: workflowPersistService },
         { provide: DatasetService, useValue: datasetService },
         { provide: ModelService, useValue: modelService },
-        {
-          provide: FileResourceDescriptor,
-          useValue: {
-            type: EntityType.File,
-            iconType: "folder-open",
-            privateRoute: "/private-files",
-            isOwner: () => true,
-          },
-        },
+        { provide: ModelResourceDescriptor, useValue: descriptor },
         ...commonTestProviders,
       ],
     });
-    const privatePageOnly = TestBed.inject(ResourceRegistryService);
-    const file = entry({ type: EntityType.File, id: 7, accessibleUserIds: [42] 
});
+    return TestBed.inject(ResourceRegistryService);
+  };
+
+  it("leaves an unroutable or unsaved entry unlinked", () => {
+    expect(registry.entryLink(entry({ type: EntityType.Dataset, id: undefined 
}), 42)).toEqual([]);
+    expect(registry.entryLink(entry({ type: EntityType.Workflow, id: "draft" 
}), 42)).toEqual([]);
+
+    const unrouted = registryWithModelAs({ type: EntityType.Model, iconType: 
MODEL_ICON, isOwner: () => true });
+    expect(unrouted.entryLink(entry({ type: EntityType.Model, id: 8 }), 
42)).toEqual([]);
+  });
+
+  /**
+   * The answer must not depend on the viewer: with nowhere else to send them, 
the private page is
+   * the only link there is, and the access check further down would otherwise 
route an outsider to
+   * `undefined`.
+   */
+  it("links a kind with a private page and no hub page straight to its private 
page", () => {
+    const privatePageOnly = registryWithModelAs({
+      type: EntityType.Model,
+      iconType: MODEL_ICON,
+      privateRoute: "/private-models",
+      isOwner: () => true,
+    });
+    const model = entry({ type: EntityType.Model, id: 7, accessibleUserIds: 
[42] });
 
-    expect(privatePageOnly.entryLink(file, 42)).toEqual(["/private-files", 
"7"]);
+    expect(privatePageOnly.entryLink(model, 42)).toEqual(["/private-models", 
"7"]);
     // Same link for a viewer with no access, and for an anonymous one.
-    expect(privatePageOnly.entryLink(file, 99)).toEqual(["/private-files", 
"7"]);
-    expect(privatePageOnly.entryLink(file, 
undefined)).toEqual(["/private-files", "7"]);
+    expect(privatePageOnly.entryLink(model, 99)).toEqual(["/private-models", 
"7"]);
+    expect(privatePageOnly.entryLink(model, 
undefined)).toEqual(["/private-models", "7"]);
   });
 });
diff --git 
a/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.ts
 
b/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.ts
index 40ef1fbc86..a65ce89cf3 100644
--- 
a/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.ts
+++ 
b/frontend/src/app/dashboard/service/user/resource-registry/resource-registry.service.ts
@@ -26,7 +26,6 @@ import { catchError, map } from "rxjs/operators";
 import { OwnerScope } from "../../../type/owner-scope";
 import { WorkflowResourceDescriptor } from "./workflow-resource.descriptor";
 import { DatasetResourceDescriptor } from "./dataset-resource.descriptor";
-import { FileResourceDescriptor } from "./file-resource.descriptor";
 import { ModelResourceDescriptor } from "./model-resource.descriptor";
 
 /**
@@ -43,12 +42,11 @@ export class ResourceRegistryService {
   constructor(
     workflow: WorkflowResourceDescriptor,
     dataset: DatasetResourceDescriptor,
-    file: FileResourceDescriptor,
     model: ModelResourceDescriptor
   ) {
     // Computing units are deliberately absent: nothing in the dashboard 
renders them as entries.
     this.descriptors = new Map<EntityType, ResourceDescriptor>(
-      [workflow, dataset, file, model].map(descriptor => [descriptor.type, 
descriptor])
+      [workflow, dataset, model].map(descriptor => [descriptor.type, 
descriptor])
     );
   }
 
diff --git a/frontend/src/app/dashboard/service/user/search.service.ts 
b/frontend/src/app/dashboard/service/user/search.service.ts
index 04d65ff975..c0442e2f59 100644
--- a/frontend/src/app/dashboard/service/user/search.service.ts
+++ b/frontend/src/app/dashboard/service/user/search.service.ts
@@ -59,7 +59,7 @@ export class SearchService {
    * @param params - Additional search filter parameters.
    * @param start - The starting index for paginated results.
    * @param count - The number of results to retrieve.
-   * @param type - The type of resource to search for ("workflow", "dataset", 
"file", "model", or null (all resource type)).
+   * @param type - The type of resource to search for ("workflow", "dataset", 
"model", or null (all resource type)).
    * @param orderBy - Specifies the sorting method.
    * @param isLogin - Indicates if the user is logged in.
    *    - `isLogin = true`: Use the authenticated search endpoint, retrieving 
both user-accessible and public resources based on `includePublic`.
@@ -73,7 +73,7 @@ export class SearchService {
     params: SearchFilterParameters,
     start: number,
     count: number,
-    type: "workflow" | "file" | "dataset" | "model" | null,
+    type: "workflow" | "dataset" | "model" | null,
     orderBy: SortMethod,
     isLogin: boolean,
     includePublic: boolean = false
@@ -106,9 +106,7 @@ export class SearchService {
           // and the search bar are unaffected. Not corrected here: that 
belongs in the
           // `LoadMoreFunction` contract shared by all five callers of 
`SearchResultsComponent.reset`,
           // and removing the backend half (#7461) ends the only condition 
that produces such rows.
-          results: result.results.filter(
-            item => item.workflow != null || item.file != null || item.dataset 
!= null || item.model != null
-          ),
+          results: result.results.filter(item => item.workflow != null || 
item.dataset != null || item.model != null),
         }))
       );
   }
@@ -134,7 +132,7 @@ export class SearchService {
    * @param params        Additional search filter parameters.
    * @param start         The starting index for paginated results.
    * @param count         The number of results to retrieve.
-   * @param type          The type of resource to search for ("workflow", 
"dataset", "file", "model", or null (all resource type)).
+   * @param type          The type of resource to search for ("workflow", 
"dataset", "model", or null (all resource type)).
    * @param orderBy       Specifies the sorting method.
    * @param isLogin       Indicates if the user is logged in.
    * @param includePublic Specifies whether to include public resources in the 
search results.
@@ -149,7 +147,7 @@ export class SearchService {
     params: SearchFilterParameters,
     start: number,
     count: number,
-    type: "workflow" | "dataset" | "file" | "model" | null,
+    type: "workflow" | "dataset" | "model" | null,
     orderBy: SortMethod,
     isLogin: boolean,
     includePublic: boolean
diff --git a/frontend/src/app/dashboard/service/user/stub-search.service.ts 
b/frontend/src/app/dashboard/service/user/stub-search.service.ts
index 18e07d7ddf..10ee9c7264 100644
--- a/frontend/src/app/dashboard/service/user/stub-search.service.ts
+++ b/frontend/src/app/dashboard/service/user/stub-search.service.ts
@@ -43,7 +43,7 @@ export class StubSearchService {
     params: SearchFilterParameters,
     start: number,
     count: number,
-    type: "workflow" | "file" | "dataset" | "model" | null,
+    type: "workflow" | "dataset" | "model" | null,
     orderBy: SortMethod,
     isLogin: boolean = true,
     includePublic: boolean = false
@@ -79,7 +79,7 @@ export class StubSearchService {
     params: SearchFilterParameters,
     start: number,
     count: number,
-    type: "workflow" | "dataset" | "file" | "model" | null,
+    type: "workflow" | "dataset" | "model" | null,
     orderBy: SortMethod,
     isLogin: boolean,
     includePublic: boolean
diff --git a/frontend/src/app/dashboard/type/dashboard-entry.spec.ts 
b/frontend/src/app/dashboard/type/dashboard-entry.spec.ts
index 76ad406673..5dcdd53db3 100644
--- a/frontend/src/app/dashboard/type/dashboard-entry.spec.ts
+++ b/frontend/src/app/dashboard/type/dashboard-entry.spec.ts
@@ -20,7 +20,6 @@
 import { DashboardEntry } from "./dashboard-entry";
 import { EntityType } from "../../hub/service/hub.service";
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
-import { DashboardFile } from "./dashboard-file.interface";
 import { DashboardDataset } from "./dashboard-dataset.interface";
 import { DashboardModel } from "./dashboard-model.interface";
 import { DashboardWorkflowComputingUnit } from 
"../../common/type/workflow-computing-unit";
@@ -57,22 +56,6 @@ function makeWorkflow(coverImage: string | null = 
"http://example.com/cover.png";
   };
 }
 
-function makeFile(): DashboardFile {
-  return {
-    ownerEmail: "[email protected]",
-    accessLevel: "WRITE",
-    file: {
-      ownerUid: 30,
-      fid: 303,
-      size: 1234,
-      name: "data.csv",
-      path: "/files/data.csv",
-      description: "A sample file",
-      uploadTime: 1700000003000,
-    },
-  };
-}
-
 function makeDataset(): DashboardDataset {
   return {
     isOwner: false,
@@ -173,21 +156,6 @@ describe("DashboardEntry", () => {
       expect(entry.coverImageUrl).toBeUndefined();
     });
 
-    it("maps a DashboardFile to the File entity and copies file fields", () => 
{
-      const entry = new DashboardEntry(makeFile());
-
-      expect(entry.type).toBe(EntityType.File);
-      expect(entry.id).toBe(303);
-      expect(entry.name).toBe("data.csv");
-      expect(entry.description).toBe("A sample file");
-      expect(entry.creationTime).toBe(1700000003000);
-      expect(entry.lastModifiedTime).toBe(1700000003000);
-      expect(entry.accessLevel).toBe("WRITE");
-      expect(entry.ownerEmail).toBe("[email protected]");
-      expect(entry.ownerId).toBe(30);
-      expect(entry.size).toBe(1234);
-    });
-
     it("maps a DashboardDataset to the Dataset entity and copies dataset 
fields", () => {
       const entry = new DashboardEntry(makeDataset());
 
@@ -307,13 +275,7 @@ describe("DashboardEntry", () => {
     it("workflow getter returns the value for a workflow entry and throws for 
others", () => {
       const workflowValue = makeWorkflow();
       expect(new DashboardEntry(workflowValue).workflow).toBe(workflowValue);
-      expect(() => new 
DashboardEntry(makeFile()).workflow).toThrowError("Value is not of type 
DashboardWorkflow.");
-    });
-
-    it("file getter returns the value for a file entry and throws for others", 
() => {
-      const fileValue = makeFile();
-      expect(new DashboardEntry(fileValue).file).toBe(fileValue);
-      expect(() => new 
DashboardEntry(makeWorkflow()).file).toThrowError("Value is not of type 
DashboardFile.");
+      expect(() => new 
DashboardEntry(makeDataset()).workflow).toThrowError("Value is not of type 
DashboardWorkflow.");
     });
 
     it("dataset getter returns the value for a dataset entry and throws for 
others", () => {
diff --git a/frontend/src/app/dashboard/type/dashboard-entry.ts 
b/frontend/src/app/dashboard/type/dashboard-entry.ts
index 6a11ba0ef0..ca569a6e73 100644
--- a/frontend/src/app/dashboard/type/dashboard-entry.ts
+++ b/frontend/src/app/dashboard/type/dashboard-entry.ts
@@ -17,14 +17,12 @@
  * under the License.
  */
 
-import { DashboardFile } from "./dashboard-file.interface";
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
 import { DashboardDataset } from "./dashboard-dataset.interface";
 import { DashboardModel } from "./dashboard-model.interface";
 import { DashboardWorkflowComputingUnit } from 
"../../common/type/workflow-computing-unit";
 import {
   isDashboardDataset,
-  isDashboardFile,
   isDashboardModel,
   isDashboardWorkflow,
   isDashboardWorkflowComputingUnit,
@@ -57,9 +55,7 @@ export class DashboardEntry {
   accessibleUserIds: number[];
   coverImageUrl?: string;
 
-  constructor(
-    public value: DashboardWorkflow | DashboardFile | DashboardDataset | 
DashboardModel | DashboardWorkflowComputingUnit
-  ) {
+  constructor(public value: DashboardWorkflow | DashboardDataset | 
DashboardModel | DashboardWorkflowComputingUnit) {
     if (isDashboardWorkflow(value)) {
       this.type = EntityType.Workflow;
       this.id = value.workflow.wid;
@@ -79,24 +75,6 @@ export class DashboardEntry {
       this.isLiked = false;
       this.accessibleUserIds = [];
       this.coverImageUrl = value.coverImage ?? undefined;
-    } else if (isDashboardFile(value)) {
-      this.type = EntityType.File;
-      this.id = value.file.fid;
-      this.name = value.file.name;
-      this.description = value.file.description;
-      this.creationTime = value.file.uploadTime;
-      this.lastModifiedTime = value.file.uploadTime;
-      this.accessLevel = value.accessLevel;
-      this.ownerName = "";
-      this.ownerEmail = value.ownerEmail;
-      this.ownerAvatar = "";
-      this.ownerId = value.file.ownerUid;
-      this.size = value.file.size;
-      this.viewCount = 0;
-      this.cloneCount = 0;
-      this.likeCount = 0;
-      this.isLiked = false;
-      this.accessibleUserIds = [];
     } else if (isDashboardDataset(value)) {
       this.type = EntityType.Dataset;
       this.id = value.dataset.did;
@@ -187,13 +165,6 @@ export class DashboardEntry {
     return this.value;
   }
 
-  get file(): DashboardFile {
-    if (!isDashboardFile(this.value)) {
-      throw new Error("Value is not of type DashboardFile.");
-    }
-    return this.value;
-  }
-
   get dataset(): DashboardDataset {
     if (!isDashboardDataset(this.value)) {
       throw new Error("Value is not of type DashboardDataset");
diff --git a/frontend/src/app/dashboard/type/dashboard-file.interface.ts 
b/frontend/src/app/dashboard/type/dashboard-file.interface.ts
index fa394904c2..7509e408f5 100644
--- a/frontend/src/app/dashboard/type/dashboard-file.interface.ts
+++ b/frontend/src/app/dashboard/type/dashboard-file.interface.ts
@@ -17,29 +17,6 @@
  * under the License.
  */
 
-export interface DashboardFile
-  extends Readonly<{
-    ownerEmail: string;
-    accessLevel: string;
-    file: UserFile;
-  }> {}
-
-/**
- * This interface stores the information about the users' files.
- * These information is used to locate the file for the operators.
- * Corresponds to 
`src/main/scala/org/apache/texera/web/resource/dashboard/file/UserFileResource.scala`
 (backend);
- * and `sql/texera_ddl.sql`, table `file` (database).
- */
-export interface UserFile {
-  ownerUid: number;
-  fid: number;
-  size: number;
-  name: string;
-  path: string;
-  description: string;
-  uploadTime: number;
-}
-
 /**
  * This interface stores the information about the users' files when uploading.
  * These information is used to upload the file to the backend.
@@ -52,14 +29,3 @@ export interface FileUploadItem {
   isUploadingFlag: boolean;
   restart: boolean;
 }
-
-/**
- * This enum type helps indicate the method in which DashboardUserFileEntry[] 
is sorted
- */
-export enum SortMethod {
-  NameAsc,
-  NameDesc,
-  SizeDesc,
-  UploadTimeAsc,
-  UploadTimeDesc,
-}
diff --git a/frontend/src/app/dashboard/type/search-filter-parameters.ts 
b/frontend/src/app/dashboard/type/search-filter-parameters.ts
index 7ead364e4f..1aa785c25f 100644
--- a/frontend/src/app/dashboard/type/search-filter-parameters.ts
+++ b/frontend/src/app/dashboard/type/search-filter-parameters.ts
@@ -35,7 +35,7 @@ export const toQueryStrings = (
   params: SearchFilterParameters,
   start?: number,
   count?: number,
-  type?: "workflow" | "file" | "dataset" | "model" | null,
+  type?: "workflow" | "dataset" | "model" | null,
   orderBy?: SortMethod
 ): string => {
   const toLocalDate = (date: Date) =>
@@ -84,7 +84,7 @@ export const searchTestEntries = (
   keywords: string[],
   params: SearchFilterParameters,
   testEntries: DashboardEntry[],
-  type: "workflow" | "file" | "dataset" | "model" | null
+  type: "workflow" | "dataset" | "model" | null
 ): DashboardEntry[] => {
   const endOfDay = (date: Date) => {
     date.setHours(23);
diff --git a/frontend/src/app/dashboard/type/search-result.ts 
b/frontend/src/app/dashboard/type/search-result.ts
index 905aa47bc0..bccf7e8220 100644
--- a/frontend/src/app/dashboard/type/search-result.ts
+++ b/frontend/src/app/dashboard/type/search-result.ts
@@ -17,16 +17,14 @@
  * under the License.
  */
 
-import { DashboardFile } from "./dashboard-file.interface";
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
 import { DashboardDataset } from "./dashboard-dataset.interface";
 import { DashboardModel } from "./dashboard-model.interface";
 import { DashboardEntry } from "./dashboard-entry";
 
 export interface SearchResultItem {
-  resourceType: "workflow" | "file" | "dataset" | "model" | "computing-unit";
+  resourceType: "workflow" | "dataset" | "model" | "computing-unit";
   workflow?: DashboardWorkflow;
-  file?: DashboardFile;
   dataset?: DashboardDataset;
   model?: DashboardModel;
 }
diff --git a/frontend/src/app/dashboard/type/type-predicates.spec.ts 
b/frontend/src/app/dashboard/type/type-predicates.spec.ts
index 6033636607..90a3894da7 100644
--- a/frontend/src/app/dashboard/type/type-predicates.spec.ts
+++ b/frontend/src/app/dashboard/type/type-predicates.spec.ts
@@ -17,14 +17,8 @@
  * under the License.
  */
 
-import {
-  isDashboardDataset,
-  isDashboardFile,
-  isDashboardWorkflow,
-  isDashboardWorkflowComputingUnit,
-} from "./type-predicates";
+import { isDashboardDataset, isDashboardWorkflow, 
isDashboardWorkflowComputingUnit } from "./type-predicates";
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
-import { DashboardFile } from "./dashboard-file.interface";
 import { DashboardDataset } from "./dashboard-dataset.interface";
 import { DashboardWorkflowComputingUnit } from 
"../../common/type/workflow-computing-unit";
 import { ExecutionMode } from "../../common/type/workflow";
@@ -56,20 +50,6 @@ const workflowFixture: DashboardWorkflow = {
   coverImage: null,
 };
 
-const fileFixture: DashboardFile = {
-  ownerEmail: "[email protected]",
-  accessLevel: "READ",
-  file: {
-    ownerUid: 10,
-    fid: 7,
-    size: 1024,
-    name: "data.csv",
-    path: "/files/data.csv",
-    description: "A sample file",
-    uploadTime: 1700000000000,
-  },
-};
-
 const datasetFixture: DashboardDataset = {
   isOwner: false,
   ownerEmail: "[email protected]",
@@ -141,38 +121,6 @@ describe("isDashboardWorkflow", () => {
   });
 });
 
-describe("isDashboardFile", () => {
-  it("should return true for a realistic DashboardFile", () => {
-    expect(isDashboardFile(fileFixture)).toBe(true);
-  });
-
-  it("should return false for null and undefined", () => {
-    expect(isDashboardFile(null)).toBe(false);
-    expect(isDashboardFile(undefined)).toBe(false);
-  });
-
-  it("should return false for an empty object", () => {
-    expect(isDashboardFile({})).toBe(false);
-  });
-
-  it("should return false when ownerEmail is missing", () => {
-    expect(isDashboardFile({ file: fileFixture.file })).toBe(false);
-  });
-
-  it("should return false when file is missing", () => {
-    expect(isDashboardFile({ ownerEmail: "[email protected]" })).toBe(false);
-  });
-
-  it("should return false when ownerEmail is not a string", () => {
-    expect(isDashboardFile({ ownerEmail: 42, file: fileFixture.file 
})).toBe(false);
-  });
-
-  it("should return false when file is null", () => {
-    // A null payload must be rejected even though typeof null === "object".
-    expect(isDashboardFile({ ownerEmail: "[email protected]", file: null 
})).toBe(false);
-  });
-});
-
 describe("isDashboardDataset", () => {
   it("should return true for a realistic DashboardDataset", () => {
     expect(isDashboardDataset(datasetFixture)).toBe(true);
@@ -227,14 +175,12 @@ describe("isDashboardWorkflowComputingUnit", () => {
 describe("type predicate cross-classification", () => {
   const fixtures: ReadonlyArray<[string, unknown, string]> = [
     ["DashboardWorkflow fixture", workflowFixture, "isDashboardWorkflow"],
-    ["DashboardFile fixture", fileFixture, "isDashboardFile"],
     ["DashboardDataset fixture", datasetFixture, "isDashboardDataset"],
     ["DashboardWorkflowComputingUnit fixture", computingUnitFixture, 
"isDashboardWorkflowComputingUnit"],
   ];
 
   const predicates: ReadonlyArray<[string, (value: unknown) => boolean]> = [
     ["isDashboardWorkflow", isDashboardWorkflow],
-    ["isDashboardFile", isDashboardFile],
     ["isDashboardDataset", isDashboardDataset],
     ["isDashboardWorkflowComputingUnit", isDashboardWorkflowComputingUnit],
   ];
diff --git a/frontend/src/app/dashboard/type/type-predicates.ts 
b/frontend/src/app/dashboard/type/type-predicates.ts
index cfd4603a35..92e7de423b 100644
--- a/frontend/src/app/dashboard/type/type-predicates.ts
+++ b/frontend/src/app/dashboard/type/type-predicates.ts
@@ -18,7 +18,6 @@
  */
 
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
-import { DashboardFile } from "./dashboard-file.interface";
 import { DashboardDataset } from "./dashboard-dataset.interface";
 import { DashboardModel } from "./dashboard-model.interface";
 import { DashboardWorkflowComputingUnit } from 
"../../common/type/workflow-computing-unit";
@@ -28,10 +27,6 @@ export function isDashboardWorkflow(value: any): value is 
DashboardWorkflow {
   return !!value && isNonNullObject(value.workflow);
 }
 
-export function isDashboardFile(value: any): value is DashboardFile {
-  return !!value && typeof value.ownerEmail === "string" && 
isNonNullObject(value.file);
-}
-
 export function isDashboardDataset(value: any): value is DashboardDataset {
   return !!value && isNonNullObject(value.dataset);
 }
diff --git a/frontend/src/app/hub/service/hub.service.ts 
b/frontend/src/app/hub/service/hub.service.ts
index 7618616e21..c1d337b124 100644
--- a/frontend/src/app/hub/service/hub.service.ts
+++ b/frontend/src/app/hub/service/hub.service.ts
@@ -30,7 +30,6 @@ export enum EntityType {
   Workflow = "workflow",
   Dataset = "dataset",
   Model = "model",
-  File = "file",
   ComputingUnit = "computing-unit",
 }
 

Reply via email to