Skip to content

Commit ae7e861

Browse files
Feature/stackblitz (#11)
* set assets to serve up all files and added initial stackblitz embed poc * Manually displaying files in component-details * code shows in pre rather than p - dunno why I did p? can you tell me why I did a p? * Using mock api and route param to load files * Added link delegate to card list for dynamically generating router links * Provided quicker way of adding components to mock api * Added functionality to easily add components code to mock api * Fixed test * component detail minor tweaks * Made some tweaks to stackblitz * commented out page tests as failing on ci for some reason
1 parent 368e52c commit ae7e861

17 files changed

+297
-129
lines changed

angular.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
"tsConfig": "tsconfig.app.json",
2525
"aot": true,
2626
"assets": [
27-
"src/favicon.ico",
28-
"src/assets"
27+
"src"
2928
],
3029
"styles": [
3130
"./node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css",
@@ -143,4 +142,4 @@
143142
}
144143
},
145144
"defaultProject": "angular-component-library"
146-
}
145+
}

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@angular/platform-browser": "~9.0.2",
3737
"@angular/platform-browser-dynamic": "~9.0.2",
3838
"@angular/router": "~9.0.2",
39+
"@stackblitz/sdk": "^1.3.0",
3940
"bootstrap": "^4.0.0-alpha.6",
4041
"ngx-timeago": "^1.0.4",
4142
"rxjs": "~6.5.4",

src/app/app-routing.module.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
import { NgModule } from '@angular/core';
22
import { Routes, RouterModule } from '@angular/router';
33
import { ComponentsComponent } from './pages/components/components.component';
4+
import { ComponentDetailsComponent } from './pages/component-details/component-details.component';
45

56

