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 900f4d182f03782985ddfb5683ac5a00f5140fae Author: Yicong Huang <[email protected]> AuthorDate: Wed Aug 27 02:37:55 2025 -0700 feat: add share and icons --- core/gui/src/app/app.module.ts | 4 ++ .../user/list-item/list-item.component.ts | 18 +++++- ...nt.html => user-model-list-item.component.html} | 32 +++++------ ...nt.scss => user-model-list-item.component.scss} | 0 ...ponent.ts => user-model-list-item.component.ts} | 65 +++++++++++----------- .../dashboard/service/user/model/model.service.ts | 54 +++++++++--------- 6 files changed, 97 insertions(+), 76 deletions(-) diff --git a/core/gui/src/app/app.module.ts b/core/gui/src/app/app.module.ts index acf9803b9c..b353e529e3 100644 --- a/core/gui/src/app/app.module.ts +++ b/core/gui/src/app/app.module.ts @@ -186,6 +186,9 @@ import { InputAutoCompleteModelComponent } from "./workspace/component/input-autocomplete-model/input-auto-complete-model.component"; import { ModelSelectionComponent } from "./workspace/component/model-selection/model-selection.component"; +import { + UserModelListItemComponent +} from "./dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component"; registerLocaleData(en); @@ -213,6 +216,7 @@ registerLocaleData(en); UserAvatarComponent, LocalLoginComponent, UserWorkflowComponent, + UserModelListItemComponent, UserQuotaComponent, RowModalComponent, OperatorLabelComponent, 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 c6aa7574a7..f4b298a660 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 @@ -51,6 +51,7 @@ import { DASHBOARD_USER_WORKSPACE, } from "../../../../app-routing.constant"; import { isDefined } from "../../../../common/util/predicate"; +import { ModelService } from "../../../service/user/model/model.service"; @UntilDestroy() @Component({ @@ -100,6 +101,7 @@ export class ListItemComponent implements OnChanges { private modalService: NzModalService, private workflowPersistService: WorkflowPersistService, private datasetService: DatasetService, + private modelService: ModelService, private modal: NzModalService, private hubService: HubService, private downloadService: DownloadService, @@ -144,7 +146,7 @@ export class ListItemComponent implements OnChanges { } else { this.entryLink = [DASHBOARD_HUB_MODEL_RESULT_DETAIL, String(this.entry.id)]; } - this.iconType = "database"; + this.iconType = "code-sandbox"; this.size = this.entry.size; } } else if (this.entry.type === "file") { @@ -202,6 +204,20 @@ export class ListItemComponent implements OnChanges { nzCentered: true, nzWidth: "700px", }); + }else if (this.entry.type === "model") { + modal = this.modalService.create({ + nzContent: ShareAccessComponent, + nzData: { + writeAccess: this.entry.accessLevel === "WRITE", + type: "model", + id: this.entry.id, + allOwners: await firstValueFrom(this.modelService.retrieveOwners()), + }, + nzFooter: null, + nzTitle: "Share this model with others", + nzCentered: true, + nzWidth: "700px", + }); } if (modal) { modal.componentInstance?.refresh.pipe(untilDestroyed(this)).subscribe(() => { diff --git a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.html b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.html similarity index 86% rename from core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.html rename to core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.html index 4f7d5e0195..d1ff4c9255 100644 --- a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.html +++ b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.html @@ -24,33 +24,33 @@ <nz-avatar [ngStyle]="{ 'background-color': 'grey', 'vertical-align': 'middle' }" [nzGap]="4" - [nzText]="'' + dataset.did" + [nzText]="'' + model.mid" nzSize="default"></nz-avatar> </nz-list-item-meta-avatar> - <!-- editable name of saved dataset --> + <!-- editable name of saved model --> <nz-list-item-meta-title class="meta-title-container"> <div class="dataset-item-meta-title"> <a *ngIf="!editingName; else customDatasetTitle " - [routerLink]="DASHBOARD_USER_DATASET + '/' + dataset.did" + [routerLink]="DASHBOARD_USER_DATASET + '/' + model.mid" class="dataset-name" - >{{ dataset.name }}</a + >{{ model.name }}</a > <ng-template #customDatasetTitle> <input #customName (focusout)="confirmUpdateDatasetCustomName(customName.value)" (keyup.enter)="confirmUpdateDatasetCustomName(customName.value)" - placeholder="{{ dataset.name }}" - value="{{ dataset.name }}" /> + placeholder="{{ model.name }}" + value="{{ model.name }}" /> </ng-template> <button *ngIf="editable && entry.accessPrivilege === 'WRITE'" (click)="editingName = true" nz-button - mat-card-title="Customize Dataset Name" - nz-tooltip="Customize Dataset Name" + mat-card-title="Customize Model Name" + nz-tooltip="Customize Model Name" nzSize="small" nzTooltipPlacement="bottom" nzType="text"> @@ -93,14 +93,14 @@ </div> </nz-list-item-meta-title> - <!-- editable description of saved dataset --> + <!-- editable description of saved model --> <nz-list-item-meta-description> <div class="dataset-item-meta-description"> <label *ngIf="!editingDescription; else customDatasetDescription " (click)="editingDescription = editable && entry.accessPrivilege == 'WRITE'" class="dataset-description-label"> - {{ dataset.description }} + {{ model.description }} </label> <ng-template #customDatasetDescription> <input @@ -109,7 +109,7 @@ (focusout)="confirmUpdateDatasetCustomDescription(customDescription.value)" (keyup.enter)="confirmUpdateDatasetCustomDescription(customDescription.value)" class="dataset-editable-description-input" - value="{{ dataset.description }}" + value="{{ model.description }}" maxlength="500" /> </ng-template> </div> @@ -121,8 +121,8 @@ <button (click)="onClickOpenShareAccess()" nz-button - nz-tooltip="Share the dataset {{ - dataset.name + nz-tooltip="Share the Model {{ + model.name }} to others" nzTooltipPlacement="bottom" type="button"> @@ -136,12 +136,12 @@ <button (nzOnConfirm)="deleted.emit()" nz-popconfirm - nzPopconfirmTitle="Confirm to delete this dataset." + nzPopconfirmTitle="Confirm to delete this Model." [disabled]="!entry.isOwner" class="delete-dataset-btn" nz-button - nz-tooltip="Delete the dataset {{ - dataset.name + nz-tooltip="Delete the model {{ + model.name }}" nzTooltipPlacement="bottom"> <i diff --git a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.scss b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.scss similarity index 100% rename from core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.scss rename to core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.scss diff --git a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.ts b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.ts similarity index 64% rename from core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.ts rename to core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.ts index c18d37ee0c..7b9a050a75 100644 --- a/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-dataset-list-item.component.ts +++ b/core/gui/src/app/dashboard/component/user/user-model/user-dataset-list-item/user-model-list-item.component.ts @@ -19,47 +19,47 @@ import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { Dataset } from "../../../../../common/type/dataset"; -import { DatasetService } from "../../../../service/user/dataset/dataset.service"; import { ShareAccessComponent } from "../../share-access/share-access.component"; import { NotificationService } from "../../../../../common/service/notification/notification.service"; import { NzModalService } from "ng-zorro-antd/modal"; -import { DashboardDataset } from "../../../../type/dashboard-dataset.interface"; import { DASHBOARD_USER_DATASET } from "../../../../../app-routing.constant"; +import { DashboardModel } from "../../../../type/dashboard-model.interface"; +import { Model } from "../../../../../common/type/model"; +import { ModelService } from "../../../../service/user/model/model.service"; @UntilDestroy() @Component({ - selector: "texera-user-dataset-list-item", - templateUrl: "./user-dataset-list-item.component.html", - styleUrls: ["./user-dataset-list-item.component.scss"], + selector: "texera-user-model-list-item", + templateUrl: "./user-model-list-item.component.html", + styleUrls: ["./user-model-list-item.component.scss"], }) -export class UserDatasetListItemComponent { +export class UserModelListItemComponent { protected readonly DASHBOARD_USER_DATASET = DASHBOARD_USER_DATASET; - private _entry?: DashboardDataset; + private _entry?: DashboardModel; @Output() refresh = new EventEmitter<void>(); @Input() - get entry(): DashboardDataset { + get entry(): DashboardModel { if (!this._entry) { throw new Error("entry property must be provided to UserDatasetListItemComponent."); } return this._entry; } - set entry(value: DashboardDataset) { + set entry(value: DashboardModel) { this._entry = value; } - get dataset(): Dataset { - if (!this.entry.dataset) { + get model(): Model { + if (!this.entry.model) { throw new Error( - "Incorrect type of DashboardEntry provided to UserDatasetListItemComponent. Entry must be dataset." + "Incorrect type of DashboardEntry provided to UserModelListItemComponent. Entry must be model.", ); } - return this.entry.dataset; + return this.entry.model; } @Input() editable = false; @@ -71,47 +71,48 @@ export class UserDatasetListItemComponent { constructor( private modalService: NzModalService, - private datasetService: DatasetService, - private notificationService: NotificationService - ) {} + private modelService: ModelService, + private notificationService: NotificationService, + ) { + } public confirmUpdateDatasetCustomName(name: string) { - if (this.entry.dataset.name === name) { + if (this.entry.model.name === name) { return; } - if (this.entry.dataset.did) - this.datasetService - .updateDatasetName(this.entry.dataset.did, name) + if (this.entry.model.mid) + this.modelService + .updateModelName(this.entry.model.mid, name) .pipe(untilDestroyed(this)) .subscribe({ next: () => { - this.entry.dataset.name = name; + this.entry.model.name = name; this.editingName = false; }, error: () => { - this.notificationService.error("Update dataset name failed"); + this.notificationService.error("Update model name failed"); this.editingName = false; }, }); } public confirmUpdateDatasetCustomDescription(description: string) { - if (this.entry.dataset.description === description) { + if (this.entry.model.description === description) { return; } - if (this.entry.dataset.did) - this.datasetService - .updateDatasetDescription(this.entry.dataset.did, description) + if (this.entry.model.mid) + this.modelService + .updateModelDescription(this.entry.model.mid, description) .pipe(untilDestroyed(this)) .subscribe({ next: () => { - this.entry.dataset.description = description; + this.entry.model.description = description; this.editingDescription = false; }, error: () => { - this.notificationService.error("Update dataset description failed"); + this.notificationService.error("Update model description failed"); this.editingDescription = false; }, }); @@ -122,11 +123,11 @@ export class UserDatasetListItemComponent { nzContent: ShareAccessComponent, nzData: { writeAccess: this.entry.accessPrivilege === "WRITE", - type: "dataset", - id: this.dataset.did, + type: "model", + id: this.model.mid, }, nzFooter: null, - nzTitle: "Share this dataset with others", + nzTitle: "Share this model with others", nzCentered: true, }); } 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 06042ab036..0670803583 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 @@ -30,22 +30,22 @@ import { GuiConfigService } from "../../../../common/service/gui-config.service" export const MODEL_BASE_URL = "model"; export const MODEL_CREATE_URL = MODEL_BASE_URL + "/create"; -export const DATASET_UPDATE_BASE_URL = MODEL_BASE_URL + "/update"; -export const DATASET_UPDATE_NAME_URL = DATASET_UPDATE_BASE_URL + "/name"; -export const DATASET_UPDATE_DESCRIPTION_URL = DATASET_UPDATE_BASE_URL + "/description"; -export const DATASET_UPDATE_PUBLICITY_URL = "update/publicity"; -export const DATASET_UPDATE_DOWNLOADABLE_URL = "update/downloadable"; -export const DATASET_LIST_URL = MODEL_BASE_URL + "/list"; -export const DATASET_SEARCH_URL = MODEL_BASE_URL + "/search"; -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 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-model-owners"; +export const MODEL_UPDATE_BASE_URL = MODEL_BASE_URL + "/update"; +export const MODEL_UPDATE_NAME_URL = MODEL_UPDATE_BASE_URL + "/name"; +export const MODEL_UPDATE_DESCRIPTION_URL = MODEL_UPDATE_BASE_URL + "/description"; +export const MODEL_UPDATE_PUBLICITY_URL = "update/publicity"; +export const MODEL_UPDATE_DOWNLOADABLE_URL = "update/downloadable"; +export const MODEL_LIST_URL = MODEL_BASE_URL + "/list"; +export const MODEL_SEARCH_URL = MODEL_BASE_URL + "/search"; +export const MODEL_DELETE_URL = MODEL_BASE_URL + "/delete"; + +export const MODEL_VERSION_BASE_URL = "version"; +export const MODEL_VERSION_RETRIEVE_LIST_URL = MODEL_VERSION_BASE_URL + "/list"; +export const MODEL_VERSION_LATEST_URL = MODEL_VERSION_BASE_URL + "/latest"; +export const DEFAULT_MODEL_NAME = "Untitled model"; +export const MODEL_PUBLIC_VERSION_BASE_URL = "publicVersion"; +export const MODEL_PUBLIC_VERSION_RETRIEVE_LIST_URL = MODEL_PUBLIC_VERSION_BASE_URL + "/list"; +export const MODEL_GET_OWNERS_URL = MODEL_BASE_URL + "/user-model-owners"; export interface MultipartUploadProgress { filePath: string; @@ -120,7 +120,7 @@ export class ModelService { } public retrieveAccessibleModels(): Observable<DashboardModel[]> { - return this.http.get<DashboardModel[]>(`${AppSettings.getApiEndpoint()}/${DATASET_LIST_URL}`); + return this.http.get<DashboardModel[]>(`${AppSettings.getApiEndpoint()}/${MODEL_LIST_URL}`); } public createModelVersion(did: number, newVersion: string): Observable<ModelVersion> { return this.http @@ -446,8 +446,8 @@ export class ModelService { */ 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}`; + ? `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${MODEL_VERSION_RETRIEVE_LIST_URL}` + : `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${MODEL_PUBLIC_VERSION_RETRIEVE_LIST_URL}`; return this.http.get<ModelVersion[]>(apiEndPont); } @@ -460,7 +460,7 @@ export class ModelService { .get<{ modelVersion: ModelVersion; fileNodes: DatasetFileNode[]; - }>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_VERSION_LATEST_URL}`) + }>(`${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${MODEL_VERSION_LATEST_URL}`) .pipe( map(response => { response.modelVersion.fileNodes = response.fileNodes; @@ -481,8 +481,8 @@ export class ModelService { isLogin: boolean = true ): Observable<{ fileNodes: DatasetFileNode[]; size: number }> { const apiUrl = isLogin - ? `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_VERSION_BASE_URL}/${dvid}/rootFileNodes` - : `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_PUBLIC_VERSION_BASE_URL}/${dvid}/rootFileNodes`; + ? `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${MODEL_VERSION_BASE_URL}/${dvid}/rootFileNodes` + : `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${MODEL_PUBLIC_VERSION_BASE_URL}/${dvid}/rootFileNodes`; return this.http.get<{ fileNodes: DatasetFileNode[]; size: number }>(apiUrl); } @@ -491,14 +491,14 @@ export class ModelService { } public updateModelName(did: number, name: string): Observable<Response> { - return this.http.post<Response>(`${AppSettings.getApiEndpoint()}/${DATASET_UPDATE_NAME_URL}`, { + return this.http.post<Response>(`${AppSettings.getApiEndpoint()}/${MODEL_UPDATE_NAME_URL}`, { did: did, name: name, }); } public updateModelDescription(did: number, description: string): Observable<Response> { - return this.http.post<Response>(`${AppSettings.getApiEndpoint()}/${DATASET_UPDATE_DESCRIPTION_URL}`, { + return this.http.post<Response>(`${AppSettings.getApiEndpoint()}/${MODEL_UPDATE_DESCRIPTION_URL}`, { did: did, description: description, }); @@ -506,19 +506,19 @@ export class ModelService { public updateModelPublicity(did: number): Observable<Response> { return this.http.post<Response>( - `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_UPDATE_PUBLICITY_URL}`, + `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${MODEL_UPDATE_PUBLICITY_URL}`, {} ); } public updateModelDownloadable(did: number): Observable<Response> { return this.http.post<Response>( - `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${DATASET_UPDATE_DOWNLOADABLE_URL}`, + `${AppSettings.getApiEndpoint()}/${MODEL_BASE_URL}/${did}/${MODEL_UPDATE_DOWNLOADABLE_URL}`, {} ); } public retrieveOwners(): Observable<string[]> { - return this.http.get<string[]>(`${AppSettings.getApiEndpoint()}/${DATASET_GET_OWNERS_URL}`); + return this.http.get<string[]>(`${AppSettings.getApiEndpoint()}/${MODEL_GET_OWNERS_URL}`); } }
