changes in css

This commit is contained in:
Mateusz Gruszczyński
2026-04-16 11:08:11 +02:00
parent 649d1003b5
commit daf8ce53d0
11 changed files with 10 additions and 221 deletions

View File

@@ -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">

View File

@@ -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>

View File

@@ -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>

View File

@@ -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');
}
}

View File

@@ -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>

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -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);
} }