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

yiconghuang pushed a commit to branch feat/add-model
in repository https://gitbox.apache.org/repos/asf/texera.git

commit 27d6a5c45979b62bb2db8cee1c93dafa038c6470
Author: Yicong Huang <[email protected]>
AuthorDate: Sun Aug 24 03:52:00 2025 -0700

    feat: upload a version of model
---
 core/gui/src/app/app-routing.constant.ts           |   4 +
 core/gui/src/app/app-routing.module.ts             |   7 +
 core/gui/src/app/app.module.ts                     |   4 +
 core/gui/src/app/common/type/dataset.ts            |  11 +-
 .../type/model-staged-object.ts}                   |  24 +--
 .../src/app/common/type/{dataset.ts => model.ts}   |  18 +-
 .../user/list-item/list-item.component.ts          |  18 +-
 .../dataset-detail.component.ts                    |   1 -
 .../model-detail.component.html                    |  28 ++--
 .../model-detail.component.ts                      | 182 ++++++++++-----------
 .../user-model-version-creator.component.ts        |  73 +++++----
 .../user-model-staged-objects-list.component.html} |   6 +-
 .../user-model-staged-objects-list.component.scss} |   0
 .../user-model-staged-objects-list.component.ts}   |  32 ++--
 .../user/user-model/user-model.component.ts        |   2 +-
 .../service/user/download/download.service.ts      |  27 +++
 .../dashboard/service/user/model/model.service.ts  | 118 ++++++-------
 .../dashboard/type/dashboard-dataset.interface.ts  |  12 +-
 core/gui/src/app/dashboard/type/dashboard-entry.ts |   3 +-
 ...t.interface.ts => dashboard-model.interface.ts} |  12 +-
 core/gui/src/app/dashboard/type/search-result.ts   |   3 +-
 core/gui/src/app/dashboard/type/type-predicates.ts |   3 +-
 22 files changed, 302 insertions(+), 286 deletions(-)

