-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 🎸 Temporary workspace connection screen #57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
763c573
f5b0246
9bda3d6
91d7bdc
a212839
c5ac450
4fe09fa
0618a41
fe64ce0
6538d11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import { HttpClient } from '@angular/common/http'; | ||
| import { inject } from '@angular/core'; | ||
| import { Router } from '@angular/router'; | ||
| import { CURRENT_WORKSPACE_PATH } from '@angular-cli-gui/shared/data'; | ||
| import { ConnectWorkspaceService } from '@angular-cli-gui/workspace-manager'; | ||
| import { catchError, map, Observable, of, retry, Subject, tap } from 'rxjs'; | ||
|
|
||
| import { CoreService } from '../core/core.service'; | ||
|
|
||
| export const currentWorkspaceGuard = (): Observable<boolean> => { | ||
| const router = inject(Router); | ||
| const http = inject(HttpClient); | ||
| const connectWorkspaceService = inject(ConnectWorkspaceService); | ||
| const core = inject(CoreService); | ||
| const retrySubject = new Subject<void>(); | ||
| const projectNames$ = http.get<string[]>('/api/workspace'); | ||
| const currentWorkspacePath = sessionStorage.getItem(CURRENT_WORKSPACE_PATH); | ||
|
|
||
| return projectNames$.pipe( | ||
| // Save projects to state | ||
| tap((projectNames) => { | ||
| core.update({ | ||
| projectNames, | ||
| currentProjectName: projectNames?.[0], | ||
| }); | ||
| }), | ||
| // Map to true to allow navigation | ||
| map(() => true), | ||
| catchError(() => { | ||
| if (!currentWorkspacePath) { | ||
| router.navigate(['workspace-manager', 'connect-workspace']); | ||
| return of(false); | ||
| } | ||
|
|
||
| // if path saved in local storage is invalid somehow (maybe deleted workspace) | ||
| // remove it from local storage so on 2nd retry cycle user will be navigated to workspace connection screen | ||
| sessionStorage.removeItem(CURRENT_WORKSPACE_PATH); | ||
|
|
||
| // Connect to workspace using local storage path and retry to get projectNames | ||
| return connectWorkspaceService | ||
| .connectWorkspace(currentWorkspacePath) | ||
| .pipe( | ||
| map(() => { | ||
| retrySubject.next(); | ||
| return false; | ||
| }) | ||
| ); | ||
| }), | ||
| retry({ delay: () => retrySubject }) | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,18 @@ | ||
| import { HttpClient, provideHttpClient } from '@angular/common/http'; | ||
| import { APP_INITIALIZER } from '@angular/core'; | ||
| import { provideHttpClient } from '@angular/common/http'; | ||
| import { bootstrapApplication } from '@angular/platform-browser'; | ||
| import { provideAnimations } from '@angular/platform-browser/animations'; | ||
| import { | ||
| provideRouter, | ||
| withEnabledBlockingInitialNavigation, | ||
| } from '@angular/router'; | ||
| import { map } from 'rxjs'; | ||
|
|
||
| import { AppComponent } from './app/app.component'; | ||
| import { APP_ROUTES } from './app/app.routes'; | ||
| import { CoreService } from './app/core/core.service'; | ||
|
|
||
| bootstrapApplication(AppComponent, { | ||
| providers: [ | ||
| provideRouter(APP_ROUTES, withEnabledBlockingInitialNavigation()), | ||
| provideHttpClient(), | ||
| provideAnimations(), | ||
| { | ||
| provide: APP_INITIALIZER, | ||
| useFactory: (http: HttpClient, core: CoreService) => () => | ||
| http.get<string[]>(`/api/workspace`).pipe( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we not need the list of projects and the current project? How do you plan to run generators? I thought we'd keep the last workspace path in LS, so if we have one, we connect to it, and there is no need to re-connect on every page reload.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right- added this logic in the guard
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use sessionStorage instead, so you won't have to deal with invalidation. its also better UX IMO, the data will be persistent until the tab is closed (which should be the same as terminating the gui process)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| map((projectNames) => | ||
| core.update({ | ||
| projectNames, | ||
| currentProjectName: projectNames?.[0], | ||
| }) | ||
| ) | ||
| ), | ||
| deps: [HttpClient, CoreService], | ||
| multi: true, | ||
| }, | ||
| ], | ||
| }).catch((err) => console.error(err)); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| export * from './lib/exec-result.interface'; | ||
| export * from './lib/generate-component-args.interface'; | ||
| export * from './lib/directory.interface'; | ||
| export * from './lib/local-storage-keys.consts'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export const CURRENT_WORKSPACE_PATH = 'currentWorkspacePath'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| export * from './lib/workspace-manager/workspace-manager.component'; | ||
| export * from './lib/workspace-manager/workspace-manager.routes'; | ||
| export * from './lib/workspace-manager/data-access/connect-workspace.service'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { HttpClient } from '@angular/common/http'; | ||
| import { inject, Injectable } from '@angular/core'; | ||
| import { Router } from '@angular/router'; | ||
| import { CURRENT_WORKSPACE_PATH } from '@angular-cli-gui/shared/data'; | ||
| import { Observable, tap } from 'rxjs'; | ||
|
|
||
| @Injectable({ providedIn: 'root' }) | ||
| export class ConnectWorkspaceService { | ||
| http = inject(HttpClient); | ||
| router = inject(Router); | ||
|
|
||
| connectWorkspace(path: string): Observable<void> { | ||
| return this.http.post<void>('/api/workspace/connect', { path }).pipe( | ||
| tap(() => { | ||
| sessionStorage.setItem(CURRENT_WORKSPACE_PATH, path); | ||
| this.router.navigate(['']); | ||
| }) | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,12 @@ | ||
| <p>connect-workspace works!</p> | ||
| <form | ||
OmerGronich marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| [formGroup]="form" | ||
| class="connect-workspace-form" | ||
| (ngSubmit)="connectWorkspace()" | ||
| > | ||
| <h2 class="mat-title">Connect your Angular workspace</h2> | ||
| <mat-form-field class="workspace-path-field" appearance="outline"> | ||
OmerGronich marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| <mat-label>The absolute path to your workspace</mat-label> | ||
| <input formControlName="path" matInput type="text" /> | ||
| </mat-form-field> | ||
| <button mat-raised-button color="primary" type="submit">Connect</button> | ||
| </form> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| .connect-workspace-form { | ||
| display: grid; | ||
| place-content: center; | ||
| height: 100%; | ||
|
|
||
| .workspace-path-field { | ||
| min-width: 350px; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,36 @@ | ||
| import { CommonModule } from '@angular/common'; | ||
| import { ChangeDetectionStrategy, Component } from '@angular/core'; | ||
| import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; | ||
| import { | ||
| FormControl, | ||
| FormGroup, | ||
| ReactiveFormsModule, | ||
| Validators, | ||
| } from '@angular/forms'; | ||
| import { MatButtonModule } from '@angular/material/button'; | ||
| import { MatInputModule } from '@angular/material/input'; | ||
|
|
||
| import { ConnectWorkspaceService } from '../../data-access/connect-workspace.service'; | ||
|
|
||
| @Component({ | ||
| selector: 'cli-connect-workspace', | ||
| standalone: true, | ||
| imports: [CommonModule], | ||
| imports: [CommonModule, MatInputModule, MatButtonModule, ReactiveFormsModule], | ||
| templateUrl: './connect-workspace.component.html', | ||
| styleUrls: ['./connect-workspace.component.scss'], | ||
| changeDetection: ChangeDetectionStrategy.OnPush, | ||
| }) | ||
| export class ConnectWorkspaceComponent {} | ||
| export class ConnectWorkspaceComponent { | ||
| connectService = inject(ConnectWorkspaceService); | ||
| form = new FormGroup( | ||
| { | ||
| path: new FormControl('', [Validators.required]), | ||
| }, | ||
| { updateOn: 'submit' } | ||
| ); | ||
|
|
||
| connectWorkspace(): void { | ||
| if (!this.form.valid) return; | ||
| const path = this.form.controls.path.value ?? ''; | ||
| this.connectService.connectWorkspace(path).subscribe(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1 @@ | ||
| <p>workspace-manager works!</p> | ||
| <router-outlet></router-outlet> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate the implementation but we need something that can be shared and reused, maybe we should consider adding ng-query
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind, but won't it make integrating this project with the angular repo more difficult? It might be a good idea to verify with them before relying on 3rd party libraries that aren't 100% necessary.