319 lines
8.8 KiB
TypeScript
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 '';
|
|
}
|
|
}
|