Skip to content

Commit c89acbd

Browse files
authored
feat: 🎸 Temporary workspace connection screen (#57)
1 parent 5b35eeb commit c89acbd

File tree

14 files changed

+147
-32
lines changed

14 files changed

+147
-32
lines changed

‎apps/cli-gui/src/app/app.component.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<ng-container *ngIf="core.coreState$ | async as coreState">
2-
<header class="main-header">
2+
<header class="main-header" *ngIf="coreState.projectNames?.length">
33
<div class="project-selector">
44
<mat-select name="project-selector" id="project-selector">
55
<mat-option

‎apps/cli-gui/src/app/app.component.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
1+
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
22
import { Component } from '@angular/core';
33
import { MatSelectModule } from '@angular/material/select';
44
import { RouterOutlet } from '@angular/router';
@@ -7,7 +7,7 @@ import { CoreService } from './core/core.service';
77

88
@Component({
99
standalone: true,
10-
imports: [NgFor, NgIf, AsyncPipe, RouterOutlet, MatSelectModule],
10+
imports: [NgIf, AsyncPipe, RouterOutlet, MatSelectModule, NgForOf],
1111
selector: 'cli-root',
1212
templateUrl: './app.component.html',
1313
styleUrls: ['./app.component.scss'],

‎apps/cli-gui/src/app/app.routes.ts‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import { Routes } from '@angular/router';
22

3+
import { currentWorkspaceGuard } from './guards/current-workspace.guard';
4+
35
export const APP_ROUTES: Routes = [
46
{
57
path: '',
8+
canActivate: [currentWorkspaceGuard],
69
children: [
10+
{
11+
path: '',
12+
redirectTo: 'generators',
13+
pathMatch: 'full',
14+
},
715
{
816
path: 'generators',
9-
loadChildren: () => import('./generators/generators.routes'),
17+
loadComponent: () =>
18+
import('@angular-cli-gui/generators').then(
19+
(m) => m.GeneratorsComponent
20+
),
1021
},
1122
{
1223
path: 'configuration',
@@ -22,10 +33,6 @@ export const APP_ROUTES: Routes = [
2233
(m) => m.ExecutorsComponent
2334
),
2435
},
25-
{
26-
path: '**',
27-
redirectTo: 'generators',
28-
},
2936
],
3037
},
3138
{
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { HttpClient } from '@angular/common/http';
2+
import { inject } from '@angular/core';
3+
import { Router } from '@angular/router';
4+
import { CURRENT_WORKSPACE_PATH } from '@angular-cli-gui/shared/data';
5+
import { ConnectWorkspaceService } from '@angular-cli-gui/workspace-manager';
6+
import { catchError, map, Observable, of, retry, Subject, tap } from 'rxjs';
7+
8+
import { CoreService } from '../core/core.service';
9+
10+
export const currentWorkspaceGuard = (): Observable<boolean> => {
11+
const router = inject(Router);
12+
const http = inject(HttpClient);
13+
const connectWorkspaceService = inject(ConnectWorkspaceService);
14+
const core = inject(CoreService);
15+
const retrySubject = new Subject<void>();
16+
const projectNames$ = http.get<string[]>('/api/workspace');
17+
const currentWorkspacePath = sessionStorage.getItem(CURRENT_WORKSPACE_PATH);
18+
19+
return projectNames$.pipe(
20+
// Save projects to state
21+
tap((projectNames) => {
22+
core.update({
23+
projectNames,
24+
currentProjectName: projectNames?.[0],
25+
});
26+
}),
27+
// Map to true to allow navigation
28+
map(() => true),
29+
catchError(() => {
30+
if (!currentWorkspacePath) {
31+
router.navigate(['workspace-manager', 'connect-workspace']);
32+
return of(false);
33+
}
34+
35+
// if path saved in local storage is invalid somehow (maybe deleted workspace)
36+
// remove it from local storage so on 2nd retry cycle user will be navigated to workspace connection screen
37+
sessionStorage.removeItem(CURRENT_WORKSPACE_PATH);
38+
39+
// Connect to workspace using local storage path and retry to get projectNames
40+
return connectWorkspaceService
41+
.connectWorkspace(currentWorkspacePath)
42+
.pipe(
43+
map(() => {
44+
retrySubject.next();
45+
return false;
46+
})
47+
);
48+
}),
49+
retry({ delay: () => retrySubject })
50+
);
51+
};

‎apps/cli-gui/src/main.ts‎

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,18 @@
1-
import { HttpClient, provideHttpClient } from '@angular/common/http';
2-
import { APP_INITIALIZER } from '@angular/core';
1+
import { provideHttpClient } from '@angular/common/http';
32
import { bootstrapApplication } from '@angular/platform-browser';
43
import { provideAnimations } from '@angular/platform-browser/animations';
54
import {
65
provideRouter,
76
withEnabledBlockingInitialNavigation,
87
} from '@angular/router';
9-
import { map } from 'rxjs';
108

119
import { AppComponent } from './app/app.component';
1210
import { APP_ROUTES } from './app/app.routes';
13-
import { CoreService } from './app/core/core.service';
1411

1512
bootstrapApplication(AppComponent, {
1613
providers: [
1714
provideRouter(APP_ROUTES, withEnabledBlockingInitialNavigation()),
1815
provideHttpClient(),
1916
provideAnimations(),
20-
{
21-
provide: APP_INITIALIZER,
22-
useFactory: (http: HttpClient, core: CoreService) => () =>
23-
http.get<string[]>(`/api/workspace`).pipe(
24-
map((projectNames) =>
25-
core.update({
26-
projectNames,
27-
currentProjectName: projectNames?.[0],
28-
})
29-
)
30-
),
31-
deps: [HttpClient, CoreService],
32-
multi: true,
33-
},
3417
],
3518
}).catch((err) => console.error(err));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './lib/exec-result.interface';
22
export * from './lib/generate-component-args.interface';
33
export * from './lib/directory.interface';
4+
export * from './lib/local-storage-keys.consts';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const CURRENT_WORKSPACE_PATH = 'currentWorkspacePath';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './lib/workspace-manager/workspace-manager.component';
22
export * from './lib/workspace-manager/workspace-manager.routes';
3+
export * from './lib/workspace-manager/data-access/connect-workspace.service';
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { HttpClient } from '@angular/common/http';
2+
import { inject, Injectable } from '@angular/core';
3+
import { Router } from '@angular/router';
4+
import { CURRENT_WORKSPACE_PATH } from '@angular-cli-gui/shared/data';
5+
import { Observable, tap } from 'rxjs';
6+
7+
@Injectable({ providedIn: 'root' })
8+
export class ConnectWorkspaceService {
9+
http = inject(HttpClient);
10+
router = inject(Router);
11+
12+
connectWorkspace(path: string): Observable<void> {
13+
return this.http.post<void>('/api/workspace/connect', { path }).pipe(
14+
tap(() => {
15+
sessionStorage.setItem(CURRENT_WORKSPACE_PATH, path);
16+
this.router.navigate(['']);
17+
})
18+
);
19+
}
20+
}
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1-
<p>connect-workspace works!</p>
1+
<form
2+
[formGroup]="form"
3+
class="connect-workspace-form"
4+
(ngSubmit)="connectWorkspace()"
5+
>
6+
<h2 class="mat-title">Connect your Angular workspace</h2>
7+
<mat-form-field class="workspace-path-field" appearance="outline">
8+
<mat-label>The absolute path to your workspace</mat-label>
9+
<input formControlName="path" matInput type="text" />
10+
</mat-form-field>
11+
<button mat-raised-button color="primary" type="submit">Connect</button>
12+
</form>

0 commit comments

Comments
 (0)