diff --git a/core/gui/src/app/app-routing.constant.ts 
b/core/gui/src/app/app-routing.constant.ts
index db50133d66..063fc246ac 100644
--- a/core/gui/src/app/app-routing.constant.ts
+++ b/core/gui/src/app/app-routing.constant.ts
@@ -28,6 +28,10 @@ export const DASHBOARD_HUB_WORKFLOW_RESULT_DETAIL = 
`${DASHBOARD_HUB_WORKFLOW_RE
 export const DASHBOARD_HUB_DATASET = `${DASHBOARD_HUB}/dataset`;
 export const DASHBOARD_HUB_DATASET_RESULT = `${DASHBOARD_HUB_DATASET}/result`;
 export const DASHBOARD_HUB_DATASET_RESULT_DETAIL = 
`${DASHBOARD_HUB_DATASET_RESULT}/detail`;
+export const DASHBOARD_HUB_MODEL = `${DASHBOARD_HUB}/model`;
+export const DASHBOARD_HUB_MODEL_RESULT = `${DASHBOARD_HUB_DATASET}/result`;
+export const DASHBOARD_HUB_MODEL_RESULT_DETAIL = 
`${DASHBOARD_HUB_DATASET_RESULT}/detail`;
+
 
 export const DASHBOARD_USER = `${DASHBOARD}/user`;
 export const DASHBOARD_USER_PROJECT = `${DASHBOARD_USER}/project`;
diff --git a/core/gui/src/app/app-routing.module.ts 
b/core/gui/src/app/app-routing.module.ts
index f8472bd57e..cd01845e4c 100644
--- a/core/gui/src/app/app-routing.module.ts
+++ b/core/gui/src/app/app-routing.module.ts
@@ -45,6 +45,9 @@ import { GuiConfigService } from 
"./common/service/gui-config.service";
 import { Router, CanActivateFn } from "@angular/router";
 import { DASHBOARD_ABOUT } from "./app-routing.constant";
 import { UserModelComponent } from 
"./dashboard/component/user/user-model/user-model.component";
+import {
+  ModelDetailComponent
+} from 
"./dashboard/component/user/user-model/user-dataset-explorer/model-detail.component";
 
 const rootRedirectGuard: CanActivateFn = () => {
   const config = inject(GuiConfigService);
@@ -132,6 +135,10 @@ routes.push({
           path: "model",
           component: UserModelComponent,
         },
+        {
+          path: "model/:mid",
+          component: ModelDetailComponent,
+        },
         {
           path: "dataset/:did",
           component: DatasetDetailComponent,
diff --git a/core/gui/src/app/app.module.ts b/core/gui/src/app/app.module.ts
index 4b07f986a3..9b6f79e61b 100644
--- a/core/gui/src/app/app.module.ts
+++ b/core/gui/src/app/app.module.ts
@@ -179,6 +179,9 @@ import {
 import {
   ModelDetailComponent
 } from 
"./dashboard/component/user/user-model/user-dataset-explorer/model-detail.component";
+import {
+  UserModelStagedObjectsListComponent
+} from 
"./dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component";
 
 registerLocaleData(en);
 
@@ -249,6 +252,7 @@ registerLocaleData(en);
     ContextMenuComponent,
     CoeditorUserIconComponent,
     InputAutoCompleteComponent,
+    UserModelStagedObjectsListComponent,
     FileSelectionComponent,
     CollabWrapperComponent,
     AboutComponent,
diff --git a/core/gui/src/app/common/type/dataset.ts 
b/core/gui/src/app/common/type/dataset.ts
index 44642d441a..343c0afcd2 100644
--- a/core/gui/src/app/common/type/dataset.ts
+++ b/core/gui/src/app/common/type/dataset.ts
@@ -40,14 +40,5 @@ export interface Dataset {
   creationTime: number | undefined;
 }
 
-export interface Model {
-  mid: number | undefined;
-  ownerUid: number | undefined;
-  name: string;
-  isPublic: boolean;
-  isDownloadable: boolean;
-  storagePath: string | undefined;
-  description: string;
-  creationTime: number | undefined;
-}
+
 
diff --git a/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts 
b/core/gui/src/app/common/type/model-staged-object.ts
similarity index 63%
copy from core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts
copy to core/gui/src/app/common/type/model-staged-object.ts
index d739bb43de..bc795db86a 100644
--- a/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts
+++ b/core/gui/src/app/common/type/model-staged-object.ts
@@ -17,22 +17,10 @@
  * under the License.
  */
 
-import { Dataset, Model, DatasetVersion } from "../../common/type/dataset";
-import { DatasetFileNode } from "../../common/type/datasetVersionFileTree";
-
-export interface DashboardDataset {
-  isOwner: boolean;
-  ownerEmail: string;
-  dataset: Dataset;
-  accessPrivilege: "READ" | "WRITE" | "NONE";
-  size: number;
-}
-
-export interface DashboardModel{
-  isOwner: boolean;
-  ownerEmail: string;
-  model: Model;
-  accessPrivilege: "READ" | "WRITE" | "NONE";
-  size: number;
+// Represents a staged dataset object change, corresponding to backend Diff
+export interface ModelStagedObject {
+  path: string;
+  pathType: "file" | "directory";
+  diffType: "added" | "removed" | "changed";
+  sizeBytes?: number; // Optional, only present for files
 }
-
diff --git a/core/gui/src/app/common/type/dataset.ts 
b/core/gui/src/app/common/type/model.ts
similarity index 79%
copy from core/gui/src/app/common/type/dataset.ts
copy to core/gui/src/app/common/type/model.ts
index 44642d441a..bb75b601e0 100644
--- a/core/gui/src/app/common/type/dataset.ts
+++ b/core/gui/src/app/common/type/model.ts
@@ -19,9 +19,9 @@
 
 import { DatasetFileNode } from "./datasetVersionFileTree";
 
-export interface DatasetVersion {
-  dvid: number | undefined;
-  did: number;
+export interface ModelVersion {
+  mvid: number | undefined;
+  mid: number;
   creatorUid: number;
   name: string;
   versionHash: string | undefined;
@@ -29,17 +29,6 @@ export interface DatasetVersion {
   fileNodes: DatasetFileNode[] | undefined;
 }
 
-export interface Dataset {
-  did: number | undefined;
-  ownerUid: number | undefined;
-  name: string;
-  isPublic: boolean;
-  isDownloadable: boolean;
-  storagePath: string | undefined;
-  description: string;
-  creationTime: number | undefined;
-}
-
 export interface Model {
   mid: number | undefined;
   ownerUid: number | undefined;
@@ -51,3 +40,4 @@ export interface Model {
   creationTime: number | undefined;
 }
 
+
diff --git 
a/core/gui/src/app/dashboard/component/user/list-item/list-item.component.ts 
b/core/gui/src/app/dashboard/component/user/list-item/list-item.component.ts
index 3463fbcf27..c6aa7574a7 100644
--- a/core/gui/src/app/dashboard/component/user/list-item/list-item.component.ts
+++ b/core/gui/src/app/dashboard/component/user/list-item/list-item.component.ts
@@ -44,9 +44,9 @@ import { formatSize } from 
"src/app/common/util/size-formatter.util";
 import { DatasetService, DEFAULT_DATASET_NAME } from 
"../../../service/user/dataset/dataset.service";
 import { NotificationService } from 
"../../../../common/service/notification/notification.service";
 import {
-  DASHBOARD_HUB_DATASET_RESULT_DETAIL,
+  DASHBOARD_HUB_DATASET_RESULT_DETAIL, DASHBOARD_HUB_MODEL_RESULT_DETAIL,
   DASHBOARD_HUB_WORKFLOW_RESULT_DETAIL,
-  DASHBOARD_USER_DATASET,
+  DASHBOARD_USER_DATASET, DASHBOARD_USER_MODEL,
   DASHBOARD_USER_PROJECT,
   DASHBOARD_USER_WORKSPACE,
 } from "../../../../app-routing.constant";
@@ -135,6 +135,18 @@ export class ListItemComponent implements OnChanges {
         this.iconType = "database";
         this.size = this.entry.size;
       }
+    } else if (this.entry.type === "model") {
+      if (typeof this.entry.id === "number") {
+        this.disableDelete = !this.entry.model.isOwner;
+        this.owners = this.entry.accessibleUserIds;
+        if (this.currentUid !== undefined && 
this.owners.includes(this.currentUid)) {
+          this.entryLink = [DASHBOARD_USER_MODEL, String(this.entry.id)];
+        } else {
+          this.entryLink = [DASHBOARD_HUB_MODEL_RESULT_DETAIL, 
String(this.entry.id)];
+        }
+        this.iconType = "database";
+        this.size = this.entry.size;
+      }
     } else if (this.entry.type === "file") {
       // not sure where to redirect
       this.iconType = "folder-open";
@@ -208,6 +220,8 @@ export class ListItemComponent implements OnChanges {
         .subscribe();
     } else if (this.entry.type === "dataset") {
       this.downloadService.downloadDataset(this.entry.id, 
this.entry.name).pipe(untilDestroyed(this)).subscribe();
+    } else if (this.entry.type === "model") {
+      this.downloadService.downloadModel(this.entry.id, 
this.entry.name).pipe(untilDestroyed(this)).subscribe();
     }
   };
 
diff --git 
a/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts
 
b/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts
index 9849bb2306..9736c46c1c 100644
--- 
a/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts
+++ 
b/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/dataset-detail.component.ts
@@ -103,7 +103,6 @@ export class DatasetDetailComponent implements OnInit {
 
   constructor(
     private route: ActivatedRoute,
-    private modalService: NzModalService,
     private datasetService: DatasetService,
     private notificationService: NotificationService,
     private downloadService: DownloadService,
diff --git 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.html
 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.html
index e0bee86403..6003e4283e 100644
--- 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.html
+++ 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.html
@@ -19,25 +19,25 @@
 
 <div *ngIf="!isMaximized">
   <nz-card>
-    <h2 class="dataset-title">Dataset: {{datasetName}}</h2>
+    <h2 class="dataset-title">Model: {{modelName}}</h2>
     <nz-card-meta
       style="padding-top: 10px"
-      nzDescription="Created at: {{datasetCreationTime}}"></nz-card-meta>
+      nzDescription="Created at: {{modelCreationTime}}"></nz-card-meta>
     <nz-card-meta
       style="padding-top: 20px"
-      nzDescription="{{datasetDescription}}"></nz-card-meta>
+      nzDescription="{{modelDescription}}"></nz-card-meta>
     <div
       class="workflow-panel"
       style="padding-top: 30px">
       <div
-        *ngIf="!(userDatasetAccessLevel === 'NONE')"
+        *ngIf="!(userModelAccessLevel === 'NONE')"
         class="dataset-controls">
         <div class="control-row">
           <label>Visibility:</label>
           <nz-switch
-            [ngModel]="datasetIsPublic"
+            [ngModel]="modelIsPublic"
             (ngModelChange)="onPublicStatusChange($event)"
-            [nzDisabled]="userDatasetAccessLevel !== 'WRITE'"
+            [nzDisabled]="userModelAccessLevel !== 'WRITE'"
             nzCheckedChildren="public"
             nzUnCheckedChildren="private"></nz-switch>
         </div>
@@ -46,7 +46,7 @@
           *ngIf="isOwner">
           <label>Download:</label>
           <nz-switch
-            [ngModel]="datasetIsDownloadable"
+            [ngModel]="modelIsDownloadable"
             (ngModelChange)="onDownloadableStatusChange($event)"
             nzCheckedChildren="allowed"
             nzUnCheckedChildren="blocked"></nz-switch>
@@ -171,8 +171,8 @@
     <texera-user-dataset-file-renderer
       *ngIf="selectedVersion"
       [isMaximized]="isMaximized"
-      [did]="did"
-      [dvid]="selectedVersion?.dvid"
+      [did]="mid"
+      [dvid]="selectedVersion?.mvid"
       [filePath]="currentDisplayedFileName"
       [fileSize]="currentFileSize"
       [isLogin]="isLogin"
@@ -237,7 +237,7 @@
                 nzType="database"
                 nzTheme="outline"
                 class="icon-database"></i>
-              Version Size: {{ formatSize(currentDatasetVersionSize) }}
+              Version Size: {{ formatSize(currentModelVersionSize) }}
             </div>
           </div>
           <texera-user-dataset-version-filetree
@@ -251,7 +251,7 @@
 
       <nz-divider></nz-divider>
       <nz-collapse
-        *ngIf="userDatasetAccessLevel === 'WRITE'"
+        *ngIf="userHasWriteAccess()"
         nzGhost>
         <nz-collapse-panel
           nzActive="true"
@@ -300,11 +300,11 @@
             </div>
           </div>
 
-          <texera-dataset-staged-objects-list
+          <texera-model-staged-objects-list
             [uploadTimeMap]="uploadTimeMap"
-            [did]="did"
+            [mid]="mid"
             [userMakeChangesEvent]="userMakeChanges"
-            
(stagedObjectsChanged)="onStagedObjectsUpdated($event)"></texera-dataset-staged-objects-list>
+            
(stagedObjectsChanged)="onStagedObjectsUpdated($event)"></texera-model-staged-objects-list>
           <div
             *ngIf="userHasWriteAccess() && userHasPendingChanges"
             class="version-creator">
diff --git 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.ts
 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.ts
index 0762021f0b..695b36dbd5 100644
--- 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.ts
+++ 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/model-detail.component.ts
@@ -20,14 +20,14 @@
 import { Component, EventEmitter, OnInit, Output } from "@angular/core";
 import { ActivatedRoute } from "@angular/router";
 import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";
-import { DatasetService, MultipartUploadProgress } from 
"../../../../service/user/dataset/dataset.service";
+import { ModelService, MultipartUploadProgress } from 
"../../../../service/user/model/model.service";
 import { NzResizeEvent } from "ng-zorro-antd/resizable";
 import {
   DatasetFileNode,
   getFullPathFromDatasetFileNode,
   getRelativePathFromDatasetFileNode,
 } from "../../../../../common/type/datasetVersionFileTree";
-import { DatasetVersion } from "../../../../../common/type/dataset";
+import { ModelVersion } from "../../../../../common/type/model";
 import { switchMap, throttleTime } from "rxjs/operators";
 import { NotificationService } from 
"../../../../../common/service/notification/notification.service";
 import { DownloadService } from 
"../../../../service/user/download/download.service";
@@ -36,13 +36,12 @@ import { UserService } from 
"../../../../../common/service/user/user.service";
 import { isDefined } from "../../../../../common/util/predicate";
 import { ActionType, EntityType, HubService, LikedStatus } from 
"../../../../../hub/service/hub.service";
 import { FileUploadItem } from "../../../../type/dashboard-file.interface";
-import { DatasetStagedObject } from 
"../../../../../common/type/dataset-staged-object";
 import { NzModalService } from "ng-zorro-antd/modal";
-import { UserModelVersionCreatorComponent } from 
"./user-dataset-version-creator/user-model-version-creator.component";
 import { AdminSettingsService } from 
"../../../../service/admin/settings/admin-settings.service";
 import { HttpErrorResponse } from "@angular/common/http";
 import { Subscription } from "rxjs";
 import { formatSpeed, formatTime } from "src/app/common/util/format.util";
+import { ModelStagedObject } from 
"../../../../../common/type/model-staged-object";
 
 export const THROTTLE_TIME_MS = 1000;
 
@@ -52,27 +51,27 @@ export const THROTTLE_TIME_MS = 1000;
   styleUrls: ["./model-detail.component.scss"],
 })
 export class ModelDetailComponent implements OnInit {
-  public did: number | undefined;
-  public datasetName: string = "";
-  public datasetDescription: string = "";
-  public datasetCreationTime: string = "";
-  public datasetIsPublic: boolean = false;
-  public datasetIsDownloadable: boolean = true;
-  public userDatasetAccessLevel: "READ" | "WRITE" | "NONE" = "NONE";
+  public mid: number | undefined;
+  public modelName: string = "";
+  public modelDescription: string = "";
+  public modelCreationTime: string = "";
+  public modelIsPublic: boolean = false;
+  public modelIsDownloadable: boolean = true;
+  public userModelAccessLevel: "READ" | "WRITE" | "NONE" = "NONE";
   public isOwner: boolean = false;
 
   public currentDisplayedFileName: string = "";
   public currentFileSize: number | undefined;
-  public currentDatasetVersionSize: number | undefined;
+  public currentModelVersionSize: number | undefined;
 
   public isRightBarCollapsed = false;
   public isMaximized = false;
 
-  public versions: ReadonlyArray<DatasetVersion> = [];
-  public selectedVersion: DatasetVersion | undefined;
+  public versions: ReadonlyArray<ModelVersion> = [];
+  public selectedVersion: ModelVersion | undefined;
   public fileTreeNodeList: DatasetFileNode[] = [];
 
-  public versionCreatorBaseVersion: DatasetVersion | undefined;
+  public versionCreatorBaseVersion: ModelVersion | undefined;
   public isLogin: boolean = this.userService.isLogin();
 
   public isLiked: boolean = false;
@@ -103,8 +102,7 @@ export class ModelDetailComponent implements OnInit {
 
   constructor(
     private route: ActivatedRoute,
-    private modalService: NzModalService,
-    private datasetService: DatasetService,
+    private modelService: ModelService,
     private notificationService: NotificationService,
     private downloadService: DownloadService,
     private userService: UserService,
@@ -136,28 +134,28 @@ export class ModelDetailComponent implements OnInit {
     this.route.params
       .pipe(
         switchMap(params => {
-          this.did = params["did"];
-          this.retrieveDatasetInfo();
-          this.retrieveDatasetVersionList();
+          this.mid = params["mid"];
+          this.retrieveModelInfo();
+          this.retrievemodelVersionList();
           return this.route.data; // or some other observable
         }),
         untilDestroyed(this)
       )
       .subscribe();
 
-    if (!isDefined(this.did)) {
+    if (!isDefined(this.mid)) {
       return;
     }
 
     this.hubService
-      .getCounts([EntityType.Dataset], [this.did], [ActionType.Like])
+      .getCounts([EntityType.Model], [this.mid], [ActionType.Like])
       .pipe(untilDestroyed(this))
       .subscribe(counts => {
         this.likeCount = counts[0].counts.like ?? 0;
       });
 
     this.hubService
-      .postView(this.did, this.currentUid ? this.currentUid : 0, 
EntityType.Dataset)
+      .postView(this.mid, this.currentUid ? this.currentUid : 0, 
EntityType.Model)
       .pipe(throttleTime(THROTTLE_TIME_MS))
       .pipe(untilDestroyed(this))
       .subscribe(count => {
@@ -169,7 +167,7 @@ export class ModelDetailComponent implements OnInit {
     }
 
     this.hubService
-      .isLiked([this.did], [EntityType.Dataset])
+      .isLiked([this.mid], [EntityType.Model])
       .pipe(untilDestroyed(this))
       .subscribe((isLiked: LikedStatus[]) => {
         this.isLiked = isLiked.length > 0 ? isLiked[0].isLiked : false;
@@ -179,18 +177,18 @@ export class ModelDetailComponent implements OnInit {
   }
 
   public onClickOpenVersionCreator() {
-    if (this.did && !this.isCreatingVersion) {
+    if (this.mid && !this.isCreatingVersion) {
       this.isCreatingVersion = true;
 
-      this.datasetService
-        .createDatasetVersion(this.did, this.versionName?.trim() || "")
+      this.modelService
+        .createModelVersion(this.mid, this.versionName?.trim() || "")
         .pipe(untilDestroyed(this))
         .subscribe({
           next: res => {
             this.notificationService.success("Version Created");
             this.isCreatingVersion = false;
             this.versionName = "";
-            this.retrieveDatasetVersionList();
+            this.retrievemodelVersionList();
             this.userMakeChanges.emit();
           },
           error: (res: unknown) => {
@@ -203,82 +201,83 @@ export class ModelDetailComponent implements OnInit {
   }
 
   public onClickDownloadVersionAsZip() {
-    if (this.did && this.selectedVersion && this.selectedVersion.dvid) {
+    if (this.mid && this.selectedVersion && this.selectedVersion.mvid) {
       this.downloadService
-        .downloadDatasetVersion(this.did, this.selectedVersion.dvid, 
this.datasetName, this.selectedVersion.name)
+        .downloadModelVersion(this.mid, this.selectedVersion.mvid, 
this.modelName, this.selectedVersion.name)
         .pipe(untilDestroyed(this))
         .subscribe();
     }
   }
 
   onPublicStatusChange(checked: boolean): void {
-    // Handle the change in dataset public status
-    if (this.did) {
-      this.datasetService
-        .updateDatasetPublicity(this.did)
+    // Handle the change in model public status
+    if (this.mid) {
+      this.modelService
+        .updateModelPublicity(this.mid)
         .pipe(untilDestroyed(this))
         .subscribe({
           next: (res: Response) => {
-            this.datasetIsPublic = checked;
+            this.modelIsPublic = checked;
             let state = "public";
-            if (!this.datasetIsPublic) {
+            if (!this.modelIsPublic) {
               state = "private";
             }
-            this.notificationService.success(`Dataset ${this.datasetName} is 
now ${state}`);
+            this.notificationService.success(`model ${this.modelName} is now 
${state}`);
           },
           error: (err: unknown) => {
-            this.notificationService.error("Fail to change the dataset 
publicity");
+            this.notificationService.error("Fail to change the model 
publicity");
           },
         });
     }
   }
 
   onDownloadableStatusChange(checked: boolean): void {
-    // Handle the change in dataset downloadable status
-    if (this.did) {
-      this.datasetService
-        .updateDatasetDownloadable(this.did)
+    // Handle the change in model downloadable status
+    if (this.mid) {
+      this.modelService
+        .updateModelDownloadable(this.mid)
         .pipe(untilDestroyed(this))
         .subscribe({
           next: (res: Response) => {
-            this.datasetIsDownloadable = checked;
+            this.modelIsDownloadable = checked;
             let state = "allowed";
-            if (!this.datasetIsDownloadable) {
+            if (!this.modelIsDownloadable) {
               state = "not allowed";
             }
-            this.notificationService.success(`Dataset downloads are now 
${state}`);
+            this.notificationService.success(`model downloads are now 
${state}`);
           },
           error: (err: unknown) => {
-            this.notificationService.error("Failed to change the dataset 
download permission");
+            this.notificationService.error("Failed to change the model 
download permission");
           },
         });
     }
   }
 
-  retrieveDatasetInfo() {
-    if (this.did) {
-      this.datasetService
-        .getDataset(this.did, this.isLogin)
+  retrieveModelInfo() {
+    if (this.mid) {
+      this.modelService
+        .getModel(this.mid, this.isLogin)
         .pipe(untilDestroyed(this))
-        .subscribe(dashboardDataset => {
-          const dataset = dashboardDataset.dataset;
-          this.datasetName = dataset.name;
-          this.datasetDescription = dataset.description;
-          this.userDatasetAccessLevel = dashboardDataset.accessPrivilege;
-          this.datasetIsPublic = dataset.isPublic;
-          this.datasetIsDownloadable = dataset.isDownloadable;
-          this.isOwner = dashboardDataset.isOwner;
-          if (typeof dataset.creationTime === "number") {
-            this.datasetCreationTime = new 
Date(dataset.creationTime).toString();
+        .subscribe(dashboardModel => {
+          console.log("dashboardModel", dashboardModel);
+          const model = dashboardModel.model;
+          this.modelName = model.name;
+          this.modelDescription = model.description;
+          this.userModelAccessLevel = dashboardModel.accessPrivilege;
+          this.modelIsPublic = model.isPublic;
+          this.modelIsDownloadable = model.isDownloadable;
+          this.isOwner = dashboardModel.isOwner;
+          if (typeof model.creationTime === "number") {
+            this.modelCreationTime = new Date(model.creationTime).toString();
           }
         });
     }
   }
 
-  retrieveDatasetVersionList() {
-    if (this.did) {
-      this.datasetService
-        .retrieveDatasetVersionList(this.did, this.isLogin)
+  retrievemodelVersionList() {
+    if (this.mid) {
+      this.modelService
+        .retrieveModelVersionList(this.mid, this.isLogin)
         .pipe(untilDestroyed(this))
         .subscribe(versionNames => {
           this.versions = versionNames;
@@ -298,9 +297,9 @@ export class ModelDetailComponent implements OnInit {
   }
 
   onClickDownloadCurrentFile = (): void => {
-    if (!this.did || !this.selectedVersion?.dvid) return;
-    // For public datasets accessed by non-owners, use public endpoint
-    const shouldUsePublicEndpoint = this.datasetIsPublic && !this.isOwner;
+    if (!this.mid || !this.selectedVersion?.mvid) return;
+    // For public models accessed by non-owners, use public endpoint
+    const shouldUsePublicEndpoint = this.modelIsPublic && !this.isOwner;
     this.downloadService
       .downloadSingleFile(this.currentDisplayedFileName, 
!shouldUsePublicEndpoint)
       .pipe(untilDestroyed(this))
@@ -315,19 +314,19 @@ export class ModelDetailComponent implements OnInit {
     this.isRightBarCollapsed = !this.isRightBarCollapsed;
   }
 
-  onStagedObjectsUpdated(stagedObjects: DatasetStagedObject[]) {
+  onStagedObjectsUpdated(stagedObjects: ModelStagedObject[]) {
     this.userHasPendingChanges = stagedObjects.length > 0;
   }
 
-  onVersionSelected(version: DatasetVersion): void {
+  onVersionSelected(version: ModelVersion): void {
     this.selectedVersion = version;
-    if (this.did && this.selectedVersion.dvid)
-      this.datasetService
-        .retrieveDatasetVersionFileTree(this.did, this.selectedVersion.dvid, 
this.isLogin)
+    if (this.mid && this.selectedVersion.mvid)
+      this.modelService
+        .retrieveModelVersionFileTree(this.mid, this.selectedVersion.mvid, 
this.isLogin)
         .pipe(untilDestroyed(this))
         .subscribe(data => {
           this.fileTreeNodeList = data.fileNodes;
-          this.currentDatasetVersionSize = data.size;
+          this.currentModelVersionSize = data.size;
           let currentNode = this.fileTreeNodeList[0];
           while (currentNode.type === "directory" && currentNode.children) {
             currentNode = currentNode.children[0];
@@ -341,7 +340,8 @@ export class ModelDetailComponent implements OnInit {
   }
 
   userHasWriteAccess(): boolean {
-    return this.userDatasetAccessLevel == "WRITE";
+    // console.log(this.userModelAccessLevel);
+    return this.userModelAccessLevel == "WRITE";
   }
 
   isDownloadAllowed(): boolean {
@@ -349,10 +349,10 @@ export class ModelDetailComponent implements OnInit {
     if (this.isOwner) {
       return true;
     }
-    // Non-owners can download if dataset is downloadable and they have access
-    // For public datasets, users have access even if userDatasetAccessLevel 
is 'NONE'
-    // For private datasets, users need explicit access 
(userDatasetAccessLevel !== 'NONE')
-    return this.datasetIsDownloadable && (this.datasetIsPublic || 
this.userDatasetAccessLevel !== "NONE");
+    // Non-owners can download if model is downloadable and they have access
+    // For public models, users have access even if userModelAccessLevel is 
'NONE'
+    // For private models, users need explicit access (userModelAccessLevel 
!== 'NONE')
+    return this.modelIsDownloadable && (this.modelIsPublic || 
this.userModelAccessLevel !== "NONE");
   }
 
   // Track multiple file by unique key
@@ -372,7 +372,7 @@ export class ModelDetailComponent implements OnInit {
   }
 
   onNewUploadFilesChanged(files: FileUploadItem[]) {
-    if (this.did) {
+    if (this.mid) {
       files.forEach((file, idx) => {
         // Cancel any existing upload for the same file to prevent progress 
confusion
         this.uploadSubscriptions.get(file.name)?.unsubscribe();
@@ -388,9 +388,9 @@ export class ModelDetailComponent implements OnInit {
           physicalAddress: "",
         });
         // Start multipart upload
-        const subscription = this.datasetService
+        const subscription = this.modelService
           .multipartUpload(
-            this.datasetName,
+            this.modelName,
             file.name,
             file.file,
             this.chunkSizeMB * 1024 * 1024,
@@ -466,9 +466,9 @@ export class ModelDetailComponent implements OnInit {
       subscription.unsubscribe();
       this.uploadSubscriptions.delete(task.filePath);
     }
-    this.datasetService
+    this.modelService
       .finalizeMultipartUpload(
-        this.datasetName,
+        this.modelName,
         task.filePath,
         task.uploadId,
         [],
@@ -492,9 +492,9 @@ export class ModelDetailComponent implements OnInit {
   }
 
   onPreviouslyUploadedFileDeleted(node: DatasetFileNode) {
-    if (this.did) {
-      this.datasetService
-        .deleteDatasetFile(this.did, getRelativePathFromDatasetFileNode(node))
+    if (this.mid) {
+      this.modelService
+        .deleteModelFile(this.mid, getRelativePathFromDatasetFileNode(node))
         .pipe(untilDestroyed(this))
         .subscribe({
           next: (res: Response) => {
@@ -524,19 +524,19 @@ export class ModelDetailComponent implements OnInit {
 
   toggleLike(): void {
     const userId = this.currentUid;
-    if (!isDefined(userId) || !isDefined(this.did)) {
+    if (!isDefined(userId) || !isDefined(this.mid)) {
       return;
     }
 
     if (this.isLiked) {
       this.hubService
-        .postUnlike(this.did, EntityType.Dataset)
+        .postUnlike(this.mid, EntityType.Model)
         .pipe(untilDestroyed(this))
         .subscribe((success: boolean) => {
           if (success) {
             this.isLiked = false;
             this.hubService
-              .getCounts([EntityType.Dataset], [this.did!], [ActionType.Like])
+              .getCounts([EntityType.Model], [this.mid!], [ActionType.Like])
               .pipe(untilDestroyed(this))
               .subscribe(counts => {
                 this.likeCount = counts[0].counts.like ?? 0;
@@ -545,13 +545,13 @@ export class ModelDetailComponent implements OnInit {
         });
     } else {
       this.hubService
-        .postLike(this.did, EntityType.Dataset)
+        .postLike(this.mid, EntityType.Model)
         .pipe(untilDestroyed(this))
         .subscribe((success: boolean) => {
           if (success) {
             this.isLiked = true;
             this.hubService
-              .getCounts([EntityType.Dataset], [this.did!], [ActionType.Like])
+              .getCounts([EntityType.Model], [this.mid!], [ActionType.Like])
               .pipe(untilDestroyed(this))
               .subscribe(counts => {
                 this.likeCount = counts[0].counts.like ?? 0;
diff --git 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-version-creator/user-model-version-creator.component.ts
 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-version-creator/user-model-version-creator.component.ts
index 9925a7a088..c11702af07 100644
--- 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-version-creator/user-model-version-creator.component.ts
+++ 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-version-creator/user-model-version-creator.component.ts
@@ -17,11 +17,10 @@
  * under the License.
  */
 
-import { Component, EventEmitter, inject, Input, OnInit, Output } from 
"@angular/core";
-import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { Component, inject, OnInit } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
 import { FormlyFieldConfig } from "@ngx-formly/core";
-import { DatasetService } from 
"../../../../../service/user/dataset/dataset.service";
-import { Dataset, Model } from "../../../../../../common/type/dataset";
+import { Model } from "../../../../../../common/type/model";
 import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";
 import { NotificationService } from 
"../../../../../../common/service/notification/notification.service";
 import { HttpErrorResponse } from "@angular/common/http";
@@ -58,8 +57,9 @@ export class UserModelVersionCreatorComponent implements 
OnInit {
     private modalRef: NzModalRef,
     private modelService: ModelService,
     private notificationService: NotificationService,
-    private formBuilder: FormBuilder
-  ) {}
+    private formBuilder: FormBuilder,
+  ) {
+  }
 
   ngOnInit() {
     this.setFormFields();
@@ -69,37 +69,38 @@ export class UserModelVersionCreatorComponent implements 
OnInit {
   private setFormFields() {
     this.fields = this.isCreatingVersion
       ? [
-          // Fields when isCreatingVersion is true
-          {
-            key: "versionDescription",
-            type: "input",
-            defaultValue: "",
-            templateOptions: {
-              label: "Describe the new version",
-              required: false,
-            },
+        // Fields when isCreatingVersion is true
+        {
+          key: "versionDescription",
+          type: "input",
+          defaultValue: "",
+          templateOptions: {
+            label: "Describe the new version",
+            required: false,
           },
-        ]
+        },
+      ]
       : [
-          // Fields when isCreatingVersion is false
-          {
-            key: "name",
-            type: "input",
-            templateOptions: {
-              label: "Name",
-              required: true,
-            },
+        // Fields when isCreatingVersion is false
+        {
+          key: "name",
+          type: "input",
+          templateOptions: {
+            label: "Name",
+            required: true,
           },
-          {
-            key: "description",
-            type: "input",
-            defaultValue: "",
-            templateOptions: {
-              label: "Description",
-            },
+        },
+        {
+          key: "description",
+          type: "input",
+          defaultValue: "",
+          templateOptions: {
+            label: "Description",
           },
-        ];
+        },
+      ];
   }
+
   get formControlNames(): string[] {
     return Object.keys(this.form.controls);
   }
@@ -145,7 +146,7 @@ export class UserModelVersionCreatorComponent implements 
OnInit {
     if (this.isCreatingVersion && this.mid) {
       const versionName = this.form.get("versionDescription")?.value;
       this.modelService
-        .createDatasetVersion(this.mid, versionName)
+        .createModelVersion(this.mid, versionName)
         .pipe(untilDestroyed(this))
         .subscribe({
           next: res => {
@@ -183,9 +184,10 @@ export class UserModelVersionCreatorComponent implements 
OnInit {
         .subscribe({
           next: res => {
             const msg = this.isDatasetNameSanitized
-              ? `Dataset '${originalName}' was sanitized to '${sanitizedName}' 
and created successfully.`
-              : `Dataset '${sanitizedName}' created successfully.`;
+              ? `Model '${originalName}' was sanitized to '${sanitizedName}' 
and created successfully.`
+              : `Model '${sanitizedName}' created successfully.`;
 
+              console.log("Created model:", res);
             this.notificationService.success(msg);
             this.isCreating = false;
             // if creation succeed, emit the created dashboard dataset
@@ -216,5 +218,4 @@ export class UserModelVersionCreatorComponent implements 
OnInit {
   protected readonly formatTime = formatTime;
 
 
-
 }
diff --git 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.html
 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.html
similarity index 92%
rename from 
core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.html
rename to 
core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.html
index 5b1dece350..a897785d06 100644
--- 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.html
+++ 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.html
@@ -21,8 +21,8 @@
   <nz-list
     nzBordered
     nzSize="small"
-    *ngIf="datasetStagedObjects.length > 0">
-    <nz-list-item *ngFor="let obj of datasetStagedObjects">
+    *ngIf="modelStagedObjects.length > 0">
+    <nz-list-item *ngFor="let obj of modelStagedObjects">
       <span>
         <nz-tag [nzColor]="obj.diffType === 'added' ? 'green' : 'red'"> {{ 
obj.diffType }} </nz-tag>
       </span>
@@ -53,6 +53,6 @@
   </nz-list>
 
   <nz-empty
-    *ngIf="datasetStagedObjects.length === 0"
+    *ngIf="modelStagedObjects.length === 0"
     nzNotFoundContent="No pending changes"></nz-empty>
 </div>
diff --git 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.scss
 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.scss
similarity index 100%
rename from 
core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.scss
rename to 
core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.scss
diff --git 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.ts
 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.ts
similarity index 76%
rename from 
core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.ts
rename to 
core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.ts
index 7856ff47ba..0b4e445de2 100644
--- 
a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-dataset-staged-objects-list/user-dataset-staged-objects-list.component.ts
+++ 
b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-explorer/user-model-staged-objects-list/user-model-staged-objects-list.component.ts
@@ -23,15 +23,17 @@ import { DatasetService } from 
"../../../../../service/user/dataset/dataset.serv
 import { NotificationService } from 
"../../../../../../common/service/notification/notification.service";
 import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";
 import { formatTime } from "src/app/common/util/format.util";
+import { ModelStagedObject } from 
"../../../../../../common/type/model-staged-object";
+import { ModelService } from "../../../../../service/user/model/model.service";
 
 @UntilDestroy()
 @Component({
-  selector: "texera-dataset-staged-objects-list",
-  templateUrl: "./user-dataset-staged-objects-list.component.html",
-  styleUrls: ["./user-dataset-staged-objects-list.component.scss"],
+  selector: "texera-model-staged-objects-list",
+  templateUrl: "./user-model-staged-objects-list.component.html",
+  styleUrls: ["./user-model-staged-objects-list.component.scss"],
 })
-export class UserDatasetStagedObjectsListComponent implements OnInit {
-  @Input() did?: number; // Dataset ID
+export class UserModelStagedObjectsListComponent implements OnInit {
+  @Input() mid?: number; // Model ID
   @Input() set userMakeChangesEvent(event: EventEmitter<void>) {
     if (event) {
       event.pipe(untilDestroyed(this)).subscribe(() => {
@@ -43,11 +45,11 @@ export class UserDatasetStagedObjectsListComponent 
implements OnInit {
 
   @Output() stagedObjectsChanged = new EventEmitter<DatasetStagedObject[]>(); 
// Emits staged objects list
 
-  datasetStagedObjects: DatasetStagedObject[] = [];
+  modelStagedObjects: ModelStagedObject[] = [];
   formatTime = formatTime;
 
   constructor(
-    private datasetService: DatasetService,
+    private modelService: ModelService,
     private notificationService: NotificationService
   ) {}
 
@@ -56,22 +58,22 @@ export class UserDatasetStagedObjectsListComponent 
implements OnInit {
   }
 
   private fetchDatasetStagedObjects(): void {
-    if (this.did != undefined) {
-      this.datasetService
-        .getDatasetDiff(this.did)
+    if (this.mid != undefined) {
+      this.modelService
+        .getModelDiff(this.mid)
         .pipe(untilDestroyed(this))
         .subscribe(diffs => {
-          this.datasetStagedObjects = diffs;
+          this.modelStagedObjects = diffs;
           // Emit the updated staged objects list
-          this.stagedObjectsChanged.emit(this.datasetStagedObjects);
+          this.stagedObjectsChanged.emit(this.modelStagedObjects);
         });
     }
   }
 
   onObjectReverted(objDiff: DatasetStagedObject) {
-    if (this.did) {
-      this.datasetService
-        .resetDatasetFileDiff(this.did, objDiff.path)
+    if (this.mid) {
+      this.modelService
+        .resetModelFileDiff(this.mid, objDiff.path)
         .pipe(untilDestroyed(this))
         .subscribe({
           next: (res: Response) => {
diff --git 
a/core/gui/src/app/dashboard/component/user/user-model/user-model.component.ts 
b/core/gui/src/app/dashboard/component/user/user-model/user-model.component.ts
index b3a2a1bd9b..e78bce419f 100644
--- 
a/core/gui/src/app/dashboard/component/user/user-model/user-model.component.ts
+++ 
b/core/gui/src/app/dashboard/component/user/user-model/user-model.component.ts
@@ -37,7 +37,7 @@ import { NzModalService } from "ng-zorro-antd/modal";
 import { FileSelectionComponent } from 
"../../../../workspace/component/file-selection/file-selection.component";
 import { DatasetFileNode, getFullPathFromDatasetFileNode } from 
"../../../../common/type/datasetVersionFileTree";
 import { UserModelVersionCreatorComponent } from 
"./user-dataset-explorer/user-dataset-version-creator/user-model-version-creator.component";
-import { DashboardModel } from "../../../type/dashboard-dataset.interface";
+import { DashboardModel } from "../../../type/dashboard-model.interface";
 import { NzMessageService } from "ng-zorro-antd/message";
 import { map, tap } from "rxjs/operators";
 
diff --git 
a/core/gui/src/app/dashboard/service/user/download/download.service.ts 
b/core/gui/src/app/dashboard/service/user/download/download.service.ts
index 9c19cf19e2..663cb8df50 100644
--- a/core/gui/src/app/dashboard/service/user/download/download.service.ts
+++ b/core/gui/src/app/dashboard/service/user/download/download.service.ts
@@ -30,6 +30,7 @@ import { AppSettings } from "../../../../common/app-setting";
 import { HttpClient, HttpResponse } from "@angular/common/http";
 import { WORKFLOW_EXECUTIONS_API_BASE_URL } from 
"../workflow-executions/workflow-executions.service";
 import { DashboardWorkflowComputingUnit } from 
"../../../../workspace/types/workflow-computing-unit";
+import { ModelService } from "../model/model.service";
 var contentDisposition = require("content-disposition");
 
 export const EXPORT_BASE_URL = "result/export";
@@ -52,6 +53,7 @@ export class DownloadService {
     private fileSaverService: FileSaverService,
     private notificationService: NotificationService,
     private datasetService: DatasetService,
+    private modelService: ModelService,
     private workflowPersistService: WorkflowPersistService,
     private http: HttpClient
   ) {}
@@ -78,6 +80,16 @@ export class DownloadService {
     );
   }
 
+  downloadModel(id: number, name: string): Observable<Blob> {
+    return this.downloadWithNotification(
+      () => this.modelService.retrieveModelVersionZip(id),
+      `${name}.zip`,
+      "Starting to download the latest version of the model as ZIP",
+      "The latest version of the model has been downloaded as ZIP",
+      "Error downloading the latest version of the model as ZIP"
+    );
+  }
+
   downloadDatasetVersion(
     datasetId: number,
     datasetVersionId: number,
@@ -93,6 +105,21 @@ export class DownloadService {
     );
   }
 
+  downloadModelVersion(
+    modelId: number,
+    modelVersionId: number,
+    datasetName: string,
+    versionName: string
+  ): Observable<Blob> {
+    return this.downloadWithNotification(
+      () => this.datasetService.retrieveDatasetVersionZip(modelId, 
modelVersionId),
+      `${datasetName}-${versionName}.zip`,
+      `Starting to download version ${versionName} as ZIP`,
+      `Version ${versionName} has been downloaded as ZIP`,
+      `Error downloading version '${versionName}' as ZIP`
+    );
+  }
+
   downloadSingleFile(filePath: string, isLogin: boolean = true): 
Observable<Blob> {
     const DEFAULT_FILE_NAME = "download";
     const fileName = filePath.split("/").pop() || DEFAULT_FILE_NAME;
diff --git a/core/gui/src/app/dashboard/service/user/model/model.service.ts 
b/core/gui/src/app/dashboard/service/user/model/model.service.ts
index d0f963013f..cec8c29c28 100644
--- a/core/gui/src/app/dashboard/service/user/model/model.service.ts
+++ b/core/gui/src/app/dashboard/service/user/model/model.service.ts
@@ -20,12 +20,12 @@
 import { Injectable } from "@angular/core";
 import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http";
 import { catchError, map, mergeMap, switchMap, tap, toArray } from 
"rxjs/operators";
-import { Dataset, DatasetVersion, Model } from 
"../../../../common/type/dataset";
+import { Model, ModelVersion } from "../../../../common/type/model";
 import { AppSettings } from "../../../../common/app-setting";
 import { EMPTY, forkJoin, from, Observable, of, throwError } from "rxjs";
-import { DashboardDataset } from "../../../type/dashboard-dataset.interface";
+import { DashboardModel } from "../../../type/dashboard-model.interface";
 import { DatasetFileNode } from 
"../../../../common/type/datasetVersionFileTree";
-import { DatasetStagedObject } from 
"../../../../common/type/dataset-staged-object";
+import { ModelStagedObject } from 
"../../../../common/type/model-staged-object";
 import { GuiConfigService } from 
"../../../../common/service/gui-config.service";
 
 export const MODEL_BASE_URL = "model";
@@ -42,10 +42,10 @@ export const DATASET_DELETE_URL = MODEL_BASE_URL + 
"/delete";
 export const DATASET_VERSION_BASE_URL = "version";
 export const DATASET_VERSION_RETRIEVE_LIST_URL = DATASET_VERSION_BASE_URL + 
"/list";
 export const DATASET_VERSION_LATEST_URL = DATASET_VERSION_BASE_URL + "/latest";
-export const DEFAULT_DATASET_NAME = "Untitled dataset";
+export const DEFAULT_DATASET_NAME = "Untitled model";
 export const DATASET_PUBLIC_VERSION_BASE_URL = "publicVersion";
 export const DATASET_PUBLIC_VERSION_RETRIEVE_LIST_URL = 
DATASET_PUBLIC_VERSION_BASE_URL + "/list";
-export const DATASET_GET_OWNERS_URL = MODEL_BASE_URL + "/user-dataset-owners";
+export const DATASET_GET_OWNERS_URL = MODEL_BASE_URL + "/user-model-owners";
 
 export interface MultipartUploadProgress {
   filePath: string;
@@ -67,8 +67,8 @@ export class ModelService {
     private config: GuiConfigService
   ) {}
 
-  public createModel(model: Model): Observable<DashboardDataset> {
-    return 
this.http.post<DashboardDataset>(`${AppSettings.getApiEndpoint()}/${MODEL_CREATE_URL}`,
 {
+  public createModel(model: Model): Observable<DashboardModel> {
+    return 
this.http.post<DashboardModel>(`${AppSettings.getApiEndpoint()}/${MODEL_CREATE_URL}`,
 {
       modelName: model.name,
       modelDescription: model.description,
       isModelPublic: model.isPublic,
@@ -76,20 +76,20 @@ export class ModelService {
     });
   }
 
-  public getDataset(did: number, isLogin: boolean = true): 
Observable<DashboardDataset> {
+  public getModel(mid: number, isLogin: boolean = true): 
Observable<DashboardModel> {
     const apiUrl = isLogin
-      ? `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}`
-      : `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/public/${did}`;
-    return this.http.get<DashboardDataset>(apiUrl);
+      ? `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${mid}`
+      : `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/public/${mid}`;
+    return this.http.get<DashboardModel>(apiUrl);
   }
 
   /**
-   * Retrieves a single file from a dataset version using a pre-signed URL.
-   * @param filePath Relative file path within the dataset.
+   * Retrieves a single file from a model version using a pre-signed URL.
+   * @param filePath Relative file path within the model.
    * @param isLogin Determine whether a user is currently logged in
    * @returns Observable<Blob>
    */
-  public retrieveDatasetVersionSingleFile(filePath: string, isLogin: boolean = 
true): Observable<Blob> {
+  public retrieveModelVersionSingleFile(filePath: string, isLogin: boolean = 
true): Observable<Blob> {
     const endpointSegment = isLogin ? "presign-download" : 
"public-presign-download";
     const endpoint = 
`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${endpointSegment}?filePath=${encodeURIComponent(filePath)}`;
 
@@ -99,12 +99,12 @@ export class ModelService {
   }
 
   /**
-   * Retrieves a zip file of a dataset version.
-   * @param did Dataset ID
-   * @param dvid (Optional) Dataset version ID. If omitted, the latest version 
is downloaded.
+   * Retrieves a zip file of a model version.
+   * @param did Model ID
+   * @param dvid (Optional) Model version ID. If omitted, the latest version 
is downloaded.
    * @returns An Observable that emits a Blob containing the zip file.
    */
-  public retrieveDatasetVersionZip(did: number, dvid?: number): 
Observable<Blob> {
+  public retrieveModelVersionZip(did: number, dvid?: number): Observable<Blob> 
{
     let params = new HttpParams();
 
     if (dvid !== undefined && dvid !== null) {
@@ -113,27 +113,27 @@ export class ModelService {
       params = params.set("latest", "true");
     }
 
-    return 
this.http.get(`${AppSettings.getApiEndpoint()}/dataset/${did}/versionZip`, {
+    return 
this.http.get(`${AppSettings.getApiEndpoint()}/model/${did}/versionZip`, {
       params,
       responseType: "blob",
     });
   }
 
-  public retrieveAccessibleDatasets(): Observable<DashboardDataset[]> {
-    return 
this.http.get<DashboardDataset[]>(`${AppSettings.getApiEndpoint()}/${DATASET_LIST_URL}`);
+  public retrieveAccessibleModels(): Observable<DashboardModel[]> {
+    return 
this.http.get<DashboardModel[]>(`${AppSettings.getApiEndpoint()}/${DATASET_LIST_URL}`);
   }
-  public createDatasetVersion(did: number, newVersion: string): 
Observable<DatasetVersion> {
+  public createModelVersion(did: number, newVersion: string): 
Observable<ModelVersion> {
     return this.http
       .post<{
-        datasetVersion: DatasetVersion;
+        modelVersion: ModelVersion;
         fileNodes: DatasetFileNode[];
       
}>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/version/create`, 
newVersion, {
         headers: { "Content-Type": "text/plain" },
       })
       .pipe(
         map(response => {
-          response.datasetVersion.fileNodes = response.fileNodes;
-          return response.datasetVersion;
+          response.modelVersion.fileNodes = response.fileNodes;
+          return response.modelVersion;
         })
       );
   }