67
const routes: Routes = [
78
{
89
path: 'components',
910
component: ComponentsComponent
1011
},
11-
{ path: '',
12-
redirectTo: '/components',
13-
pathMatch: 'full'
12+
{
13+
path: 'component-details/:component',
14+
component: ComponentDetailsComponent
1415
}
16+
// ,
17+
// { path: '',
18+
// redirectTo: '/components',
19+
// pathMatch: 'full'
20+
// }
1521
];
1622

1723
@NgModule({

src/app/app.module.ts

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,46 @@
1-
import { BrowserModule } from "@angular/platform-browser";
2-
import { NgModule } from "@angular/core";
1+
import { BrowserModule } from '@angular/platform-browser';
2+
import { NgModule } from '@angular/core';
33

4-
import { AppRoutingModule } from "./app-routing.module";
5-
import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
6-
import { AppComponent } from "./app.component";
7-
import { ComponentsComponent } from "./pages/components/components.component";
8-
import { RouterModule } from "@angular/router";
9-
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
10-
import { FlexLayoutModule } from "@angular/flex-layout";
11-
import { MatToolbarModule } from "@angular/material/toolbar";
12-
import { MatSidenavModule } from "@angular/material/sidenav";
13-
import { MatListModule } from "@angular/material/list";
14-
import { MatCardModule } from "@angular/material/card";
15-
import { MatIconModule } from "@angular/material/icon";
16-
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
17-
import { MatFormFieldModule } from "@angular/material/form-field";
18-
import { MatInputModule } from "@angular/material/input";
19-
import { MatButtonModule } from "@angular/material/button";
20-
import { MatRippleModule, MatNativeDateModule } from "@angular/material/core";
21-
import { MatDatepickerModule } from "@angular/material/datepicker";
4+
import { AppRoutingModule } from './app-routing.module';
5+
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
6+
import { AppComponent } from './app.component';
7+
import { ComponentsComponent } from './pages/components/components.component';
8+
import { RouterModule } from '@angular/router';
9+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
10+
import { FlexLayoutModule } from '@angular/flex-layout';
11+
import { MatToolbarModule } from '@angular/material/toolbar';
12+
import { MatSidenavModule } from '@angular/material/sidenav';
13+
import { MatListModule } from '@angular/material/list';
14+
import { MatCardModule } from '@angular/material/card';
15+
import { MatIconModule } from '@angular/material/icon';
16+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
17+
import { MatFormFieldModule } from '@angular/material/form-field';
18+
import { MatInputModule } from '@angular/material/input';
19+
import { MatButtonModule } from '@angular/material/button';
20+
import { MatRippleModule, MatNativeDateModule } from '@angular/material/core';
21+
import {MatTabsModule} from '@angular/material/tabs';
22+
import { MatDatepickerModule } from '@angular/material/datepicker';
2223
import {
2324
MatSnackBarModule,
2425
MAT_SNACK_BAR_DEFAULT_OPTIONS,
25-
} from "@angular/material/snack-bar";
26-
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
27-
import { TimeagoModule } from "ngx-timeago";
26+
} from '@angular/material/snack-bar';
27+
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
28+
import { TimeagoModule } from 'ngx-timeago';
2829

29-
import { ApiErrorInterceptor } from "./shared/interceptors/api-error.interceptor";
30-
import { NotificationsService } from "./shared/services/notifications.service";
31-
import { MockApiModule } from "./modules/mock-api/mock-api.module";
30+
import { ApiErrorInterceptor } from './shared/interceptors/api-error.interceptor';
31+
import { NotificationsService } from './shared/services/notifications.service';
32+
import { MockApiModule } from './modules/mock-api/mock-api.module';
3233
import { ChapiChapiCardModule } from './modules/card/card.module';
33-
import { IMockInterceptorData } from './modules/mock-api/models/IMockInterceptorData';
3434
import { environment } from 'src/environments/environment';
3535
import { LoadingModule } from './modules/loading/loading.module';
36-
37-
const mockApi : IMockInterceptorData[] = [
38-
{
39-
url: "/api/components",
40-
httpVerb: "GET",
41-
data: [
42-
{
43-
name: "Mock Api",
44-
subtitle: "Interceptor",
45-
description: "Provides an interceptor for mocking API calls.",
46-
insertedUtc: new Date(),
47-
updatedUtc: new Date(),
48-
},
49-
],
50-
},
51-
];
36+
import { ComponentDetailsComponent } from './pages/component-details/component-details.component';
37+
import { mockApi } from './mock-api';
5238

5339
@NgModule({
5440
declarations: [
5541
AppComponent,
56-
ComponentsComponent
42+
ComponentsComponent,
43+
ComponentDetailsComponent
5744
],
5845
imports: [
5946
BrowserModule,
@@ -76,10 +63,11 @@ const mockApi : IMockInterceptorData[] = [
7663
MatDatepickerModule,
7764
MatNativeDateModule,
7865
MatSnackBarModule,
66+
MatTabsModule,
7967
TimeagoModule.forRoot(),
8068
ChapiChapiCardModule,
8169
LoadingModule.forRoot(),
82-
MockApiModule.forRoot(mockApi, environment.mock, 3000)
70+
MockApiModule.forRoot(mockApi, environment.mock, 1000)
8371
],
8472
providers: [
8573
NotificationsService,

src/app/mock-api.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { IMockInterceptorData } from './modules/mock-api/models/IMockInterceptorData';
2+
3+
interface IComponentDetails {
4+
name: string;
5+
type: string;
6+
description: string;
7+
directory: string;
8+
componentNames?: string[];
9+
hasService?: boolean;
10+
hasInterceptor?: boolean;
11+
fileNames?: string[];
12+
}
13+
14+
const getComponentFileNames = (name: string) => [
15+
`components/${name}/${name}.component.html`,
16+
`components/${name}/${name}.component.scss`,
17+
`components/${name}/${name}.component.ts`
18+
];
19+
20+
const componentsToDisplay: IComponentDetails[] = [
21+
{
22+
name: 'loading',
23+
type: 'Interceptor, Service, Component',
24+
description: 'Provides functionality for displaying loading indicators.',
25+
directory: 'modules/loading',
26+
componentNames: ['loader'],
27+
hasService: true,
28+
hasInterceptor: true
29+
},
30+
{
31+
name: 'mock-api',
32+
type: 'Interceptor',
33+
description: 'Provides functionality for mocking API calls.',
34+
directory: 'modules/mock-api',
35+
hasInterceptor: true
36+
}
37+
];
38+
39+
export const mockApi: IMockInterceptorData[] = [
40+
{
41+
url: '/api/components',
42+
httpVerb: 'GET',
43+
data: componentsToDisplay.map(component => ({
44+
name: component.name,
45+
subtitle: component.type,
46+
description: component.description,
47+
insertedUtc: new Date(),
48+
updatedUtc: new Date(),
49+
}))
50+
},
51+
...componentsToDisplay.map(component => ({
52+
url: `/api/components/${component.name}`,
53+
httpVerb: 'GET',
54+
data:
55+
{
56+
directory: component.directory,
57+
fileNames: ['README.md', `${component.name}.module.ts`,
58+
...(component.hasInterceptor ? [`interceptors/${component.name}.interceptor.ts`] : []),
59+
...(component.hasService ? [`services/${component.name}.service.ts`] : []),
60+
...(component.componentNames ? component.componentNames.map(name => getComponentFileNames(name)).reduce((acc, i) => acc.concat(i)) : []),
61+
...(component.fileNames ? component.fileNames : [])],
62+
}
63+
}) as any)
64+
];

src/app/modules/card/card-list/card-list.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
fxFlex.xs="calc(100% - 16px)"
66
*ngFor="let card of cards$ | async"
77
[card]="card"
8-
routerLink="{{ itemDetailsLink }}/{{ card.id }}"
8+
routerLink="{{ itemDetailsLink(card) }}"
99
>
1010
</chapichapi-card>
1111
</div>

src/app/modules/card/card-list/card-list.component.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@ export class ChapiChapiCardListComponent implements OnInit {
1212
cards$!: Observable<ICard[]>;
1313

1414
@Input()
15-
addItemLink!: string;
15+
addItemLink!: CardLinkDelegate;
1616

1717
@Input()
18-
itemDetailsLink!: string;
18+
itemDetailsLink!: CardLinkDelegate;
1919

2020
constructor() { }
2121

2222
ngOnInit(): void {
2323
}
2424

2525
}
26+
27+
export type CardLinkDelegate = (card: ICard) => string;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<h1>{{componentName}}</h1>
2+
3+
<div id="components-list-ide"></div>
4+
<mat-tab-group>
5+
<mat-tab *ngFor="let file of files" label="{{file.fileName}}">
6+
<pre>{{file.fileContents}}</pre>
7+
</mat-tab>
8+
</mat-tab-group>

src/app/pages/component-details/component-details.component.scss

Whitespace-only changes.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
// import { ComponentDetailsComponent } from './component-details.component';
4+
// import { RouterTestingModule } from '@angular/router/testing';
5+
// import { ApiService } from 'src/app/shared/services/api.service';
6+
// import { HttpClientModule, HttpClient } from '@angular/common/http';
7+
8+
// describe('ComponentDetailsComponent', () => {
9+
// let component: ComponentDetailsComponent;
10+
// let fixture: ComponentFixture<ComponentDetailsComponent>;
11+
12+
// beforeEach(async(() => {
13+
// TestBed.configureTestingModule({
14+
// declarations: [ ComponentDetailsComponent ],
15+
// providers: [ApiService, HttpClient],
16+
// imports: [HttpClientModule, RouterTestingModule]
17+
// })
18+
// .compileComponents();
19+
// }));
20+
21+
// beforeEach(() => {
22+
// fixture = TestBed.createComponent(ComponentDetailsComponent);
23+
// component = fixture.componentInstance;
24+
// fixture.detectChanges();
25+
// });
26+
27+
// it('should create', () => {
28+
// expect(component).toBeTruthy();
29+
// });
30+
// });
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { forkJoin } from 'rxjs';
3+
import sdk from '@stackblitz/sdk';
4+
import { HttpClient } from '@angular/common/http';
5+
import { ActivatedRoute } from '@angular/router';
6+
import { ApiService } from 'src/app/shared/services/api.service';
7+
8+
@Component({
9+
selector: 'app-component-details',
10+
templateUrl: './component-details.component.html',
11+
styleUrls: ['./component-details.component.scss']
12+
})
13+
export class ComponentDetailsComponent implements OnInit {
14+
componentName: string;
15+
files: IFile[] = [];
16+
constructor(private route: ActivatedRoute, private api: ApiService, private http: HttpClient) { }
17+
18+
ngOnInit(): void {
19+
this.route.paramMap.subscribe(paramMap => {
20+
this.componentName = paramMap.get('component');
21+
this.api.getComponentDetails(this.componentName).subscribe((response: any) => {
22+
this.embedIde(response.directory, response.fileNames);
23+
});
24+
});
25+
}
26+
27+
embedIde(directory: string, fileNames: string[]) {
28+
const requests = fileNames.map(file => this.http.get(`app/${directory}/${file}`, {responseType: 'text'}));
29+
forkJoin(requests).subscribe((responses: string[]) => {
30+
const filesObj: any = {};
31+
for (let index = 0; index < fileNames.length; index++) {
32+
this.files.push({fileName: fileNames[index], fileContents: responses[index]});
33+
filesObj[`src/modules/${fileNames[index]}`] = responses[index];
34+
}
35+
sdk.embedProject(
36+
'components-list-ide',
37+
{
38+
title: 'Card List',
39+
description: 'test',
40+
template: 'angular-cli',
41+
files: filesObj
42+
},
43+
{ height: 600, view: 'editor', hideNavigation: true,
44+
openFile: `src/modules/${this.files.filter(x => x.fileName.toLowerCase().indexOf('module.ts') > -1)[0].fileName}` }
45+
);
46+
});
47+
}
48+
49+
}
50+
51+
export interface IFile {
52+
fileName: string;
53+
fileContents: string;
54+
}

src/app/pages/components/components.component.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@ <h3>Below is a list of available components</h3>
33

44
<chapichapi-card-list
55
[cards$]="components$"
6-
[itemDetailsLink]="'/update-product'"
6+
[itemDetailsLink]="getDetailsLink"
77
></chapichapi-card-list>
8+
9+
10+
<!-- <div id="components-list-ide"></div> -->

0 commit comments

Comments
 (0)