Skip to content

Commit

Permalink
Добавлена ассоциация .har расширения с PWA (только для PC)
Browse files Browse the repository at this point in the history
Closes #21
  • Loading branch information
sunriselink committed Apr 16, 2024
1 parent 552e478 commit da6be28
Show file tree
Hide file tree
Showing 18 changed files with 240 additions and 80 deletions.
3 changes: 3 additions & 0 deletions .docker/lt.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ARG NODEJS_IMAGE
FROM ${NODEJS_IMAGE}
RUN npm i -g [email protected] && npm cache clean --force
File renamed without changes.
7 changes: 3 additions & 4 deletions Dockerfile → .docker/web.dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM node:20.11.0-slim as builder
ARG NODEJS_IMAGE
FROM ${NODEJS_IMAGE} as builder

ENV NODE_ENV=production

Expand All @@ -20,6 +21,4 @@ RUN npm run build:prod
FROM nginx:1.25.4-alpine

COPY --from=builder /app/dist/har-viewer/browser /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
COPY .docker/nginx.conf /etc/nginx/nginx.conf
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
COMPOSE_PROJECT_NAME=har-viewer
NODEJS_IMAGE=node:20.11.0-slim
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,25 @@
> Возможно будет дорабатываться если ну прям надо
## [Открыть](https://sunriselink.github.io/har-viewer)

## Запуск в Docker

Для сборки и запуска проекта выполнить команду:

```shell
docker compose up -d --build web
```

Проект будет доступен по адресу `http://localhost:8080`.

Если требуется проверить работу Service Worker'а, то надо подключиться к HTTPS туннелю. Для этого требуется запустить еще один контейнер:

```shell
docker compose up -d --build lt
```

Адрес туннеля можно достать из логов командой:

```shell
docker compose logs lt
```
14 changes: 13 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
version: "3"
services:
web:
build: .
build:
context: .
dockerfile: .docker/web.dockerfile
args:
- NODEJS_IMAGE=${NODEJS_IMAGE}
ports:
- "8080:80"

lt:
build:
context: .docker
dockerfile: lt.dockerfile
args:
- NODEJS_IMAGE=${NODEJS_IMAGE}
command: lt --port 80 --local-host web
17 changes: 1 addition & 16 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
<div
class="drop"
appFileDropZone
[class.file-over]="fileOver()"
(fileOver)="fileOver.set($event)"
(fileDrop)="loadHAR($event)"
>
@if (harLog(); as har) {
<app-har-viewer [harLog]="har"></app-har-viewer>
} @else {
<div class="upload">
<app-file-uploader buttonText="SELECT HAR FILE" (fileSelect)="loadHAR($event)"></app-file-uploader>
<div class="upload__tip">Or drop file here</div>
</div>
}
</div>
<router-outlet></router-outlet>

<app-version></app-version>
22 changes: 0 additions & 22 deletions src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -1,25 +1,3 @@
:host {
display: block;
height: 100%;
}

.upload {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

&__tip {
color: rgba(0, 0, 0, 0.5);
text-align: center;
margin-top: 16px;
}
}

.drop {
min-height: 100%;
}