@@ -143,7 +143,7 @@ export class ModelService {
    * with a concurrency limit on how many parts we process in parallel.
    */
   public multipartUpload(
-    datasetName: string,
+    modelName: string,
     filePath: string,
     file: File,
     partSize: number,
@@ -207,7 +207,7 @@ export class ModelService {
         };
       };
 
-      const subscription = this.initiateMultipartUpload(datasetName, filePath, 
partCount)
+      const subscription = this.initiateMultipartUpload(modelName, filePath, 
partCount)
         .pipe(
           switchMap(initiateResponse => {
             const { uploadId, presignedUrls, physicalAddress } = 
initiateResponse;
@@ -312,7 +312,7 @@ export class ModelService {
               toArray(),
               // 4) Finalize if all parts succeeded
               switchMap(() =>
-                this.finalizeMultipartUpload(datasetName, filePath, uploadId, 
uploadedParts, physicalAddress, false)
+                this.finalizeMultipartUpload(modelName, filePath, uploadId, 
uploadedParts, physicalAddress, false)
               ),
               tap(() => {
                 const finalTotalTime = (Date.now() - startTime) / 1000;
@@ -343,7 +343,7 @@ export class ModelService {
                 });
 
                 return this.finalizeMultipartUpload(
-                  datasetName,
+                  modelName,
                   filePath,
                   uploadId,
                   uploadedParts,
@@ -363,18 +363,18 @@ export class ModelService {
 
   /**
    * Initiates a multipart upload and retrieves presigned URLs for each part.
-   * @param datasetName Dataset Name
-   * @param filePath File path within the dataset
+   * @param modelName Model Name
+   * @param filePath File path within the model
    * @param numParts Number of parts for the multipart upload
    */
   private initiateMultipartUpload(
-    datasetName: string,
+    modelName: string,
     filePath: string,
     numParts: number
   ): Observable<{ uploadId: string; presignedUrls: string[]; physicalAddress: 
string }> {
     const params = new HttpParams()
       .set("type", "init")
-      .set("datasetName", datasetName)
+      .set("modelName", modelName)
       .set("filePath", encodeURIComponent(filePath))
       .set("numParts", numParts.toString());
 
@@ -389,7 +389,7 @@ export class ModelService {
    * Completes or aborts a multipart upload, sending part numbers and ETags to 
the backend.
    */
   public finalizeMultipartUpload(
-    datasetName: string,
+    modelName: string,
     filePath: string,
     uploadId: string,
     parts: { PartNumber: number; ETag: string }[],
@@ -398,7 +398,7 @@ export class ModelService {
   ): Observable<Response> {
     const params = new HttpParams()
       .set("type", isAbort ? "abort" : "finish")
-      .set("datasetName", datasetName)
+      .set("modelName", modelName)
       .set("filePath", encodeURIComponent(filePath))
       .set("uploadId", uploadId);
 
@@ -410,61 +410,61 @@ export class ModelService {
   }
 
   /**
-   * Resets a dataset file difference in LakeFS.
-   * @param did Dataset ID
+   * Resets a model file difference in LakeFS.
+   * @param did Model ID
    * @param filePath File path to reset
    */
-  public resetDatasetFileDiff(did: number, filePath: string): 
Observable<Response> {
+  public resetModelFileDiff(did: number, filePath: string): 
Observable<Response> {
     const params = new HttpParams().set("filePath", 
encodeURIComponent(filePath));
 
     return 
this.http.put<Response>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/diff`,
 {}, { params });
   }
 
   /**
-   * Deletes a dataset file from LakeFS.
-   * @param did Dataset ID
+   * Deletes a model file from LakeFS.
+   * @param did Model ID
    * @param filePath File path to delete
    */
-  public deleteDatasetFile(did: number, filePath: string): 
Observable<Response> {
+  public deleteModelFile(did: number, filePath: string): Observable<Response> {
     const params = new HttpParams().set("filePath", 
encodeURIComponent(filePath));
 
     return 
this.http.delete<Response>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/file`,
 { params });
   }
 
   /**
-   * Retrieves the list of uncommitted dataset changes (diffs).
-   * @param did Dataset ID
+   * Retrieves the list of uncommitted model changes (diffs).
+   * @param did Model ID
    */
-  public getDatasetDiff(did: number): Observable<DatasetStagedObject[]> {
-    return 
this.http.get<DatasetStagedObject[]>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/diff`);
+  public getModelDiff(did: number): Observable<ModelStagedObject[]> {
+    return 
this.http.get<ModelStagedObject[]>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/diff`);
   }
 
   /**
-   * retrieve a list of versions of a dataset. The list is sorted so that the 
latest versions are at front.
+   * retrieve a list of versions of a model. The list is sorted so that the 
latest versions are at front.
    * @param did
    * @param isLogin
    */
-  public retrieveDatasetVersionList(did: number, isLogin: boolean = true): 
Observable<DatasetVersion[]> {
+  public retrieveModelVersionList(did: number, isLogin: boolean = true): 
Observable<ModelVersion[]> {
     const apiEndPont = isLogin
       ? 
`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_VERSION_RETRIEVE_LIST_URL}`
       : 
`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_PUBLIC_VERSION_RETRIEVE_LIST_URL}`;
-    return this.http.get<DatasetVersion[]>(apiEndPont);
+    return this.http.get<ModelVersion[]>(apiEndPont);
   }
 
   /**
-   * retrieve the latest version of a dataset.
+   * retrieve the latest version of a model.
    * @param did
    */
-  public retrieveDatasetLatestVersion(did: number): Observable<DatasetVersion> 
{
+  public retrieveModelLatestVersion(did: number): Observable<ModelVersion> {
     return this.http
       .get<{
-        datasetVersion: DatasetVersion;
+        modelVersion: ModelVersion;
         fileNodes: DatasetFileNode[];
       
}>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_VERSION_LATEST_URL}`)
       .pipe(
         map(response => {
-          response.datasetVersion.fileNodes = response.fileNodes;
-          return response.datasetVersion;
+          response.modelVersion.fileNodes = response.fileNodes;
+          return response.modelVersion;
         })
       );
   }
@@ -475,7 +475,7 @@ export class ModelService {
    * @param dvid
    * @param isLogin
    */
-  public retrieveDatasetVersionFileTree(
+  public retrieveModelVersionFileTree(
     did: number,
     dvid: number,
     isLogin: boolean = true
@@ -486,32 +486,32 @@ export class ModelService {
     return this.http.get<{ fileNodes: DatasetFileNode[]; size: number 
}>(apiUrl);
   }
 
-  public deleteDatasets(did: number): Observable<Response> {
+  public deleteModels(did: number): Observable<Response> {
     return 
this.http.delete<Response>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}`);
   }
 
-  public updateDatasetName(did: number, name: string): Observable<Response> {
+  public updateModelName(did: number, name: string): Observable<Response> {
     return 
this.http.post<Response>(`${AppSettings.getApiEndpoint()}/${DATASET_UPDATE_NAME_URL}`,
 {
       did: did,
       name: name,
     });
   }
 
-  public updateDatasetDescription(did: number, description: string): 
Observable<Response> {
+  public updateModelDescription(did: number, description: string): 
Observable<Response> {
     return 
this.http.post<Response>(`${AppSettings.getApiEndpoint()}/${DATASET_UPDATE_DESCRIPTION_URL}`,
 {
       did: did,
       description: description,
     });
   }
 
-  public updateDatasetPublicity(did: number): Observable<Response> {
+  public updateModelPublicity(did: number): Observable<Response> {
     return this.http.post<Response>(
       
`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_UPDATE_PUBLICITY_URL}`,
       {}
     );
   }
 
-  public updateDatasetDownloadable(did: number): Observable<Response> {
+  public updateModelDownloadable(did: number): Observable<Response> {
     return this.http.post<Response>(
       
`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_UPDATE_DOWNLOADABLE_URL}`,
       {}
diff --git a/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts 
b/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts
index d739bb43de..88cae66bc8 100644
--- a/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts
+++ b/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts
@@ -17,8 +17,8 @@
  * under the License.
  */
 
-import { Dataset, Model, DatasetVersion } from "../../common/type/dataset";
-import { DatasetFileNode } from "../../common/type/datasetVersionFileTree";
+import { Dataset } from "../../common/type/dataset";
+import { Model } from "../../common/type/model";
 
 export interface DashboardDataset {
   isOwner: boolean;
@@ -28,11 +28,5 @@ export interface DashboardDataset {
   size: number;
 }
 
-export interface DashboardModel{
-  isOwner: boolean;
-  ownerEmail: string;
-  model: Model;
-  accessPrivilege: "READ" | "WRITE" | "NONE";
-  size: number;
-}
+
 
diff --git a/core/gui/src/app/dashboard/type/dashboard-entry.ts 
b/core/gui/src/app/dashboard/type/dashboard-entry.ts
index 1ba86eea88..551d7c6afe 100644
--- a/core/gui/src/app/dashboard/type/dashboard-entry.ts
+++ b/core/gui/src/app/dashboard/type/dashboard-entry.ts
@@ -20,7 +20,8 @@
 import { DashboardFile } from "./dashboard-file.interface";
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
 import { DashboardProject } from "./dashboard-project.interface";
-import { DashboardDataset, DashboardModel } from 
"./dashboard-dataset.interface";
+import { DashboardDataset} from "./dashboard-dataset.interface";
+import { DashboardModel } from "./dashboard-model.interface";
 import {
   isDashboardDataset,
   isDashboardFile,
diff --git a/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts 
b/core/gui/src/app/dashboard/type/dashboard-model.interface.ts
similarity index 72%
copy from core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts
copy to core/gui/src/app/dashboard/type/dashboard-model.interface.ts
index d739bb43de..f4a1c3296e 100644
--- a/core/gui/src/app/dashboard/type/dashboard-dataset.interface.ts
+++ b/core/gui/src/app/dashboard/type/dashboard-model.interface.ts
@@ -17,18 +17,10 @@
  * under the License.
  */
 
-import { Dataset, Model, DatasetVersion } from "../../common/type/dataset";
-import { DatasetFileNode } from "../../common/type/datasetVersionFileTree";
+import { Model } from "../../common/type/model";
 
-export interface DashboardDataset {
-  isOwner: boolean;
-  ownerEmail: string;
-  dataset: Dataset;
-  accessPrivilege: "READ" | "WRITE" | "NONE";
-  size: number;
-}
 
-export interface DashboardModel{
+export interface DashboardModel {
   isOwner: boolean;
   ownerEmail: string;
   model: Model;
diff --git a/core/gui/src/app/dashboard/type/search-result.ts 
b/core/gui/src/app/dashboard/type/search-result.ts
index 5720618cd8..5327aa9fc2 100644
--- a/core/gui/src/app/dashboard/type/search-result.ts
+++ b/core/gui/src/app/dashboard/type/search-result.ts
@@ -20,7 +20,8 @@
 import { DashboardFile } from "./dashboard-file.interface";
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
 import { DashboardProject } from "./dashboard-project.interface";
-import { DashboardDataset, DashboardModel } from 
"./dashboard-dataset.interface";
+import { DashboardDataset} from "./dashboard-dataset.interface";
+import {  DashboardModel } from "./dashboard-model.interface";
 import { DashboardEntry } from "./dashboard-entry";
 
 export interface SearchResultItem {
diff --git a/core/gui/src/app/dashboard/type/type-predicates.ts 
b/core/gui/src/app/dashboard/type/type-predicates.ts
index 53c7815940..111ed81f92 100644
--- a/core/gui/src/app/dashboard/type/type-predicates.ts
+++ b/core/gui/src/app/dashboard/type/type-predicates.ts
@@ -20,7 +20,8 @@
 import { DashboardWorkflow } from "./dashboard-workflow.interface";
 import { DashboardProject } from "./dashboard-project.interface";
 import { DashboardFile } from "./dashboard-file.interface";
-import { DashboardDataset, DashboardModel } from 
"./dashboard-dataset.interface";
+import { DashboardDataset} from "./dashboard-dataset.interface";
+import { DashboardModel } from "./dashboard-model.interface";
 
 export function isDashboardWorkflow(value: any): value is DashboardWorkflow {
   return value && typeof value.workflow === "object";

Reply via email to