Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion core/gui/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,15 @@
"node_modules/jointjs/css/themes/default.css",
"node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
"node_modules/ng-zorro-antd/resizable/style/index.min.css",
"node_modules/bootstrap/dist/css/bootstrap.css",
"node_modules/bootstrap-markdown/css/bootstrap-markdown.min.css",
"node_modules/font-awesome/css/font-awesome.css",
"src/styles.scss"
],
"scripts": [
"./node_modules/marked/marked.min.js"
"./node_modules/marked/marked.min.js",
"node_modules/jquery/dist/jquery.js",
"node_modules/bootstrap-markdown/js/bootstrap-markdown.js"
],
"customWebpackConfig": {
"path": "./custom-webpack.config.js"
Expand Down
7 changes: 7 additions & 0 deletions core/gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,21 @@
"@types/lodash-es": "4.17.4",
"@types/plotly.js-basic-dist-min": "2.12.4",
"ajv": "8.10.0",
"angular-markdown-editor": "^3.1.1",
"backbone": "1.4.1",
"bootstrap": "^5.3.7",
"bootstrap-markdown": "^2.10.0",
"content-disposition": "0.5.4",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the versions of the libraries you introduced by removing ^

"dagre": "0.8.5",
"deep-map": "2.0.0",
"edit-distance": "1.0.4",
"es6-weak-map": "2.0.3",
"file-saver": "2.0.5",
"font-awesome": "^4.7.0",
"fuse.js": "6.5.3",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

"html2canvas": "1.4.1",
"jointjs": "3.5.4",
"jquery": "^3.7.1",
"js-abbreviation-number": "1.4.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move it to the dependee package, and leave a comment

"jszip": "3.10.1",
"lodash-es": "4.17.21",
Expand Down Expand Up @@ -111,11 +116,13 @@
"@nrwl/nx-cloud": "19.1.0",
"@nx/angular": "20.0.3",
"@types/backbone": "1.4.15",
"@types/bootstrap": "^5",
"@types/content-disposition": "0",
"@types/dagre": "0.7.47",
"@types/file-saver": "2.0.5",
"@types/graphlib": "2.1.8",
"@types/jasmine": "4.6.4",
"@types/jquery": "^3",
"@types/json-schema": "7.0.9",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aglinxinyuan Please take a look to see if both devDependencies & dependencies need to have these packages

"@types/lodash": "4.14.179",
"@types/node": "18.15.5",
Expand Down
4 changes: 4 additions & 0 deletions core/gui/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ import { AdminSettingsComponent } from "./dashboard/component/admin/settings/adm
import { catchError, of } from "rxjs";
import { FormlyRepeatDndComponent } from "./common/formly/repeat-dnd/repeat-dnd.component";
import { NzInputNumberModule } from "ng-zorro-antd/input-number";
import { UserDatasetFileEditorComponent } from "./dashboard/component/user/user-dataset/user-dataset-explorer/user-dataset-file-editor/user-dataset-file-editor.component";
import { AngularMarkdownEditorModule } from "angular-markdown-editor";

registerLocaleData(en);

Expand Down Expand Up @@ -264,6 +266,7 @@ registerLocaleData(en);
HubSearchResultComponent,
ComputingUnitSelectionComponent,
AdminSettingsComponent,
UserDatasetFileEditorComponent,
],
imports: [
BrowserModule,
Expand Down Expand Up @@ -330,6 +333,7 @@ registerLocaleData(en);
NzDividerModule,
NzProgressModule,
NzInputNumberModule,
AngularMarkdownEditorModule.forRoot(),
],
providers: [
provideNzI18n(en_US),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ <h3 class="file-title">
</h3>
</div>
<div style="display: flex">
<button
nz-button
*ngIf="isEditableFile(currentDisplayedFileName)"
nz-tooltip="Edit File"
[disabled]="!isLogin || userDatasetAccessLevel !== 'WRITE'"
(click)="onClickEditFile()">
<i
nz-icon
nzTheme="outline"
nzType="edit">
</i>
</button>
<button
nz-button
*ngIf="selectedVersion"
Expand Down Expand Up @@ -172,11 +184,30 @@ <h3 class="file-title">
</div>
</div>
</nz-card>

<nz-empty
class="empty-version-indicator"
*ngIf="!selectedVersion"
nzNotFoundContent="No version is selected"></nz-empty>

<!-- Use file editor for editable files -->
<texera-user-dataset-file-editor
*ngIf="selectedVersion && isEditMode"
[did]="did"
[dvid]="selectedVersion?.dvid"
[selectedVersion]="selectedVersion"
[datasetName]="datasetName"
[filePath]="currentDisplayedFileName"
[isMaximized]="isMaximized"
[userHasWriteAccess]="userDatasetAccessLevel === 'WRITE'"
[isLogin]="isLogin"
[chunkSizeMB]="chunkSizeMB"
[maxConcurrentChunks]="maxConcurrentChunks"
[isEditMode]="isEditMode"
(userMakeChanges)="onFileChanged()"
(editCanceled)="exitEditMode()">
</texera-user-dataset-file-editor>

<texera-user-dataset-file-renderer
*ngIf="selectedVersion"
[isMaximized]="isMaximized"
Expand Down Expand Up @@ -259,6 +290,25 @@ <h6 style="font-weight: lighter; font-size: 0.9em">Choose a Version:</h6>
</div>
</ng-container>
</div>

<!-- Simple README creation in sidebar -->
<div
*ngIf="userDatasetAccessLevel === 'WRITE' && !hasReadmeFile()"
class="create-readme-section">
<button
nz-button
nzType="default"
nzSize="small"
class="compact-readme-btn"
[nzLoading]="isCreatingReadme"
(click)="onClickCreateReadme()">
<i
nz-icon
nzType="file-add"></i>
Create README.md
</button>
</div>

<texera-user-dataset-version-filetree
[fileTreeNodes]="fileTreeNodeList"
[isTreeNodeDeletable]="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,26 @@ nz-select {
margin-left: 20px;
}

