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";
