oggui/ogWebconsole/src/app/components/commands/commands-task/create-task-script/create-task-script.componen...

319 lines
8.8 KiB
TypeScript

import {Component, EventEmitter, Inject, OnInit, Output} from '@angular/core';
import {SelectionModel} from "@angular/cdk/collections";
import {HttpClient} from "@angular/common/http";
import {ToastrService} from "ngx-toastr";
import {ConfigService} from "@services/config.service";
import {ActivatedRoute, Router} from "@angular/router";
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
import {
SaveScriptComponent
} from "../../../groups/components/client-main-view/run-script-assistant/save-script/save-script.component";
import {FormBuilder, FormGroup} from "@angular/forms";
import {TranslateService} from "@ngx-translate/core";
interface ActionCategory {
id: string;
icon: string;
labelKey: string;
descriptionKey: string;
color: string;
infoOnly: boolean;
actions: ActionOption[];
}
interface ActionOption {
type: string;
icon: string;
labelKey: string;
}
@Component({
selector: 'app-create-task-script',
templateUrl: './create-task-script.component.html',
styleUrl: './create-task-script.component.css'
})
export class CreateTaskScriptComponent implements OnInit {
form: FormGroup;
baseUrl: string;
@Output() dataChange = new EventEmitter<any>();
loading: boolean = false;
scripts: any[] = [];
scriptContent: string = "";
parameters: any = {};
commandType: string = 'existing';
selectedScript: any = null;
newScript: string = '';
executionOrder: number = 0;
selection = new SelectionModel(true, []);
parameterNames: string[] = Object.keys(this.parameters);
commandTask: any;
selectedCategory: string = '';
selectedAction: string = '';
loginDisk: number = 1;
loginPartition: number = 1;
categories: ActionCategory[] = [
{
id: 'image-ops',
icon: 'perm_media',
labelKey: 'catImageOps',
descriptionKey: 'catImageOpsDesc',
color: '#1565c0',
infoOnly: true,
actions: [
{ type: 'deploy-image', icon: 'cloud_download', labelKey: 'deployImage' },
{ type: 'create-image', icon: 'add_photo_alternate', labelKey: 'createImage' },
]
},
{
id: 'partition',
icon: 'storage',
labelKey: 'catPartition',
descriptionKey: 'catPartitionDesc',
color: '#2e7d32',
infoOnly: true,
actions: [
{ type: 'partition-assistant', icon: 'view_column', labelKey: 'partitionAndFormat' },
]
},
{
id: 'system',
icon: 'settings_power',
labelKey: 'catSystemControl',
descriptionKey: 'catSystemControlDesc',
color: '#e65100',
infoOnly: false,
actions: [
{ type: 'power-on', icon: 'power', labelKey: 'powerOnDevice' },
{ type: 'shutdown', icon: 'power_off', labelKey: 'shutdownDevice' },
{ type: 'reboot', icon: 'restart_alt', labelKey: 'rebootDevice' },
{ type: 'login', icon: 'login', labelKey: 'loginSession' },
]
},
{
id: 'script',
icon: 'code',
labelKey: 'catCustomScript',
descriptionKey: 'catCustomScriptDesc',
color: '#6a1b9a',
infoOnly: false,
actions: [
{ type: 'run-script', icon: 'terminal', labelKey: 'runScript' },
]
}
];
constructor(
private fb: FormBuilder,
private http: HttpClient,
public dialogRef: MatDialogRef<CreateTaskScriptComponent>,
private toastService: ToastrService,
private configService: ConfigService,
private router: Router,
private dialog: MatDialog,
private route: ActivatedRoute,
private translate: TranslateService,
@Inject(MAT_DIALOG_DATA) public data: any
) {
this.baseUrl = this.configService.apiUrl;
this.commandTask = this.data.commandTask;
this.loadScripts();
this.form = this.fb.group({
content: [''],
order: [''],
});
}
ngOnInit(): void {}
selectCategory(categoryId: string): void {
const cat = this.categories.find(c => c.id === categoryId);
if (cat?.infoOnly) {
this.selectedCategory = categoryId;
this.selectedAction = '';
return;
}
this.selectedCategory = categoryId;
if (cat && cat.actions.length === 1) {
this.selectAction(cat.actions[0].type);
} else {
this.selectedAction = '';
}
}
selectAction(actionType: string): void {
this.selectedAction = actionType;
}
goBackToCategories(): void {
this.selectedCategory = '';
this.selectedAction = '';
}
goBackToActions(): void {
this.selectedAction = '';
}
isInfoOnlyCategory(): boolean {
const cat = this.categories.find(c => c.id === this.selectedCategory);
return cat?.infoOnly || false;
}
loadScripts(): void {
this.loading = true;
this.http.get(`${this.baseUrl}/commands?readOnly=false&enabled=true`).subscribe((data: any) => {
this.scripts = data['hydra:member'];
this.loading = false;
}, (error) => {
this.toastService.error(error.error['hydra:description']);
this.loading = false;
});
}
onScriptChange(): void {
if (this.selectedScript) {
this.scriptContent = this.selectedScript.script;
const matches = this.scriptContent.match(/@(\w+)/g) || [];
const uniqueParams = Array.from(new Set(matches.map((m: string) => m.slice(1))));
this.parameters = {};
uniqueParams.forEach(param => this.parameters[param] = '');
this.parameterNames = uniqueParams;
this.updateScript();
}
}
onParamChange(name: string, value: string): void {
this.parameters[name] = value;
this.updateScript();
}
updateScript(): void {
let updatedScript = this.selectedScript.script;
for (const [key, value] of Object.entries(this.parameters)) {
const regex = new RegExp(`@${key}\\b`, 'g');
updatedScript = updatedScript.replace(regex, value || `@${key}`);
}
this.scriptContent = updatedScript;
}
saveNewScript(): void {
if (!this.newScript.trim()) {
this.toastService.error(this.translate.instant('youMustEnterAScriptBefore'));
return;
}
const dialogRef = this.dialog.open(SaveScriptComponent, {
width: '400px',
data: this.newScript
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.toastService.success(this.translate.instant('scriptSavedSuccessfully'));
}
});
}
onSubmit(): void {
if (!this.selectedAction) {
this.toastService.error(this.translate.instant('selectActionTypeError'));
return;
}
if (this.executionOrder === null || this.executionOrder === undefined) {
this.toastService.error(this.translate.instant('executionOrderRequired'));
return;
}
let type = '';
let content = '';
switch (this.selectedAction) {
case 'run-script':
if (!this.validateScript()) return;
type = 'run-script';
content = this.commandType === 'existing' ? this.scriptContent : this.newScript;
break;
case 'power-on':
case 'shutdown':
case 'reboot':
type = this.selectedAction;
content = this.selectedAction;
break;
case 'login':
type = 'login';
content = 'login';
break;
default:
this.toastService.error(this.translate.instant('unrecognizedActionType'));
return;
}
const payload: any = {
commandTask: this.commandTask['@id'],
content: content,
order: this.executionOrder,
type: type,
};
if (this.selectedAction === 'login') {
payload.parameters = { disk: this.loginDisk, partition: this.loginPartition };
}
this.http.post(`${this.baseUrl}/command-task-scripts`, payload).subscribe({
next: () => {
this.toastService.success(this.translate.instant('actionAddedSuccess'));
this.dialogRef.close(true);
},
error: (error) => {
this.toastService.error(error.error['hydra:description']);
}
});
}
private validateScript(): boolean {
if (this.commandType === 'new') {
if (!this.newScript.trim()) {
this.toastService.error(this.translate.instant('youMustEnterAScript'));
return false;
}
} else if (this.commandType === 'existing') {
if (!this.selectedScript) {
this.toastService.error(this.translate.instant('youMustSelectAScript'));
return false;
}
}
return true;
}
onCancel(): void {
this.dialogRef.close(false);
}
getSelectedCategoryColor(): string {
const cat = this.categories.find(c => c.id === this.selectedCategory);
return cat?.color || '#1976d2';
}
getSelectedActionLabel(): string {
for (const cat of this.categories) {
const action = cat.actions.find(a => a.type === this.selectedAction);
if (action) return this.translate.instant(action.labelKey);
}
return '';
}
getSelectedActionIcon(): string {
for (const cat of this.categories) {
const action = cat.actions.find(a => a.type === this.selectedAction);
if (action) return action.icon;
}
return '';
}
}