new features

This commit is contained in:
Mateusz Gruszczyński
2026-04-14 15:43:25 +02:00
parent 1a2ae0d607
commit 92a0f99fb3
17 changed files with 580 additions and 154 deletions

View File

@@ -4,10 +4,11 @@
[subtitle]="subtitle"
>
<div header-actions class="header-actions-row">
<button *ngIf="!isSwitchos" pButton type="button" icon="pi pi-upload" [label]="'routers.exportOne' | translate" [loading]="exporting" (click)="runExport()"></button>
<button pButton type="button" severity="secondary" icon="pi pi-database" [label]="(isSwitchos ? 'routers.downloadSwitchBackup' : 'routers.binaryOne') | translate" [loading]="runningBinary" (click)="runBinary()"></button>
<button pButton type="button" severity="secondary" icon="pi pi-pencil" [label]="'common.edit' | translate" (click)="openEdit()"></button>
<button *ngIf="!isSwitchos" pButton type="button" icon="pi pi-upload" [label]="'routers.exportOne' | translate" [loading]="exporting" [disabled]="routerItem?.disable_all_backups || routerItem?.disable_export_backups" (click)="runExport()"></button>
<button pButton type="button" severity="secondary" icon="pi pi-database" [label]="(isSwitchos ? 'routers.downloadSwitchBackup' : 'routers.binaryOne') | translate" [loading]="runningBinary" [disabled]="routerItem?.disable_all_backups || routerItem?.disable_binary_backups" (click)="runBinary()"></button>
<button pButton type="button" severity="info" icon="pi pi-wifi" [label]="'routers.testConnection' | translate" [loading]="testing" (click)="testConnection()"></button>
<button pButton type="button" severity="danger" icon="pi pi-trash" [label]="'routers.deleteRouter' | translate" [loading]="deletingRouter" (click)="deleteRouter()"></button>
<button pButton type="button" severity="danger" icon="pi pi-trash" [label]="'routers.deleteDevice' | translate" [loading]="deletingRouter" (click)="deleteRouter()"></button>
</div>
</app-page-header>
@@ -46,43 +47,93 @@
</ng-template>
</app-section-card>
<div class="router-detail-inspection-stack" *ngIf="!isSwitchos">
<app-section-card [title]="'routers.previewTitle' | translate" [subtitle]="'routers.previewSubtitle' | translate">
<div class="router-modal-summary" *ngIf="hasPreview; else noPreview">
<div>
<strong>{{ previewTitle }}</strong>
<small>{{ 'routers.previewModalHint' | translate }}</small>
</div>
<div class="dialog-actions">
<button pButton type="button" severity="info" icon="pi pi-eye" [label]="'routers.openPreviewModal' | translate" (click)="openPreviewModal()"></button>
</div>
<app-section-card [title]="'routers.backupSettingsTitle' | translate" [subtitle]="'routers.backupSettingsHint' | translate">
<form [formGroup]="settingsForm" class="device-settings-form" (ngSubmit)="saveSettings()">
<div class="device-settings-stack">
<label class="device-toggle device-toggle--primary" [class.is-active]="settingsForm.controls.disable_all_backups.value">
<input type="checkbox" formControlName="disable_all_backups" />
<span class="device-toggle__switch" aria-hidden="true"></span>
<span class="device-toggle__icon"><i class="pi pi-ban"></i></span>
<span class="device-toggle__content">
<strong>{{ 'routers.disableAllBackups' | translate }}</strong>
<small>{{ 'routers.disableAllBackupsHint' | translate }}</small>
</span>
<span class="device-toggle__state">{{ (settingsForm.controls.disable_all_backups.value ? 'common.enabled' : 'common.disabled') | translate }}</span>
</label>
<label class="device-toggle" *ngIf="!isSwitchos" [class.is-active]="settingsForm.controls.disable_export_backups.value">
<input type="checkbox" formControlName="disable_export_backups" />
<span class="device-toggle__switch" aria-hidden="true"></span>
<span class="device-toggle__icon"><i class="pi pi-file-export"></i></span>
<span class="device-toggle__content">
<strong>{{ 'routers.disableExports' | translate }}</strong>
<small>{{ 'routers.disableExportsHint' | translate }}</small>
</span>
<span class="device-toggle__state">{{ (settingsForm.controls.disable_export_backups.value ? 'common.enabled' : 'common.disabled') | translate }}</span>
</label>
<label class="device-toggle" [class.is-active]="settingsForm.controls.disable_binary_backups.value">
<input type="checkbox" formControlName="disable_binary_backups" />
<span class="device-toggle__switch" aria-hidden="true"></span>
<span class="device-toggle__icon"><i class="pi pi-database"></i></span>
<span class="device-toggle__content">
<strong>{{ 'routers.disableBinaryBackups' | translate }}</strong>
<small>{{ 'routers.disableBinaryBackupsHint' | translate }}</small>
</span>
<span class="device-toggle__state">{{ (settingsForm.controls.disable_binary_backups.value ? 'common.enabled' : 'common.disabled') | translate }}</span>
</label>
<label class="device-toggle" [class.is-active]="settingsForm.controls.disable_ping.value">
<input type="checkbox" formControlName="disable_ping" />
<span class="device-toggle__switch" aria-hidden="true"></span>
<span class="device-toggle__icon"><i class="pi pi-wifi"></i></span>
<span class="device-toggle__content">
<strong>{{ 'routers.disablePing' | translate }}</strong>
<small>{{ 'routers.disablePingHint' | translate }}</small>
</span>
<span class="device-toggle__state">{{ (settingsForm.controls.disable_ping.value ? 'common.enabled' : 'common.disabled') | translate }}</span>
</label>
</div>
<ng-template #noPreview>
<div class="empty-state compact-empty">
<i class="pi pi-eye"></i>
<p>{{ 'routers.noPreview' | translate }}</p>
</div>
</ng-template>
</app-section-card>
<div class="dialog-actions device-settings-actions">
<button pButton type="submit" [loading]="savingSettings" [disabled]="savingSettings" [label]="'common.save' | translate"></button>
</div>
</form>
</app-section-card>
</div>
<app-section-card [title]="'routers.diffTitle' | translate" [subtitle]="'routers.diffSubtitle' | translate">
<div class="router-modal-summary" *ngIf="hasDiff && diffData; else noDiff">
<div>
<strong>{{ diffData.left_file_name }} → {{ diffData.right_file_name }}</strong>
<small>{{ 'routers.diffModalHint' | translate }}</small>
</div>
<div class="dialog-actions">
<button pButton type="button" severity="help" icon="pi pi-code" [label]="'routers.openDiffModal' | translate" (click)="openDiffModal()"></button>
</div>
<div class="router-detail-split-grid" *ngIf="!isSwitchos">
<app-section-card [title]="'routers.previewTitle' | translate" [subtitle]="'routers.previewSubtitle' | translate">
<div class="router-modal-summary" *ngIf="hasPreview; else noPreview">
<div>
<strong>{{ previewTitle }}</strong>
<small>{{ 'routers.previewModalHint' | translate }}</small>
</div>
<ng-template #noDiff>
<div class="empty-state compact-empty">
<i class="pi pi-code"></i>
<p>{{ 'routers.noDiff' | translate }}</p>
</div>
</ng-template>
</app-section-card>
</div>
<div class="dialog-actions">
<button pButton type="button" severity="info" icon="pi pi-eye" [label]="'routers.openPreviewModal' | translate" (click)="openPreviewModal()"></button>
</div>
</div>
<ng-template #noPreview>
<div class="empty-state compact-empty">
<i class="pi pi-eye"></i>
<p>{{ 'routers.noPreview' | translate }}</p>
</div>
</ng-template>
</app-section-card>
<app-section-card [title]="'routers.diffTitle' | translate" [subtitle]="'routers.diffSubtitle' | translate">
<div class="router-modal-summary" *ngIf="hasDiff && diffData; else noDiff">
<div>
<strong>{{ diffData.left_file_name }} → {{ diffData.right_file_name }}</strong>
<small>{{ 'routers.diffModalHint' | translate }}</small>
</div>
<div class="dialog-actions">
<button pButton type="button" severity="help" icon="pi pi-code" [label]="'routers.openDiffModal' | translate" (click)="openDiffModal()"></button>
</div>
</div>
<ng-template #noDiff>
<div class="empty-state compact-empty">
<i class="pi pi-code"></i>
<p>{{ 'routers.noDiff' | translate }}</p>
</div>
</ng-template>
</app-section-card>
</div>
<div class="dashboard-grid router-detail-grid router-detail-grid--stack" *ngIf="!isSwitchos">
@@ -168,3 +219,84 @@
<pre class="code-preview preview-dialog__content">{{ diffText }}</pre>
</ng-template>
</p-dialog>
<p-dialog [(visible)]="editVisible" [modal]="true" [draggable]="false" [resizable]="false" [style]="{ width: 'min(760px, 96vw)' }" styleClass="router-dialog">
<ng-template pTemplate="header">
<div class="router-dialog-header">
<div class="router-dialog-header__icon">
<i class="pi" [ngClass]="selectedDeviceType === 'switchos' ? 'pi-sitemap' : 'pi-server'"></i>
</div>
<div class="router-dialog-header__text">
<div class="router-dialog-header__eyebrow">
{{ 'routers.deviceType' | translate }} · {{ selectedDeviceType === 'switchos' ? ('routers.switchos' | translate) : ('routers.routeros' | translate) }}
</div>
<div class="router-dialog-header__title">{{ 'routers.editDialogTitle' | translate }}</div>
<small>
{{
selectedDeviceType === 'switchos'
? ('routers.switchDialogSubtitle' | translate)
: ('routers.routerDialogSubtitle' | translate)
}}
</small>
</div>
</div>
</ng-template>
<form [formGroup]="form" (ngSubmit)="saveEdit()" class="router-dialog-form">
<section class="router-dialog-panel">
<div class="router-dialog-panel__header">
<div>
<strong>{{ 'routers.connectionSectionTitle' | translate }}</strong>
<p>{{ 'routers.connectionSectionHint' | translate }}</p>
</div>
</div>
<div class="form-grid-2 router-dialog-grid">
<span class="form-field">
<label>{{ 'routers.name' | translate }}</label>
<input pInputText formControlName="name" />
</span>
<span class="form-field">
<label>{{ 'routers.deviceType' | translate }}</label>
<p-select [appendTo]="'body'" [options]="deviceTypeOptions" formControlName="device_type" optionLabel="label" optionValue="value"></p-select>
</span>
<span class="form-field">
<label>{{ 'routers.host' | translate }}</label>
<input pInputText formControlName="host" />
</span>
<span class="form-field">
<label>{{ 'routers.port' | translate }}</label>
<input pInputText type="number" formControlName="port" />
</span>
</div>
</section>
<section class="router-dialog-panel">
<div class="router-dialog-panel__header">
<div>
<strong>{{ 'routers.credentialsSectionTitle' | translate }}</strong>
<p>{{ selectedDeviceType === 'switchos' ? ('routers.switchDialogSubtitle' | translate) : ('routers.routerDialogSubtitle' | translate) }}</p>
</div>
</div>
<div class="form-grid-2 router-dialog-grid">
<span class="form-field">
<label>{{ 'routers.sshUser' | translate }}</label>
<input pInputText formControlName="ssh_user" [placeholder]="selectedDeviceType === 'switchos' ? ('routers.switchUserPlaceholder' | translate) : 'admin'" />
</span>
<span class="form-field">
<label>{{ 'routers.sshPassword' | translate }}</label>
<input pInputText type="password" formControlName="ssh_password" [placeholder]="selectedDeviceType === 'switchos' ? ('routers.switchPasswordPlaceholder' | translate) : ('routers.optionalPassword' | translate)" />
</span>
<span class="form-field form-field--full" *ngIf="selectedDeviceType === 'routeros'">
<label>{{ 'routers.sshPrivateKey' | translate }}</label>
<textarea pTextarea formControlName="ssh_key" rows="8" [placeholder]="'routers.optionalPrivateKey' | translate"></textarea>
</span>
</div>
</section>
<div class="dialog-actions router-dialog-actions">
<button pButton type="button" severity="secondary" [label]="'common.cancel' | translate" (click)="editVisible=false"></button>
<button pButton type="submit" [disabled]="form.invalid || saving" [loading]="saving" [label]="'routers.saveRouter' | translate"></button>
</div>
</form>
</p-dialog>