.create-readme-section {
margin-bottom: 8px;
display: flex;
justify-content: center;

button[nzType="default"] {
border-color: #1890ff;
color: #1890ff;

&:hover {
border-color: #40a9ff;
color: #40a9ff;
background-color: #f0f8ff;
}

&:focus {
border-color: #40a9ff;
color: #40a9ff;
}
}
.upload-progress-wrapper-pending {
display: flex;
flex-direction: column;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { DatasetStagedObject } from "../../../../../common/type/dataset-staged-o
import { NzModalService } from "ng-zorro-antd/modal";
import { UserDatasetVersionCreatorComponent } from "./user-dataset-version-creator/user-dataset-version-creator.component";
import { AdminSettingsService } from "../../../../service/admin/settings/admin-settings.service";
import { of } from "rxjs";
import { HttpErrorResponse } from "@angular/common/http";
import { Subscription } from "rxjs";
import { formatSpeed, formatTime } from "src/app/common/util/format.util";
Expand Down Expand Up @@ -102,6 +103,9 @@ export class DatasetDetailComponent implements OnInit {
versionName: string = "";
isCreatingVersion: boolean = false;

public isCreatingReadme: boolean = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this

public isEditMode: boolean = false;

// List of upload tasks – each task tracked by its filePath
public uploadTasks: Array<
MultipartUploadProgress & {
Expand Down Expand Up @@ -221,6 +225,149 @@ export class DatasetDetailComponent implements OnInit {
}
}

public onFileChanged(): void {
this.userMakeChanges.emit();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this, simply reload the dataset to show the latest version


// Get the current filename to re-select after refresh
const currentFileName = this.currentDisplayedFileName;

this.retrieveDatasetVersionList();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the subscribe style to achieve the call handling


// Wait a bit for the version list to update, then refresh the current version
setTimeout(() => {
if (this.versions.length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this

// Select the latest version (newly created)
this.selectedVersion = this.versions[0];

// Refresh the file tree for the new version
if (this.did && this.selectedVersion.dvid) {
this.datasetService
.retrieveDatasetVersionFileTree(this.did, this.selectedVersion.dvid, this.isLogin)
.pipe(untilDestroyed(this))
.subscribe(data => {
this.fileTreeNodeList = data.fileNodes;
this.currentDatasetVersionSize = data.size;

// Try to find and re-select the same file we were editing
const fileNode = this.findFileInTree(currentFileName);
if (fileNode) {
this.loadFileContent(fileNode);
} else {
// Fallback to first file if our file isn't found
let currentNode = this.fileTreeNodeList[0];
while (currentNode && currentNode.type === "directory" && currentNode.children) {
currentNode = currentNode.children[0];
}
if (currentNode) {
this.loadFileContent(currentNode);
}
}
});
}
}
}, 500); // Small delay to ensure backend has processed the new version

this.exitEditMode();
}

private findFileInTree(fileName: string, nodes: DatasetFileNode[] = this.fileTreeNodeList): DatasetFileNode | null {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this, by default, show the README.md(if any) of a dataset version when users open a dataset, otherwise, show the first file in the file tree.

for (const node of nodes) {
if (node.name === fileName && node.type === "file") {
return node;
}
if (node.children) {
const found = this.findFileInTree(fileName, node.children);
if (found) {
return found;
}
}
}
return null;
}

public onClickCreateReadme(): void {
this.modalService.confirm({
nzTitle: "Create README.md",
nzContent: "Are you sure you want to create a README.md file for this dataset?",
nzOkText: "Yes, Create",
nzCancelText: "Cancel",
nzOnOk: () => {
this.createReadmeFile();
},
});
}

private createReadmeFile(): void {
if (!this.did) return;

this.isCreatingReadme = true;
const defaultReadmeContent = "# Dataset README\n\nDescribe your dataset here...";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace 'Dataset' with actual dataset name


this.datasetService
.getDataset(this.did, this.isLogin)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see if you can avoid this additional request

.pipe(
switchMap(dashboardDataset => {
const datasetName = dashboardDataset.dataset.name;
const readmeBlob = new Blob([defaultReadmeContent], { type: "text/markdown" });
const readmeFile = new File([readmeBlob], "README.md", { type: "text/markdown" });
return this.datasetService.multipartUpload(
datasetName,
"README.md",
readmeFile,
this.chunkSizeMB * 1024 * 1024,
this.maxConcurrentChunks
);
}),
switchMap(progress => {
if (progress.status === "finished") {
return this.datasetService.createDatasetVersion(this.did!, "Created README.md");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Created" => "Create"; "README.md" => "README"

}
return of(progress);
}),
untilDestroyed(this)
)
.subscribe({
next: result => {
if (result && typeof result === "object" && "dvid" in result) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this if

this.isCreatingReadme = false;
this.notificationService.success("README created successfully!");

this.currentDisplayedFileName = "README.md";
this.onFileChanged();

setTimeout(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

this.isEditMode = true;
}, 1000);
}
},
error: (error: unknown) => {
this.isCreatingReadme = false;
console.error("Error creating README:", error);
this.notificationService.error("Failed to create README");
},
});
}

public hasReadmeFile(): boolean {
return this.findFileInTree("README.md") !== null;
}

public isEditableFile(fileName: string): boolean {
const extension = fileName.toLowerCase().split(".").pop();
const editableExtensions = ["md", "markdown", "txt", "log", "yml", "yaml"];
return editableExtensions.includes(extension || "");
}

public onClickEditFile(): void {
if (!this.selectedVersion || !this.currentDisplayedFileName) return;

this.isEditMode = !this.isEditMode;
}

public exitEditMode(): void {
this.isEditMode = false;
}

onPublicStatusChange(checked: boolean): void {
// Handle the change in dataset public status
if (this.did) {
Expand Down Expand Up @@ -341,6 +488,8 @@ export class DatasetDetailComponent implements OnInit {
}

onVersionSelected(version: DatasetVersion): void {
this.exitEditMode();

this.selectedVersion = version;
if (this.did && this.selectedVersion.dvid)
this.datasetService
Expand All @@ -362,6 +511,7 @@ export class DatasetDetailComponent implements OnInit {
}

onVersionFileTreeNodeSelected(node: DatasetFileNode) {
this.exitEditMode();
this.loadFileContent(node);
}

Expand Down
Loading