diff --git a/apps/showcase/package.json b/apps/showcase/package.json index d316b78ad9..ad8b9ef13b 100644 --- a/apps/showcase/package.json +++ b/apps/showcase/package.json @@ -84,7 +84,7 @@ "ngx-highlightjs": "^12.0.0", "ngx-markdown": "^18.1.0", "ngx-monaco-editor-v2": "^18.0.0", - "ngx-monaco-tree": "^18.1.0", + "ngx-monaco-tree": "^18.3.0", "pixelmatch": "^5.2.1", "pngjs": "^7.0.0", "prism-themes": "^1.9.0", diff --git a/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.html b/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.html index 1a87319958..86dc89549e 100644 --- a/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.html +++ b/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.html @@ -5,7 +5,7 @@ @@ -26,7 +26,7 @@ - @if (editorMode === 'interactive') { + @if (editorMode() === 'interactive') { diff --git a/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.ts b/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.ts index cde520843c..022b59bd60 100644 --- a/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.ts +++ b/apps/showcase/src/components/training/code-editor-view/code-editor-view.component.ts @@ -5,12 +5,12 @@ import { ChangeDetectionStrategy, Component, computed, + effect, ElementRef, inject, - Input, - OnChanges, + input, OnDestroy, - SimpleChanges, + untracked, ViewChild, ViewEncapsulation, } from '@angular/core'; @@ -119,7 +119,7 @@ export interface TrainingProject { templateUrl: './code-editor-view.component.html', styleUrl: './code-editor-view.component.scss' }) -export class CodeEditorViewComponent implements OnDestroy, OnChanges { +export class CodeEditorViewComponent implements OnDestroy { /** * @see {FormBuilder} */ @@ -142,13 +142,13 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { /** * Allow to edit the code in the monaco editor */ - @Input() public editorMode: EditorMode = 'readonly'; + public editorMode = input('readonly'); /** * Project to load in the code editor. * It should describe the files to load, the starting file, the folder dedicated to the project as well as the * commands to initialize the project */ - @Input() public project?: TrainingProject; + public project = input.required(); /** * Service to load files and run commands in the application instance of the webcontainer. */ @@ -177,9 +177,9 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { code: FormControl; file: FormControl; }> = this.formBuilder.group({ - code: '', - file: '' - }); + code: '', + file: '' + }); /** * Subject used to notify when monaco editor has been initialized @@ -201,7 +201,7 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { filter((filePath): filePath is string => !!filePath), map(() => ({ theme: 'vs-dark', - readOnly: (this.editorMode === 'readonly'), + readOnly: (this.editorMode() === 'readonly'), automaticLayout: true, scrollBeyondLastLine: false, overflowWidgetsDomNode: this.monacoOverflowWidgets.nativeElement, @@ -213,7 +213,7 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { takeUntilDestroyed(), combineLatestWith(this.cwdTree$), filter(([path, monacoTree]) => !!path && checkIfPathInMonacoTree(monacoTree, path.split('/'))), - switchMap(([path]) => from(this.webContainerService.readFile(`${this.project!.cwd}/${path}`).catch(() => ''))), + switchMap(([path]) => from(this.webContainerService.readFile(`${this.project().cwd}/${path}`).catch(() => ''))), share() ); @@ -235,6 +235,17 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { }); constructor() { + effect(async () => { + const project = this.project(); + await untracked(async () => { + if (project.files) { + // Remove link between launch project and terminals + await this.webContainerService.loadProject(project.files, project.commands, project.cwd); + } + await this.loadNewProject(); + this.cwd$.next(project?.cwd || ''); + }); + }); this.form.controls.code.valueChanges.pipe( distinctUntilChanged(), skip(1), @@ -246,7 +257,7 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { this.loggerService.error('No project found'); return; } - const path = `${this.project.cwd}/${this.form.controls.file.value}`; + const path = `${this.project().cwd}/${this.form.controls.file.value}`; this.loggerService.log('Writing file', path); void this.webContainerService.writeFile(path, text); }); @@ -268,10 +279,10 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { void this.monacoPromise.then((monaco) => { monaco.editor.registerEditorOpener({ openCodeEditor: (_source: Monaco.editor.ICodeEditor, resource: Monaco.Uri, selectionOrPosition?: Monaco.IRange | Monaco.IPosition) => { - if (resource && this.project?.files) { + if (resource && this.project().files) { const filePath = resource.path.slice(1); // TODO write a proper function to search in the tree - const flatFiles = flattenTree(this.project.files); + const flatFiles = flattenTree(this.project().files); if (flatFiles.some((projectFile) => projectFile.filePath === resource.path)) { this.form.controls.file.setValue(filePath); if (selectionOrPosition) { @@ -318,7 +329,7 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { */ private async loadAllProjectFilesToMonaco() { const monaco = await this.monacoPromise; - const flatFiles = flattenTree(this.project?.files!); + const flatFiles = flattenTree(this.project().files); flatFiles.forEach(({ filePath, content }) => { const language = editorOptionsLanguage[filePath.split('.').at(-1) || ''] || ''; monaco.editor.createModel(content, language, monaco.Uri.from({ scheme: 'file', path: filePath })); @@ -333,23 +344,23 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { * Load a new project in global monaco editor and update local form accordingly */ private async loadNewProject() { - await this.cleanAllModelsFromMonaco(); - await this.loadAllProjectFilesToMonaco(); - if (this.project?.startingFile) { - this.form.controls.file.setValue(this.project.startingFile); + if (this.project()?.startingFile) { + this.form.controls.file.setValue(this.project().startingFile); } else { this.form.controls.file.setValue(''); this.form.controls.code.setValue(''); } + await this.cleanAllModelsFromMonaco(); + await this.loadAllProjectFilesToMonaco(); } /** * Reload declaration types from web-container */ public async reloadDeclarationTypes() { - if (this.project?.cwd) { + if (this.project().cwd) { const declarationTypes = [ - ...await this.webContainerService.getDeclarationTypes(this.project.cwd), + ...await this.webContainerService.getDeclarationTypes(this.project().cwd), { filePath: 'file:///node_modules/@ama-sdk/core/index.d.ts', content: 'export * from "./src/public_api.d.ts";' }, { filePath: 'file:///node_modules/@ama-sdk/client-fetch/index.d.ts', content: 'export * from "./src/public_api.d.ts";' } ]; @@ -370,29 +381,12 @@ export class CodeEditorViewComponent implements OnDestroy, OnChanges { * @inheritDoc */ public async onClickFile(filePath: string) { - if (!this.project) { - return; - } - const path = `${this.project.cwd}/${filePath}`; - if (this.project && await this.webContainerService.isFile(path)) { + const path = `${this.project().cwd}/${filePath}`; + if (await this.webContainerService.isFile(path)) { this.form.controls.file.setValue(filePath); } } - /** - * @inheritDoc - */ - public ngOnChanges(changes: SimpleChanges) { - if ('project' in changes) { - if (this.project?.files) { - // Remove link between launch project and terminals - void this.webContainerService.loadProject(this.project.files, this.project.commands, this.project.cwd); - } - void this.loadNewProject(); - this.cwd$.next(this.project?.cwd || ''); - } - } - /** * @inheritDoc */ diff --git a/package.json b/package.json index d8e9998781..8d3eff8d24 100644 --- a/package.json +++ b/package.json @@ -257,7 +257,7 @@ "ngx-highlightjs": "^12.0.0", "ngx-markdown": "^18.1.0", "ngx-monaco-editor-v2": "^18.0.0", - "ngx-monaco-tree": "^18.1.0", + "ngx-monaco-tree": "^18.3.0", "npm-run-all2": "^6.0.0", "nx": "~19.5.0", "nx-cloud": "^19.1.0", diff --git a/yarn.lock b/yarn.lock index b6375cc7ca..c85c3cb69d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9340,7 +9340,7 @@ __metadata: ngx-highlightjs: "npm:^12.0.0" ngx-markdown: "npm:^18.1.0" ngx-monaco-editor-v2: "npm:^18.0.0" - ngx-monaco-tree: "npm:^18.1.0" + ngx-monaco-tree: "npm:^18.3.0" npm-run-all2: "npm:^6.0.0" nx: "npm:~19.5.0" nx-cloud: "npm:^19.1.0" @@ -10321,7 +10321,7 @@ __metadata: ngx-highlightjs: "npm:^12.0.0" ngx-markdown: "npm:^18.1.0" ngx-monaco-editor-v2: "npm:^18.0.0" - ngx-monaco-tree: "npm:^18.1.0" + ngx-monaco-tree: "npm:^18.3.0" pixelmatch: "npm:^5.2.1" playwright-lighthouse: "npm:~4.0.0" pngjs: "npm:^7.0.0" @@ -28999,9 +28999,9 @@ __metadata: languageName: node linkType: hard -"ngx-monaco-tree@npm:^18.1.0": - version: 18.2.0 - resolution: "ngx-monaco-tree@npm:18.2.0" +"ngx-monaco-tree@npm:^18.3.0": + version: 18.3.0 + resolution: "ngx-monaco-tree@npm:18.3.0" dependencies: tslib: "npm:^2.7.0" peerDependencies: @@ -29009,7 +29009,7 @@ __metadata: "@angular/common": ^18.2.2 "@angular/core": ^18.2.2 "@vscode/codicons": ^0.0.32 - checksum: 10/87044e525ebbb39612a23642dd1d7ece8b46f338e0d3467edcc429a0b26ae4ac06b6a28393443be48b0380b290e99ab6ef6655ca69c8e65bd33728c70a2724cf + checksum: 10/ee369bc9b313ab6cafa12c58d9502dbeb4f33df61cc2c09e5e59dfec0e87c766889ed329f01566731d84fc8fc4193c74e6b4e8b6b331ce5fff1505b531ca2154 languageName: node linkType: hard