Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,19 @@
"scripts": [
"jquery/dist/jquery.min.js",
"@ztree/ztree_v3/js/jquery.ztree.all.min.js",
"@ztree/ztree_v3/js/jquery.ztree.exhide.min.js",
"asciinema-player/dist/bundle/asciinema-player.min.js"
"@ztree/ztree_v3/js/jquery.ztree.exhide.min.js"
]
},
"configurations": {
"production": {
"optimization": true,
"optimization": {
"scripts": true,
"styles": {
"minify": true,
"inlineCritical": false
},
"fonts": true
},
"outputHashing": "all",
"baseHref": "/luna/",
"outputPath": {
Expand All @@ -68,8 +74,13 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "5mb",
"maximumWarning": "4mb",
"maximumError": "6mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "200kb",
"maximumError": "300kb"
}
],
"fileReplacements": [
Expand Down
64 changes: 47 additions & 17 deletions src/app/elements/replay/asciicast/asciicast.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { formatTime } from '@app/utils/common';
import { HttpService } from '@app/services';
import { filter } from 'rxjs';

declare const AsciinemaPlayer: any;

@Component({
standalone: false,
selector: 'elements-replay-asciicast',
Expand All @@ -29,6 +27,7 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
startTimeStamp = null;
commands: Command[];
page = 0;
private AsciinemaPlayer: any;

constructor(
private route: ActivatedRoute,
Expand All @@ -37,7 +36,10 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
this.startAt = 0;
}

ngOnInit() {
async ngOnInit() {
// 动态加载 asciinema-player
await this.loadAsciinemaPlayer();

this.commands = new Array<Command>();
const start = new Date(this.replay.date_start);
const end = new Date(this.replay.date_end);
Expand All @@ -62,38 +64,60 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
this.getCommands(this.page);
}

private async loadAsciinemaPlayer() {
try {
// 动态导入 asciinema-player
const module = await import('asciinema-player');
this.AsciinemaPlayer = module.default || module;
} catch (error) {
console.error('Failed to load asciinema-player:', error);
// 如果动态导入失败,尝试从全局变量获取(兼容性)
this.AsciinemaPlayer = (window as any).AsciinemaPlayer;
}
}

ngAfterViewInit() {
this.player = this.createPlayer();
this.player.play();
this.isPlaying = true;
this.createTimer();
if (this.AsciinemaPlayer) {
this.player = this.createPlayer();
this.player.play();
this.isPlaying = true;
this.createTimer();
}
}

@HostListener('window:resize', ['$event'])
onResize(event: Event) {
this.rows = Math.min(25, Math.floor((window.innerHeight - 120) / 16));
this.currentTime = this.player.getCurrentTime();
this.resetPlayer();
if (this.player) {
this.currentTime = this.player.getCurrentTime();
this.resetPlayer();
}
}

speedDown() {
if (this.speed <= 1) {
return;
}
this.speed--;
this.currentTime = this.player.getCurrentTime();
this.resetPlayer();
this.player.seek(this.currentTime);
if (this.player) {
this.currentTime = this.player.getCurrentTime();
this.resetPlayer();
this.player.seek(this.currentTime);
}
}

speedUp() {
this.speed++;
this.currentTime = this.player.getCurrentTime();
this.resetPlayer();
this.player.seek(this.currentTime);
if (this.player) {
this.currentTime = this.player.getCurrentTime();
this.resetPlayer();
this.player.seek(this.currentTime);
}
}

toggle() {
if (!this.player) return;

clearInterval(this.timer);
if (this.isPlaying) {
this.player.pause();
Expand Down Expand Up @@ -126,7 +150,7 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {

resetPlayer() {
clearInterval(this.timer);
if (!this.player) {
if (!this.player || !this.AsciinemaPlayer) {
return;
}
this.player.pause();
Expand All @@ -148,9 +172,13 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
}

createPlayer() {
if (!this.AsciinemaPlayer) {
console.error('AsciinemaPlayer not loaded');
return null;
}
const el = document.getElementById('screen');
const opt = this.getPlayerOptions();
return AsciinemaPlayer.create(this.replay.src, el, opt);
return this.AsciinemaPlayer.create(this.replay.src, el, opt);
}

getUserLang() {
Expand Down Expand Up @@ -191,6 +219,8 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
}

commandClick(item: Command) {
if (!this.player) return;

const startPlayTime = new Date(this.replay.date_start).getTime() / 1000;
const instructStartTime = item.timestamp - 5 - startPlayTime;
const time = instructStartTime > 0 ? instructStartTime : 0;
Expand Down
6 changes: 5 additions & 1 deletion src/app/plugins/ZorroModule.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
import { NzFloatButtonModule } from 'ng-zorro-antd/float-button';
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
import { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';
import { NzMessageModule } from 'ng-zorro-antd/message';
import { NzNotificationModule } from 'ng-zorro-antd/notification';

@NgModule({
exports: [
Expand Down Expand Up @@ -63,7 +65,9 @@ import { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';
NzPopconfirmModule,
NzFloatButtonModule,
NzInputNumberModule,
NzDescriptionsModule
NzDescriptionsModule,
NzMessageModule,
NzNotificationModule
]
})
export class NgZorroAntdModule {}
44 changes: 29 additions & 15 deletions src/app/router.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,45 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { PageMainComponent } from './pages/main/main.component';
import { PageSftpComponent } from './pages/sftp/sftp.component';
import { PagesBlankComponent } from './pages/blank/blank.component';
import { PagesShareComponent } from './pages/share/share.component';
import { PageDirectComponent } from './pages/direct/direct.component';
import { PagesReplayComponent } from './pages/replay/replay.component';
import { PagesConnectComponent } from './pages/connect/connect.component';
import { PagesMonitorComponent } from './pages/monitor/monitor.component';
import { PagesKubernetesComponent } from './pages/kubernetes/kubernetes.component';
import { PagesShareComponent } from './pages/share/share.component';

const appRoutes: Routes = [
{ path: '', component: PageMainComponent },
{ path: 'sftp', component: PageSftpComponent },
{ path: 'connect', component: PagesConnectComponent },
{
path: 'sftp',
loadComponent: () => import('./pages/sftp/sftp.component').then(m => m.PageSftpComponent)
},
{
path: 'connect',
loadComponent: () =>
import('./pages/connect/connect.component').then(m => m.PagesConnectComponent)
},
{ path: 'undefined', component: PagesBlankComponent },
{ path: 'share/:id', component: PagesShareComponent },
{ path: 'replay/:sid', component: PagesReplayComponent },
{ path: 'admin-connect', component: PageDirectComponent },
{ path: 'monitor/:sid', component: PagesMonitorComponent },
{ path: 'k8s/:token', component: PagesKubernetesComponent },
{
path: 'replay/:sid',
loadComponent: () => import('./pages/replay/replay.component').then(m => m.PagesReplayComponent)
},
{
path: 'admin-connect',
loadComponent: () => import('./pages/direct/direct.component').then(m => m.PageDirectComponent)
},
{
path: 'monitor/:sid',
loadComponent: () =>
import('./pages/monitor/monitor.component').then(m => m.PagesMonitorComponent)
},
{
path: 'k8s/:token',
loadComponent: () =>
import('./pages/kubernetes/kubernetes.component').then(m => m.PagesKubernetesComponent)
}
// { path: '**', component: PagesNotFoundComponent }
];

@NgModule({
imports: [RouterModule.forRoot(appRoutes, { enableTracing: false })],
exports: [RouterModule],
exports: [RouterModule]
})

export class AppRouterModule {}
4 changes: 1 addition & 3 deletions src/polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.

/***************************************************************************************************
* Zone JS is required by Angular itself.
*/
import 'zone.js'; // Included with Angular CLI.


/***************************************************************************************************
* APPLICATION IMPORTS
*/
Expand All @@ -47,5 +47,3 @@ import 'zone.js'; // Included with Angular CLI.
* Need to import at least one locale-data with intl.
*/
// import 'intl/locale-data/jsonp/en';

(window as any).global = window;
7 changes: 2 additions & 5 deletions src/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "ES2015",
"module": "esnext",
"target": "ES2022",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
"exclude": ["test.ts", "**/*.spec.ts"]
}
19 changes: 5 additions & 14 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
"compilerOptions": {
"baseUrl": "src",
"paths": {
"@src/*": [
"*"
],
"@app/*": [
"app/*"
]
"@src/*": ["*"],
"@app/*": ["app/*"]
},
"allowJs": true,
"outDir": "./dist/out-tsc",
Expand All @@ -19,14 +15,9 @@
"experimentalDecorators": true,
"target": "es2020",
"importHelpers": true,
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2020",
"dom"
],
"module": "es2015",
"typeRoots": ["node_modules/@types"],
"lib": ["es2020", "dom"],
"module": "esnext",
"allowSyntheticDefaultImports": true
}
}