changes in css
This commit is contained in:
@@ -15,7 +15,7 @@
|
|||||||
<div class="operations-center">
|
<div class="operations-center">
|
||||||
<div class="operations-center__actions">
|
<div class="operations-center__actions">
|
||||||
<button pButton type="button" icon="pi pi-upload" [label]="'dashboard.exportAll' | translate" [loading]="exporting" (click)="exportAll()"></button>
|
<button pButton type="button" icon="pi pi-upload" [label]="'dashboard.exportAll' | translate" [loading]="exporting" (click)="exportAll()"></button>
|
||||||
<button pButton type="button" severity="secondary" styleClass="btn-binary-accent" icon="pi pi-database" [label]="'dashboard.binaryAll' | translate" [loading]="runningBinary" (click)="binaryAll()"></button>
|
<button pButton type="button" icon="pi pi-database" [label]="'dashboard.binaryAll' | translate" [loading]="runningBinary" (click)="binaryAll()"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="operations-center__stats">
|
<div class="operations-center__stats">
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<div header-actions class="header-actions-row router-header-actions router-header-actions--desktop">
|
<div header-actions class="header-actions-row router-header-actions router-header-actions--desktop">
|
||||||
<button pButton type="button" severity="secondary" icon="pi pi-pencil" [label]="'common.edit' | translate" (click)="openEdit()"></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 *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-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="secondary" 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.deleteDevice' | 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>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
<app-page-header [eyebrow]="'switchosBeta.eyebrow' | translate" [title]="'switchosBeta.title' | translate" [subtitle]="'switchosBeta.subtitle' | translate">
|
|
||||||
<div header-actions class="header-actions-row">
|
|
||||||
<p-tag severity="warn" [value]="'switchosBeta.betaTag' | translate"></p-tag>
|
|
||||||
</div>
|
|
||||||
</app-page-header>
|
|
||||||
|
|
||||||
<app-section-card [title]="'switchosBeta.warningTitle' | translate" [subtitle]="'switchosBeta.warningSubtitle' | translate">
|
|
||||||
<div class="beta-banner">
|
|
||||||
<div>
|
|
||||||
<strong>{{ 'switchosBeta.warningHeadline' | translate }}</strong>
|
|
||||||
<p>{{ 'switchosBeta.warningBody' | translate }}</p>
|
|
||||||
</div>
|
|
||||||
<p-tag severity="warn" [value]="'switchosBeta.betaTag' | translate"></p-tag>
|
|
||||||
</div>
|
|
||||||
</app-section-card>
|
|
||||||
|
|
||||||
<div class="metric-grid-2 swos-beta-grid">
|
|
||||||
<app-section-card [title]="'switchosBeta.formTitle' | translate" [subtitle]="'switchosBeta.formSubtitle' | translate">
|
|
||||||
<form [formGroup]="form" class="form-grid-2">
|
|
||||||
<span class="form-field">
|
|
||||||
<label>{{ 'switchosBeta.label' | translate }}</label>
|
|
||||||
<input pInputText formControlName="label" [placeholder]="'switchosBeta.labelPlaceholder' | translate" />
|
|
||||||
</span>
|
|
||||||
<span class="form-field">
|
|
||||||
<label>{{ 'switchosBeta.host' | translate }}</label>
|
|
||||||
<input pInputText formControlName="host" [placeholder]="'switchosBeta.hostPlaceholder' | translate" />
|
|
||||||
</span>
|
|
||||||
<span class="form-field">
|
|
||||||
<label>{{ 'switchosBeta.port' | translate }}</label>
|
|
||||||
<input pInputText type="number" formControlName="port" placeholder="80" />
|
|
||||||
</span>
|
|
||||||
<span class="form-field">
|
|
||||||
<label>{{ 'switchosBeta.username' | translate }}</label>
|
|
||||||
<input pInputText formControlName="username" placeholder="admin" />
|
|
||||||
</span>
|
|
||||||
<span class="form-field form-field--full">
|
|
||||||
<label>{{ 'switchosBeta.password' | translate }}</label>
|
|
||||||
<input pInputText type="password" formControlName="password" [placeholder]="'switchosBeta.passwordPlaceholder' | translate" />
|
|
||||||
</span>
|
|
||||||
<div class="dialog-actions swos-beta-actions">
|
|
||||||
<button pButton type="button" severity="secondary" icon="pi pi-search" [label]="'switchosBeta.probeButton' | translate" [loading]="probing" (click)="probe()"></button>
|
|
||||||
<button pButton type="button" icon="pi pi-download" [label]="'switchosBeta.downloadButton' | translate" [loading]="downloading" (click)="download()"></button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</app-section-card>
|
|
||||||
|
|
||||||
<app-section-card [title]="'switchosBeta.resultTitle' | translate" [subtitle]="'switchosBeta.resultSubtitle' | translate">
|
|
||||||
<div class="empty-state" *ngIf="!probeResult && !lastError">{{ 'switchosBeta.resultEmpty' | translate }}</div>
|
|
||||||
|
|
||||||
<div class="swos-beta-result" *ngIf="probeResult">
|
|
||||||
<div class="swos-beta-result__item">
|
|
||||||
<span>{{ 'switchosBeta.baseUrl' | translate }}</span>
|
|
||||||
<strong>{{ probeResult.base_url }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="swos-beta-result__item">
|
|
||||||
<span>{{ 'switchosBeta.httpStatus' | translate }}</span>
|
|
||||||
<strong>{{ probeResult.status_code }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="swos-beta-result__item">
|
|
||||||
<span>{{ 'switchosBeta.authMode' | translate }}</span>
|
|
||||||
<strong>{{ probeResult.auth_mode }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="swos-beta-result__item">
|
|
||||||
<span>{{ 'switchosBeta.pageTitle' | translate }}</span>
|
|
||||||
<strong>{{ probeResult.page_title || '—' }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="swos-beta-result__item">
|
|
||||||
<span>{{ 'switchosBeta.serverHeader' | translate }}</span>
|
|
||||||
<strong>{{ probeResult.server || '—' }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="swos-beta-result__item">
|
|
||||||
<span>{{ 'switchosBeta.backupEndpoint' | translate }}</span>
|
|
||||||
<strong>{{ (probeResult.backup_endpoint_ok ? 'switchosBeta.available' : 'switchosBeta.unavailable') | translate }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="swos-beta-note" *ngIf="probeResult.note">{{ probeResult.note }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="beta-error" *ngIf="lastError">{{ lastError }}</div>
|
|
||||||
</app-section-card>
|
|
||||||
</div>
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
|
|
||||||
import { Component, inject } from '@angular/core';
|
|
||||||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
import { finalize } from 'rxjs';
|
|
||||||
import { ButtonModule } from 'primeng/button';
|
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
|
||||||
import { TagModule } from 'primeng/tag';
|
|
||||||
|
|
||||||
import { ApiService } from '../../core/services/api.service';
|
|
||||||
import { UiService } from '../../core/services/ui.service';
|
|
||||||
import { PageHeaderComponent } from '../../shared/ui/page-header.component';
|
|
||||||
import { SectionCardComponent } from '../../shared/ui/section-card.component';
|
|
||||||
|
|
||||||
interface SwosBetaProbeResult {
|
|
||||||
success: boolean;
|
|
||||||
base_url: string;
|
|
||||||
status_code: number;
|
|
||||||
auth_mode: string;
|
|
||||||
page_title?: string | null;
|
|
||||||
content_type?: string | null;
|
|
||||||
server?: string | null;
|
|
||||||
save_backup_visible: boolean;
|
|
||||||
backup_endpoint_ok: boolean;
|
|
||||||
note?: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule, ReactiveFormsModule, TranslateModule, ButtonModule, InputTextModule, TagModule, PageHeaderComponent, SectionCardComponent],
|
|
||||||
templateUrl: './swos-beta-page.component.html'
|
|
||||||
})
|
|
||||||
export class SwosBetaPageComponent {
|
|
||||||
private readonly api = inject(ApiService);
|
|
||||||
private readonly fb = inject(FormBuilder);
|
|
||||||
private readonly ui = inject(UiService);
|
|
||||||
|
|
||||||
probing = false;
|
|
||||||
downloading = false;
|
|
||||||
lastError = '';
|
|
||||||
probeResult?: SwosBetaProbeResult;
|
|
||||||
|
|
||||||
readonly form = this.fb.nonNullable.group({
|
|
||||||
label: '',
|
|
||||||
host: ['', Validators.required],
|
|
||||||
port: [80, [Validators.required, Validators.min(1), Validators.max(65535)]],
|
|
||||||
username: ['admin', Validators.required],
|
|
||||||
password: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
get formValue() {
|
|
||||||
return this.form.getRawValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
probe() {
|
|
||||||
if (this.form.invalid || this.probing) {
|
|
||||||
this.form.markAllAsTouched();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastError = '';
|
|
||||||
this.probing = true;
|
|
||||||
this.api.http
|
|
||||||
.post<SwosBetaProbeResult>(`${this.api.baseUrl}/swos-beta/probe`, this.formValue)
|
|
||||||
.pipe(finalize(() => (this.probing = false)))
|
|
||||||
.subscribe({
|
|
||||||
next: (result) => {
|
|
||||||
this.probeResult = result;
|
|
||||||
this.ui.success('toast.swosBetaProbeOk');
|
|
||||||
},
|
|
||||||
error: (error: HttpErrorResponse) => {
|
|
||||||
this.probeResult = undefined;
|
|
||||||
this.lastError = this.extractError(error);
|
|
||||||
this.ui.error('toast.swosBetaProbeFailed');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
download() {
|
|
||||||
if (this.form.invalid || this.downloading) {
|
|
||||||
this.form.markAllAsTouched();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastError = '';
|
|
||||||
this.downloading = true;
|
|
||||||
this.api.http
|
|
||||||
.post(`${this.api.baseUrl}/swos-beta/download`, this.formValue, {
|
|
||||||
observe: 'response',
|
|
||||||
responseType: 'blob'
|
|
||||||
})
|
|
||||||
.pipe(finalize(() => (this.downloading = false)))
|
|
||||||
.subscribe({
|
|
||||||
next: (response) => {
|
|
||||||
this.saveBlob(response);
|
|
||||||
this.ui.success('toast.swosBetaDownloadOk');
|
|
||||||
},
|
|
||||||
error: (error: HttpErrorResponse) => {
|
|
||||||
this.lastError = this.extractError(error);
|
|
||||||
this.ui.error('toast.swosBetaDownloadFailed');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private saveBlob(response: HttpResponse<Blob>) {
|
|
||||||
const blob = response.body || new Blob();
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = url;
|
|
||||||
link.download = this.extractFilename(response.headers.get('content-disposition'));
|
|
||||||
link.click();
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
private extractFilename(disposition: string | null): string {
|
|
||||||
const match = disposition?.match(/filename="?([^\"]+)"?/i);
|
|
||||||
return match?.[1] || 'switchos-backup.swb';
|
|
||||||
}
|
|
||||||
|
|
||||||
private extractError(error: HttpErrorResponse): string {
|
|
||||||
const detail = error.error?.detail;
|
|
||||||
if (typeof detail === 'string' && detail.trim()) {
|
|
||||||
return detail.trim();
|
|
||||||
}
|
|
||||||
if (typeof error.error === 'string' && error.error.trim()) {
|
|
||||||
return error.error.trim();
|
|
||||||
}
|
|
||||||
return this.ui.instant('switchosBeta.genericError');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="sidebar-brand">
|
<div class="sidebar-brand">
|
||||||
<div class="sidebar-brand__logo">
|
<div class="sidebar-brand__logo">
|
||||||
<img src="https://mikrotik.com/logo/library/logo/SVG/MT_Symbol_Black.svg" alt="MikroTik" />
|
<img src="assets/mikrotik-w4y9rth430h5bcfzp9in8i.webp" alt="MikroTik" />
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-brand__text" *ngIf="!collapsed">
|
<div class="sidebar-brand__text" *ngIf="!collapsed">
|
||||||
<h2>{{ 'sidebar.title' | translate }}</h2>
|
<h2>{{ 'sidebar.title' | translate }}</h2>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"title": "Mikrotik Backup System",
|
"title": "Mikrotik Backup System",
|
||||||
"subtitle": "Device backup platform"
|
"subtitle": "RouterOS/SwitchOS"
|
||||||
},
|
},
|
||||||
"topbar": {
|
"topbar": {
|
||||||
"caption": "mikrotik / control center",
|
"caption": "mikrotik / control center",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"title": "copia de MikroTik",
|
"title": "copia de MikroTik",
|
||||||
"subtitle": "gestor de RouterOS/SwitchOS"
|
"subtitle": "RouterOS/SwitchOS"
|
||||||
},
|
},
|
||||||
"topbar": {
|
"topbar": {
|
||||||
"caption": "mikrotik / centro de control",
|
"caption": "mikrotik / centro de control",
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"title": "MikroTik-backup",
|
"title": "MikroTik-backup",
|
||||||
"subtitle": "RouterOS/SwitchOS-behandler"
|
"subtitle": "RouterOS/SwitchOS" },
|
||||||
},
|
|
||||||
"topbar": {
|
"topbar": {
|
||||||
"caption": "mikrotik / kontrollsenter",
|
"caption": "mikrotik / kontrollsenter",
|
||||||
"role": "administrator",
|
"role": "administrator",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"title": "Mikrotik Backup System",
|
"title": "Mikrotik Backup System",
|
||||||
"subtitle": "Device backup platform"
|
"subtitle": "RouterOS/SwitchOS"
|
||||||
},
|
},
|
||||||
"topbar": {
|
"topbar": {
|
||||||
"caption": "mikrotik / control center",
|
"caption": "mikrotik / control center",
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
"binaryLabel": "Backupy binarne",
|
"binaryLabel": "Backupy binarne",
|
||||||
"binaryLabelHint": "Obrazy odzyskiwania",
|
"binaryLabelHint": "Obrazy odzyskiwania",
|
||||||
"connectionLabel": "Połączenie",
|
"connectionLabel": "Połączenie",
|
||||||
"connectionLabelHint": "Status automatycznego lub ręcznego testu połączenia",
|
"connectionLabelHint": "Status testu połączenia",
|
||||||
"probeTag": "Test",
|
"probeTag": "Test",
|
||||||
"accessTag": "Dostęp",
|
"accessTag": "Dostęp",
|
||||||
"sshUserHint": "Efektywny login urządzenia",
|
"sshUserHint": "Efektywny login urządzenia",
|
||||||
|
|||||||
BIN
frontend/src/assets/mikrotik-w4y9rth430h5bcfzp9in8i.webp
Normal file
BIN
frontend/src/assets/mikrotik-w4y9rth430h5bcfzp9in8i.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1048,6 +1048,7 @@ body.dark-theme .topbar {
|
|||||||
padding: 0.55rem;
|
padding: 0.55rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
|
place-items: center;
|
||||||
box-shadow: inset 0 0 0 1px rgba(17, 20, 23, 0.08);
|
box-shadow: inset 0 0 0 1px rgba(17, 20, 23, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user