.file-over {
background-color: rgba(0, 0, 0, 0.35);
}
40 changes: 4 additions & 36 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,13 @@
import { ChangeDetectionStrategy, Component, inject, Signal, signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { BehaviorSubject, Observable, of, switchMap } from 'rxjs';
import { FileUploaderComponent } from './components/file-uploader/file-uploader.component';
import { HarViewerComponent } from './components/har-viewer/har-viewer.component';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { VersionComponent } from './components/version/version.component';
import { FileDropZoneDirective } from './directives/file-drop-zone.directive';
import { HarReaderService } from './services/har-reader.service';
import { IHAR } from './types/har-log';
import { Unsafe } from './types/unsafe';
import { catchAndLogError } from './utils/catch-and-log-error';

@Component({
selector: 'app-root',
standalone: true,
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [FileDropZoneDirective, FileUploaderComponent, VersionComponent, HarViewerComponent],
imports: [VersionComponent, RouterOutlet],
})
export class AppComponent {
protected readonly fileOver = signal(false);

protected readonly harFile$ = new BehaviorSubject<Unsafe<File>>(null);
protected readonly harLog = this.createHARSignal();

protected readonly harReader = inject(HarReaderService);

protected loadHAR(file: File): void {
this.harFile$.next(file);
}

private createHARSignal(): Signal<Unsafe<IHAR>> {
const harLog$ = this.harFile$.pipe(switchMap(file => this.readFile(file)));
return toSignal(harLog$);
}

private readFile(file: Unsafe<File>): Observable<Unsafe<IHAR>> {
if (!file) {
return of(null);
}

return this.harReader.readHAR(file).pipe(catchAndLogError());
}
}
export class AppComponent {}
16 changes: 16 additions & 0 deletions src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import { ApplicationConfig, isDevMode } from '@angular/core';
import { provideRouter, Routes } from '@angular/router';
import { provideServiceWorker } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { APP_ENVIRONMENT_TOKEN } from '../environments/environment.interface';
import { FileHandlerComponent } from './pages/file-handler/file-handler.component';
import { HarPageComponent } from './pages/har-page/har-page.component';

const routes: Routes = [
{
path: '',
pathMatch: 'full',
component: HarPageComponent,
},
{
path: 'file_handler',
component: FileHandlerComponent,
},
];

export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
{
provide: APP_ENVIRONMENT_TOKEN,
useValue: environment,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<label>
<span class="select-btn">{{ buttonText }}</span>
<input type="file" (change)="onFileSelect($event)" />
<input type="file" [accept]="accept" (change)="onFileSelect($event)" />
</label>
3 changes: 3 additions & 0 deletions src/app/components/file-uploader/file-uploader.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export class FileUploaderComponent {
@Input()
public buttonText = 'SELECT FILE';

@Input()
public accept?: string;

@Output()
public fileSelect = new EventEmitter<File>();

Expand Down
19 changes: 19 additions & 0 deletions src/app/pages/file-handler/file-handler.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { LaunchQueueService } from '../../services/launch-queue.service';

@Component({
selector: 'app-file-handler',
template: '',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FileHandlerComponent implements OnInit {
private readonly launchQueueService = inject(LaunchQueueService);
private readonly router = inject(Router);

public ngOnInit(): void {
this.launchQueueService.tryCreateConsumer();
this.router.navigateByUrl('/', { replaceUrl: true });
}
}
21 changes: 21 additions & 0 deletions src/app/pages/har-page/har-page.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div
class="drop"
appFileDropZone
[class.file-over]="fileOver()"
(fileOver)="fileOver.set($event)"
(fileDrop)="loadHAR($event)"
>
@if (harLog(); as har) {
<app-har-viewer [harLog]="har"></app-har-viewer>
} @else {
<div class="upload">
<app-file-uploader
buttonText="SELECT HAR FILE"
accept=".har"
(fileSelect)="loadHAR($event)"
></app-file-uploader>

<div class="upload__tip">Or drop file here</div>
</div>
}
</div>
25 changes: 25 additions & 0 deletions src/app/pages/har-page/har-page.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
:host {
display: block;
height: 100%;
}

.upload {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

&__tip {
color: rgba(0, 0, 0, 0.5);
text-align: center;
margin-top: 16px;
}
}

.drop {
min-height: 100%;
}

.file-over {
background-color: rgba(0, 0, 0, 0.35);
}
50 changes: 50 additions & 0 deletions src/app/pages/har-page/har-page.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ChangeDetectionStrategy, Component, inject, OnInit, Signal, signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { BehaviorSubject, Observable, of, switchMap } from 'rxjs';
import { FileUploaderComponent } from '../../components/file-uploader/file-uploader.component';
import { HarViewerComponent } from '../../components/har-viewer/har-viewer.component';
import { FileDropZoneDirective } from '../../directives/file-drop-zone.directive';
import { HarReaderService } from '../../services/har-reader.service';
import { LaunchQueueService } from '../../services/launch-queue.service';
import { IHAR } from '../../types/har-log';
import { Unsafe } from '../../types/unsafe';
import { catchAndLogError } from '../../utils/catch-and-log-error';

@Component({
selector: 'app-har-page',
standalone: true,
templateUrl: './har-page.component.html',
styleUrl: './har-page.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [FileDropZoneDirective, FileUploaderComponent, HarViewerComponent],
})
export class HarPageComponent implements OnInit {
protected readonly fileOver = signal(false);

protected readonly harFile$ = new BehaviorSubject<Unsafe<File>>(null);
protected readonly harLog = this.createHARSignal();

private readonly harReader = inject(HarReaderService);
private readonly launchQueueService = inject(LaunchQueueService);

public ngOnInit(): void {
this.launchQueueService.handleFile().subscribe(file => this.loadHAR(file));
}

protected loadHAR(file: File): void {
this.harFile$.next(file);
}

private createHARSignal(): Signal<Unsafe<IHAR>> {
const harLog$ = this.harFile$.pipe(switchMap(file => this.readFile(file)));
return toSignal(harLog$);
}

private readFile(file: Unsafe<File>): Observable<Unsafe<IHAR>> {
if (!file) {
return of(null);
}

return this.harReader.readHAR(file).pipe(catchAndLogError());
}
}
50 changes: 50 additions & 0 deletions src/app/services/launch-queue.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Injectable } from '@angular/core';
import { EMPTY, Observable, ReplaySubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class LaunchQueueService {
private readonly file$ = new ReplaySubject<File>(1);

private hasConsumer = false;

public tryCreateConsumer(): void {
if (!this.isSupported()) {
console.warn('LaunchQueue is not supported');
return;
}

this.createConsumer();
}

public handleFile(): Observable<File> {
return this.hasConsumer ? this.file$.asObservable() : EMPTY;
}

private isSupported(): boolean {
return !!window.launchQueue;
}

private createConsumer(): void {
this.hasConsumer = true;

window.launchQueue.setConsumer(async params => {
if (params.files?.length) {
const file = await params.files[0].getFile();

this.file$.next(file);
this.file$.complete();
}
});
}
}

declare global {
interface Window {
launchQueue: {
setConsumer: (consumer: (params: LaunchParams) => void) => void;
};
}
interface LaunchParams {
readonly files?: FileSystemFileHandle[];
}
}
8 changes: 8 additions & 0 deletions src/manifest.webmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
"display": "standalone",
"scope": "./",
"start_url": "./",
"file_handlers": [
{
"action": "/file_handler",
"accept": {
"application/json": [".har"]
}
}
],
"icons": [
{
"src": "assets/icons/icon-72x72.png",
Expand Down

0 comments on commit da6be28

Please sign in to comment.