switchos support
This commit is contained in:
@@ -56,10 +56,9 @@ export class AppComponent {
|
||||
{ label: 'nav.routers', link: '/routers', icon: 'pi pi-server', exact: false },
|
||||
{ label: 'nav.files', link: '/files', icon: 'pi pi-folder-open', exact: false },
|
||||
{ label: 'nav.diffConfigs', link: '/diff-configs', icon: 'pi pi-code', exact: false },
|
||||
{ label: 'nav.settings', link: '/settings', icon: 'pi pi-cog', exact: false },
|
||||
{ label: 'nav.logs', link: '/logs', icon: 'pi pi-history', exact: false },
|
||||
{ label: 'nav.switchosBeta', link: '/switchos-beta', icon: 'pi pi-sitemap', exact: false },
|
||||
{ label: 'nav.changePassword', link: '/change-password', icon: 'pi pi-lock', exact: false }
|
||||
{ label: 'nav.changePassword', link: '/change-password', icon: 'pi pi-lock', exact: false },
|
||||
{ label: 'nav.settings', link: '/settings', icon: 'pi pi-cog', exact: false }
|
||||
];
|
||||
|
||||
get currentPageTitle(): string {
|
||||
@@ -133,10 +132,6 @@ export class AppComponent {
|
||||
this.pageLabel = 'logs.title';
|
||||
return;
|
||||
}
|
||||
if (url.startsWith('/switchos-beta')) {
|
||||
this.pageLabel = 'switchosBeta.title';
|
||||
return;
|
||||
}
|
||||
if (url.startsWith('/change-password')) {
|
||||
this.pageLabel = 'auth.changePassword';
|
||||
return;
|
||||
|
||||
@@ -11,7 +11,6 @@ import { LogsPageComponent } from './features/logs/logs-page.component';
|
||||
import { RouterDetailPageComponent } from './features/routers/router-detail-page.component';
|
||||
import { RoutersPageComponent } from './features/routers/routers-page.component';
|
||||
import { SettingsPageComponent } from './features/settings/settings-page.component';
|
||||
import { SwosBetaPageComponent } from './features/swos-beta/swos-beta-page.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: 'login', component: LoginPageComponent },
|
||||
@@ -24,6 +23,5 @@ export const routes: Routes = [
|
||||
{ path: 'diff-configs', canActivate: [authGuard], component: DiffConfigsPageComponent },
|
||||
{ path: 'settings', canActivate: [authGuard], component: SettingsPageComponent },
|
||||
{ path: 'logs', canActivate: [authGuard], component: LogsPageComponent },
|
||||
{ path: 'switchos-beta', canActivate: [authGuard], component: SwosBetaPageComponent },
|
||||
{ path: '**', redirectTo: '' }
|
||||
];
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="table-primary">{{ item.router_name || item.router_id }}</div>
|
||||
<small class="table-secondary">ID {{ item.router_id }}</small>
|
||||
<small class="table-secondary">{{ deviceLabel(item) }} · ID {{ item.router_id }}</small>
|
||||
</td>
|
||||
<td><p-tag [value]="item.backup_type === 'export' ? ('files.exportType' | translate) : ('files.binaryType' | translate)" [severity]="item.backup_type === 'export' ? 'success' : 'warning'"></p-tag></td>
|
||||
<td>
|
||||
@@ -113,7 +113,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="table-primary">{{ formatBytes(item.file_size) }}</div>
|
||||
<small class="table-secondary">{{ item.backup_type === 'export' ? '.rsc' : '.backup' }}</small>
|
||||
<small class="table-secondary">{{ fileExtension(item) }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="table-actions table-actions--stack" *ngIf="item.backup_type === 'export'; else noCompare">
|
||||
@@ -130,7 +130,7 @@
|
||||
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" icon="pi pi-download" [label]="'common.download' | translate" (click)="download(item.id)"></button>
|
||||
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="secondary" icon="pi pi-envelope" [label]="'common.email' | translate" (click)="sendEmail(item.id)"></button>
|
||||
<button *ngIf="item.backup_type==='export'" pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="info" icon="pi pi-eye" [label]="'common.preview' | translate" (click)="viewExport(item)"></button>
|
||||
<button *ngIf="item.backup_type==='binary'" pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="help" icon="pi pi-upload" [label]="'common.restore' | translate" (click)="upload(item)"></button>
|
||||
<button *ngIf="item.backup_type==='binary' && item.device_type==='routeros'" pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="help" icon="pi pi-upload" [label]="'common.restore' | translate" (click)="upload(item)"></button>
|
||||
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="danger" icon="pi pi-trash" [label]="'common.delete' | translate" (click)="deleteOne(item.id)"></button>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -16,10 +16,13 @@ import { PageHeaderComponent } from '../../shared/ui/page-header.component';
|
||||
import { SectionCardComponent } from '../../shared/ui/section-card.component';
|
||||
import { StatCardComponent } from '../../shared/ui/stat-card.component';
|
||||
|
||||
type DeviceType = 'routeros' | 'switchos';
|
||||
|
||||
interface BackupFile {
|
||||
id: number;
|
||||
router_id: number;
|
||||
router_name?: string;
|
||||
device_type: DeviceType;
|
||||
file_name: string;
|
||||
backup_type: 'export' | 'binary';
|
||||
created_at: string;
|
||||
@@ -233,6 +236,9 @@ export class FilesPageComponent implements OnInit {
|
||||
}
|
||||
|
||||
upload(item: BackupFile) {
|
||||
if (item.device_type !== 'routeros') {
|
||||
return;
|
||||
}
|
||||
this.api.http.post(`${this.api.baseUrl}/backups/router/${item.router_id}/upload/${item.id}`, {}).subscribe(() => {
|
||||
this.ui.success('toast.binaryUploaded');
|
||||
});
|
||||
@@ -410,6 +416,15 @@ export class FilesPageComponent implements OnInit {
|
||||
return `${value.slice(0, 8)}…${value.slice(-6)}`;
|
||||
}
|
||||
|
||||
deviceLabel(item: BackupFile): string {
|
||||
return this.ui.instant(item.device_type === 'switchos' ? 'routers.switchos' : 'routers.routeros');
|
||||
}
|
||||
|
||||
fileExtension(item: BackupFile): string {
|
||||
const parts = item.file_name.split('.');
|
||||
return parts.length > 1 ? `.${parts[parts.length - 1]}` : '—';
|
||||
}
|
||||
|
||||
private setComparePair(firstId: number, secondId: number) {
|
||||
const [left, right] = this.sortPairByDate(firstId, secondId);
|
||||
this.compareLeftId = left;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<app-page-header
|
||||
[eyebrow]="'routers.profileEyebrow' | translate"
|
||||
[title]="routerItem?.name || ('routers.detailTitle' | translate)"
|
||||
[subtitle]="routerItem ? routerItem.host + ':' + routerItem.port + ' · ' + routerItem.ssh_user : ('routers.detailSubtitle' | translate)"
|
||||
[subtitle]="subtitle"
|
||||
>
|
||||
<div header-actions class="header-actions-row">
|
||||
<button 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]="'routers.binaryOne' | translate" [loading]="runningBinary" (click)="runBinary()"></button>
|
||||
<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="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>
|
||||
</div>
|
||||
</app-page-header>
|
||||
|
||||
<div class="stats-grid compact-grid">
|
||||
<app-stat-card [label]="'routers.exportsLabel' | translate" [value]="exportBackups.length" [hint]="'routers.exportsLabelHint' | translate" [tag]="'files.exportType' | translate" severity="success" icon="pi pi-file-export" iconClass="icon-emerald"></app-stat-card>
|
||||
<app-stat-card [label]="'routers.deviceType' | translate" [value]="deviceTypeLabel" [hint]="'routers.listSubtitle' | translate" [tag]="'routers.fleetTag' | translate" severity="info" icon="pi pi-sitemap" iconClass="icon-blue"></app-stat-card>
|
||||
<app-stat-card [label]="'routers.binaryLabel' | translate" [value]="binaryBackups.length" [hint]="'routers.binaryLabelHint' | translate" [tag]="'files.binaryType' | translate" severity="warning" icon="pi pi-database" iconClass="icon-amber"></app-stat-card>
|
||||
<app-stat-card [label]="'routers.connectionLabel' | translate" [value]="connectionStateLabel" [hint]="'routers.connectionLabelHint' | translate" [tag]="'routers.probeTag' | translate" severity="info" icon="pi pi-bolt" iconClass="icon-blue"></app-stat-card>
|
||||
<app-stat-card [label]="'routers.sshUser' | translate" [value]="routerItem?.ssh_user || '-'" [hint]="'routers.sshUserHint' | translate" [tag]="'routers.accessTag' | translate" severity="secondary" icon="pi pi-user" iconClass="icon-violet"></app-stat-card>
|
||||
<app-stat-card [label]="'routers.sshUser' | translate" [value]="routerItem?.effective_username || '-'" [hint]="'routers.sshUserHint' | translate" [tag]="'routers.accessTag' | translate" severity="secondary" icon="pi pi-user" iconClass="icon-violet"></app-stat-card>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid router-detail-grid router-detail-grid--inspection">
|
||||
@@ -28,6 +28,10 @@
|
||||
<div class="metric-tile"><span>{{ 'routers.model' | translate }}</span><strong>{{ connection.model }}</strong></div>
|
||||
<div class="metric-tile"><span>{{ 'routers.version' | translate }}</span><strong>{{ connection.version || 'n/a' }}</strong></div>
|
||||
<div class="metric-tile"><span>{{ 'routers.uptime' | translate }}</span><strong>{{ connection.uptime }}</strong></div>
|
||||
<div class="metric-tile" *ngIf="isSwitchos"><span>{{ 'routers.httpStatus' | translate }}</span><strong>{{ connection.http_status || '—' }}</strong></div>
|
||||
<div class="metric-tile" *ngIf="isSwitchos"><span>{{ 'routers.serverHeader' | translate }}</span><strong>{{ connection.server || '—' }}</strong></div>
|
||||
<div class="metric-tile" *ngIf="isSwitchos"><span>{{ 'routers.authMode' | translate }}</span><strong>{{ connection.auth_mode || '—' }}</strong></div>
|
||||
<div class="metric-tile" *ngIf="isSwitchos"><span>{{ 'routers.backupEndpoint' | translate }}</span><strong>{{ connection.backup_available ? ('routers.backupAvailable' | translate) : ('routers.backupUnavailable' | translate) }}</strong></div>
|
||||
</div>
|
||||
<div class="router-status-error" *ngIf="!connection.success && connection.error">
|
||||
<strong>{{ 'routers.lastError' | translate }}</strong>
|
||||
@@ -42,7 +46,7 @@
|
||||
</ng-template>
|
||||
</app-section-card>
|
||||
|
||||
<div class="router-detail-inspection-stack">
|
||||
<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>
|
||||
@@ -81,7 +85,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid router-detail-grid router-detail-grid--stack">
|
||||
<div class="dashboard-grid router-detail-grid router-detail-grid--stack" *ngIf="!isSwitchos">
|
||||
<app-section-card [title]="'routers.exportsTableTitle' | translate" [subtitle]="'routers.exportsTableSubtitle' | translate">
|
||||
<p-table [value]="exportBackups" responsiveLayout="scroll" styleClass="app-table">
|
||||
<ng-template pTemplate="header">
|
||||
@@ -107,7 +111,9 @@
|
||||
</ng-template>
|
||||
</p-table>
|
||||
</app-section-card>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid router-detail-grid router-detail-grid--stack">
|
||||
<app-section-card [title]="'routers.binaryTableTitle' | translate" [subtitle]="'routers.binaryTableSubtitle' | translate">
|
||||
<p-table [value]="binaryBackups" responsiveLayout="scroll" styleClass="app-table">
|
||||
<ng-template pTemplate="header">
|
||||
@@ -123,7 +129,7 @@
|
||||
<td>
|
||||
<div class="table-actions table-actions--labels table-actions--tight">
|
||||
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide table-action-btn--compact" icon="pi pi-download" [label]="'common.download' | translate" (click)="download(item.id)"></button>
|
||||
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide table-action-btn--compact" severity="help" icon="pi pi-upload" [label]="'common.restore' | translate" (click)="upload(item.id)"></button>
|
||||
<button *ngIf="!isSwitchos" pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide table-action-btn--compact" severity="help" icon="pi pi-upload" [label]="'common.restore' | translate" (click)="upload(item.id)"></button>
|
||||
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide table-action-btn--compact" severity="secondary" icon="pi pi-envelope" [label]="'common.email' | translate" (click)="sendEmail(item.id)"></button>
|
||||
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide table-action-btn--compact" severity="danger" icon="pi pi-trash" [label]="'common.delete' | translate" (click)="remove(item.id)"></button>
|
||||
</div>
|
||||
|
||||
@@ -14,11 +14,37 @@ import { PageHeaderComponent } from '../../shared/ui/page-header.component';
|
||||
import { SectionCardComponent } from '../../shared/ui/section-card.component';
|
||||
import { StatCardComponent } from '../../shared/ui/stat-card.component';
|
||||
|
||||
type DeviceType = 'routeros' | 'switchos';
|
||||
|
||||
interface DeviceItem {
|
||||
id: number;
|
||||
name: string;
|
||||
host: string;
|
||||
port: number;
|
||||
device_type: DeviceType;
|
||||
effective_username?: string | null;
|
||||
supports_export: boolean;
|
||||
supports_restore_upload: boolean;
|
||||
last_connection_status?: boolean | null;
|
||||
last_connection_tested_at?: string | null;
|
||||
last_connection_error?: string | null;
|
||||
last_connection_hostname?: string | null;
|
||||
last_connection_model?: string | null;
|
||||
last_connection_version?: string | null;
|
||||
last_connection_uptime?: string | null;
|
||||
last_connection_transport?: string | null;
|
||||
last_connection_server?: string | null;
|
||||
last_connection_auth_mode?: string | null;
|
||||
last_connection_http_status?: string | null;
|
||||
last_connection_backup_available?: boolean | null;
|
||||
}
|
||||
|
||||
interface BackupItem {
|
||||
id: number;
|
||||
file_name: string;
|
||||
backup_type: 'export' | 'binary';
|
||||
created_at: string;
|
||||
device_type: DeviceType;
|
||||
}
|
||||
|
||||
interface ConnectionSnapshot {
|
||||
@@ -29,6 +55,11 @@ interface ConnectionSnapshot {
|
||||
version?: string | null;
|
||||
uptime: string;
|
||||
error?: string | null;
|
||||
transport?: string | null;
|
||||
server?: string | null;
|
||||
auth_mode?: string | null;
|
||||
http_status?: string | null;
|
||||
backup_available?: boolean | null;
|
||||
}
|
||||
|
||||
interface BackupDiffStats {
|
||||
@@ -59,7 +90,7 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
private readonly ui = inject(UiService);
|
||||
|
||||
routerId!: number;
|
||||
routerItem: any;
|
||||
routerItem: DeviceItem | null = null;
|
||||
backups: BackupItem[] = [];
|
||||
connection: ConnectionSnapshot | null = null;
|
||||
exportContent = '';
|
||||
@@ -73,6 +104,10 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
testing = false;
|
||||
deletingRouter = false;
|
||||
|
||||
get isSwitchos(): boolean {
|
||||
return this.routerItem?.device_type === 'switchos';
|
||||
}
|
||||
|
||||
get exportBackups(): BackupItem[] {
|
||||
return this.backups.filter((item) => item.backup_type === 'export');
|
||||
}
|
||||
@@ -96,13 +131,25 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
return !!this.diffText;
|
||||
}
|
||||
|
||||
get subtitle(): string {
|
||||
if (!this.routerItem) {
|
||||
return this.ui.instant('routers.detailSubtitle');
|
||||
}
|
||||
const suffix = this.routerItem.effective_username ? ` · ${this.routerItem.effective_username}` : '';
|
||||
return `${this.routerItem.host}:${this.routerItem.port}${suffix}`;
|
||||
}
|
||||
|
||||
get deviceTypeLabel(): string {
|
||||
return this.ui.instant(this.isSwitchos ? 'routers.switchos' : 'routers.routeros');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.routerId = Number(this.route.snapshot.paramMap.get('id'));
|
||||
this.load();
|
||||
}
|
||||
|
||||
load() {
|
||||
this.api.http.get(`${this.api.baseUrl}/routers/${this.routerId}`).subscribe((routerItem: any) => {
|
||||
this.api.http.get<DeviceItem>(`${this.api.baseUrl}/routers/${this.routerId}`).subscribe((routerItem) => {
|
||||
this.routerItem = routerItem;
|
||||
this.connection = this.mapStoredConnection(routerItem);
|
||||
});
|
||||
@@ -110,7 +157,7 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
}
|
||||
|
||||
runExport() {
|
||||
if (this.exporting) {
|
||||
if (this.exporting || this.isSwitchos) {
|
||||
return;
|
||||
}
|
||||
this.exporting = true;
|
||||
@@ -187,6 +234,9 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
}
|
||||
|
||||
upload(id: number) {
|
||||
if (this.isSwitchos) {
|
||||
return;
|
||||
}
|
||||
this.api.http.post(`${this.api.baseUrl}/backups/router/${this.routerId}/upload/${id}`, {}).subscribe(() => {
|
||||
this.ui.success('toast.binaryUploaded');
|
||||
});
|
||||
@@ -217,7 +267,7 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
|
||||
viewExport(id: number) {
|
||||
const backup = this.exportBackups.find((item) => item.id === id);
|
||||
this.api.http.get<any>(`${this.api.baseUrl}/backups/${id}/view`).subscribe((r) => {
|
||||
this.api.http.get<{ content: string }>(`${this.api.baseUrl}/backups/${id}/view`).subscribe((r) => {
|
||||
this.exportContent = r.content;
|
||||
this.previewTitle = backup?.file_name || this.ui.instant('routers.previewTitle');
|
||||
this.ui.clear();
|
||||
@@ -241,7 +291,7 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
this.diffVisible = true;
|
||||
}
|
||||
|
||||
private mapStoredConnection(routerItem: any): ConnectionSnapshot | null {
|
||||
private mapStoredConnection(routerItem: DeviceItem): ConnectionSnapshot | null {
|
||||
if (!routerItem?.last_connection_tested_at) {
|
||||
return null;
|
||||
}
|
||||
@@ -252,7 +302,12 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
model: routerItem.last_connection_model || 'Unknown',
|
||||
version: routerItem.last_connection_version,
|
||||
uptime: routerItem.last_connection_uptime || 'Unknown',
|
||||
error: routerItem.last_connection_error || null
|
||||
error: routerItem.last_connection_error || null,
|
||||
transport: routerItem.last_connection_transport || null,
|
||||
server: routerItem.last_connection_server || null,
|
||||
auth_mode: routerItem.last_connection_auth_mode || null,
|
||||
http_status: routerItem.last_connection_http_status || null,
|
||||
backup_available: routerItem.last_connection_backup_available ?? null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -269,6 +324,11 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
last_connection_version: result.version,
|
||||
last_connection_uptime: result.uptime,
|
||||
last_connection_error: result.error,
|
||||
last_connection_transport: result.transport,
|
||||
last_connection_server: result.server,
|
||||
last_connection_auth_mode: result.auth_mode,
|
||||
last_connection_http_status: result.http_status,
|
||||
last_connection_backup_available: result.backup_available
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
</div>
|
||||
<div class="inline-summary__divider"></div>
|
||||
<div class="inline-summary__item">
|
||||
<strong>{{ keyCount }}</strong>
|
||||
<span>{{ 'routers.summaryKeyAccess' | translate }}</span>
|
||||
<strong>{{ routerOsCount }}</strong>
|
||||
<span>{{ 'routers.routeros' | translate }}</span>
|
||||
</div>
|
||||
<div class="inline-summary__divider"></div>
|
||||
<div class="inline-summary__item">
|
||||
<strong>{{ passwordCount }}</strong>
|
||||
<span>{{ 'routers.summaryPasswordAccess' | translate }}</span>
|
||||
<strong>{{ switchOsCount }}</strong>
|
||||
<span>{{ 'routers.switchos' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,16 +30,16 @@
|
||||
<tr>
|
||||
<td>
|
||||
<div class="table-primary">{{ routerItem.name }}</div>
|
||||
<small class="table-secondary">{{ 'routers.routerOsTarget' | translate }}</small>
|
||||
<small class="table-secondary">{{ deviceTypeLabel(routerItem) }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="table-primary">{{ routerItem.host }}:{{ routerItem.port }}</div>
|
||||
<small class="table-secondary">{{ routerItem.ssh_user }}</small>
|
||||
<small class="table-secondary">{{ accessUser(routerItem) }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="inline-tags">
|
||||
<p-tag [value]="routerItem.ssh_password ? ('routers.passwordMode' | translate) : ('routers.noPassword' | translate)" [severity]="routerItem.ssh_password ? 'warning' : 'secondary'"></p-tag>
|
||||
<p-tag [value]="hasEffectiveSshKey(routerItem) ? ((usesGlobalSshKey(routerItem) ? 'routers.globalKeyMode' : 'routers.keyMode') | translate) : ('routers.noKey' | translate)" [severity]="hasEffectiveSshKey(routerItem) ? 'success' : 'secondary'"></p-tag>
|
||||
<p-tag [value]="primaryAccessTag(routerItem).value" [severity]="primaryAccessTag(routerItem).severity"></p-tag>
|
||||
<p-tag [value]="secondaryAccessTag(routerItem).value" [severity]="secondaryAccessTag(routerItem).severity"></p-tag>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
@@ -54,33 +54,101 @@
|
||||
</p-table>
|
||||
</app-section-card>
|
||||
|
||||
<p-dialog [(visible)]="visible" [modal]="true" [header]="dialogTitle" [style]="{ width: '640px' }" styleClass="router-dialog">
|
||||
<form [formGroup]="form" (ngSubmit)="save()" class="form-grid-2">
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.name' | translate }}</label>
|
||||
<input pInputText formControlName="name" placeholder="core-router-waw" />
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.host' | translate }}</label>
|
||||
<input pInputText formControlName="host" placeholder="10.0.0.1" />
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.port' | translate }}</label>
|
||||
<input pInputText type="number" formControlName="port" placeholder="22" />
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.sshUser' | translate }}</label>
|
||||
<input pInputText formControlName="ssh_user" placeholder="admin" />
|
||||
</span>
|
||||
<span class="form-field form-field--full">
|
||||
<label>{{ 'routers.sshPassword' | translate }}</label>
|
||||
<input pInputText formControlName="ssh_password" [placeholder]="'routers.optionalPassword' | translate" />
|
||||
</span>
|
||||
<span class="form-field form-field--full">
|
||||
<label>{{ 'routers.sshPrivateKey' | translate }}</label>
|
||||
<textarea pInputTextarea formControlName="ssh_key" rows="7" [placeholder]="'routers.optionalPrivateKey' | translate"></textarea>
|
||||
</span>
|
||||
<div class="dialog-actions">
|
||||
<p-dialog [(visible)]="visible" [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">{{ dialogTitle }}</div>
|
||||
<small>
|
||||
{{
|
||||
selectedDeviceType === 'switchos'
|
||||
? ('routers.switchDialogSubtitle' | translate)
|
||||
: ('routers.routerDialogSubtitle' | translate)
|
||||
}}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="save()" 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>
|
||||
<span class="router-dialog-pill">
|
||||
<i class="pi" [ngClass]="selectedDeviceType === 'switchos' ? 'pi-globe' : 'pi-shield'"></i>
|
||||
{{ selectedDeviceType === 'switchos' ? 'HTTP' : 'SSH' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="form-grid-2 router-dialog-grid">
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.name' | translate }}</label>
|
||||
<input pInputText formControlName="name" placeholder="core-router-waw" />
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.deviceType' | translate }}</label>
|
||||
<p-dropdown [options]="deviceTypeOptions" formControlName="device_type" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.host' | translate }}</label>
|
||||
<input pInputText formControlName="host" placeholder="10.0.0.1" />
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.port' | translate }}</label>
|
||||
<input pInputText type="number" formControlName="port" [placeholder]="selectedDeviceType === 'switchos' ? '80' : '22'" />
|
||||
</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>
|
||||
<span class="router-dialog-pill">
|
||||
<i class="pi pi-key"></i>
|
||||
{{ selectedDeviceType === 'switchos' ? ('routers.defaultCredentials' | translate) : 'SSH' }}
|
||||
</span>
|
||||
</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 pInputTextarea formControlName="ssh_key" rows="8" [placeholder]="'routers.optionalPrivateKey' | translate"></textarea>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="router-dialog-note" *ngIf="selectedDeviceType === 'switchos'">
|
||||
<i class="pi pi-info-circle"></i>
|
||||
<span>{{ 'routers.switchDefaultsHint' | translate }}</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="dialog-actions router-dialog-actions">
|
||||
<button pButton type="button" severity="secondary" [label]="'common.cancel' | translate" (click)="visible=false"></button>
|
||||
<button pButton type="submit" [disabled]="form.invalid || saving" [loading]="saving" [label]="'routers.saveRouter' | translate"></button>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Router } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DialogModule } from 'primeng/dialog';
|
||||
import { DropdownModule } from 'primeng/dropdown';
|
||||
import { InputTextareaModule } from 'primeng/inputtextarea';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { TableModule } from 'primeng/table';
|
||||
@@ -15,21 +16,40 @@ import { UiService } from '../../core/services/ui.service';
|
||||
import { PageHeaderComponent } from '../../shared/ui/page-header.component';
|
||||
import { SectionCardComponent } from '../../shared/ui/section-card.component';
|
||||
|
||||
type DeviceType = 'routeros' | 'switchos';
|
||||
|
||||
interface RouterItem {
|
||||
id: number;
|
||||
name: string;
|
||||
host: string;
|
||||
port: number;
|
||||
ssh_user: string;
|
||||
ssh_password?: string;
|
||||
ssh_key?: string;
|
||||
device_type: DeviceType;
|
||||
ssh_user?: string | null;
|
||||
ssh_password?: string | null;
|
||||
ssh_key?: string | null;
|
||||
effective_username?: string | null;
|
||||
uses_global_ssh_key?: boolean;
|
||||
has_effective_ssh_key?: boolean;
|
||||
uses_global_switchos_credentials?: boolean;
|
||||
has_effective_password?: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, ReactiveFormsModule, TranslateModule, ButtonModule, DialogModule, InputTextModule, InputTextareaModule, TableModule, TagModule, PageHeaderComponent, SectionCardComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
TranslateModule,
|
||||
ButtonModule,
|
||||
DialogModule,
|
||||
DropdownModule,
|
||||
InputTextModule,
|
||||
InputTextareaModule,
|
||||
TableModule,
|
||||
TagModule,
|
||||
PageHeaderComponent,
|
||||
SectionCardComponent
|
||||
],
|
||||
templateUrl: './routers-page.component.html'
|
||||
})
|
||||
export class RoutersPageComponent implements OnInit {
|
||||
@@ -42,11 +62,16 @@ export class RoutersPageComponent implements OnInit {
|
||||
editingId: number | null = null;
|
||||
saving = false;
|
||||
routers: RouterItem[] = [];
|
||||
readonly deviceTypeOptions = [
|
||||
{ label: 'RouterOS', value: 'routeros' },
|
||||
{ label: 'SwitchOS', value: 'switchos' }
|
||||
];
|
||||
readonly form = this.fb.nonNullable.group({
|
||||
name: ['', Validators.required],
|
||||
device_type: ['routeros' as DeviceType, Validators.required],
|
||||
host: ['', Validators.required],
|
||||
port: [22, Validators.required],
|
||||
ssh_user: ['admin', Validators.required],
|
||||
ssh_user: ['admin'],
|
||||
ssh_password: '',
|
||||
ssh_key: ''
|
||||
});
|
||||
@@ -55,24 +80,22 @@ export class RoutersPageComponent implements OnInit {
|
||||
return this.ui.instant(this.editingId ? 'routers.editDialogTitle' : 'routers.createDialogTitle');
|
||||
}
|
||||
|
||||
get passwordCount(): number {
|
||||
return this.routers.filter((item) => !!item.ssh_password).length;
|
||||
get selectedDeviceType(): DeviceType {
|
||||
return this.form.controls.device_type.value;
|
||||
}
|
||||
|
||||
get keyCount(): number {
|
||||
return this.routers.filter((item) => this.hasEffectiveSshKey(item)).length;
|
||||
get routerOsCount(): number {
|
||||
return this.routers.filter((item) => item.device_type === 'routeros').length;
|
||||
}
|
||||
|
||||
hasEffectiveSshKey(item: RouterItem): boolean {
|
||||
return !!item.has_effective_ssh_key;
|
||||
get switchOsCount(): number {
|
||||
return this.routers.filter((item) => item.device_type === 'switchos').length;
|
||||
}
|
||||
|
||||
usesGlobalSshKey(item: RouterItem): boolean {
|
||||
return !!item.uses_global_ssh_key;
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.form.controls.device_type.valueChanges.subscribe((deviceType) => {
|
||||
this.applyDeviceDefaults((deviceType || 'routeros') as DeviceType);
|
||||
});
|
||||
this.load();
|
||||
}
|
||||
|
||||
@@ -82,7 +105,7 @@ export class RoutersPageComponent implements OnInit {
|
||||
|
||||
openCreate() {
|
||||
this.editingId = null;
|
||||
this.form.reset({ name: '', host: '', port: 22, ssh_user: 'admin', ssh_password: '', ssh_key: '' });
|
||||
this.form.reset({ name: '', device_type: 'routeros', host: '', port: 22, ssh_user: 'admin', ssh_password: '', ssh_key: '' });
|
||||
this.visible = true;
|
||||
}
|
||||
|
||||
@@ -90,9 +113,10 @@ export class RoutersPageComponent implements OnInit {
|
||||
this.editingId = item.id;
|
||||
this.form.reset({
|
||||
name: item.name,
|
||||
device_type: item.device_type,
|
||||
host: item.host,
|
||||
port: item.port,
|
||||
ssh_user: item.ssh_user,
|
||||
ssh_user: item.ssh_user ?? '',
|
||||
ssh_password: item.ssh_password ?? '',
|
||||
ssh_key: item.ssh_key ?? ''
|
||||
});
|
||||
@@ -104,9 +128,13 @@ export class RoutersPageComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
this.saving = true;
|
||||
const payload = this.form.getRawValue();
|
||||
if (payload.device_type === 'switchos') {
|
||||
payload.ssh_key = '';
|
||||
}
|
||||
const request$ = this.editingId
|
||||
? this.api.http.put(`${this.api.baseUrl}/routers/${this.editingId}`, this.form.getRawValue())
|
||||
: this.api.http.post(`${this.api.baseUrl}/routers`, this.form.getRawValue());
|
||||
? this.api.http.put(`${this.api.baseUrl}/routers/${this.editingId}`, payload)
|
||||
: this.api.http.post(`${this.api.baseUrl}/routers`, payload);
|
||||
|
||||
request$.subscribe({
|
||||
next: () => {
|
||||
@@ -134,8 +162,56 @@ export class RoutersPageComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
open(id: number) {
|
||||
this.router.navigate(['/routers', id]);
|
||||
}
|
||||
|
||||
deviceTypeLabel(item: RouterItem): string {
|
||||
return this.ui.instant(item.device_type === 'switchos' ? 'routers.switchos' : 'routers.routeros');
|
||||
}
|
||||
|
||||
accessUser(item: RouterItem): string {
|
||||
return item.effective_username || item.ssh_user || '—';
|
||||
}
|
||||
|
||||
primaryAccessTag(item: RouterItem): { value: string; severity: 'success' | 'warning' | 'secondary' | 'info' } {
|
||||
if (item.device_type === 'switchos') {
|
||||
if (item.uses_global_switchos_credentials) {
|
||||
return { value: this.ui.instant('routers.defaultCredentials'), severity: 'info' };
|
||||
}
|
||||
if (item.has_effective_password) {
|
||||
return { value: this.ui.instant('routers.localCredentials'), severity: 'success' };
|
||||
}
|
||||
return { value: this.ui.instant('routers.noCredentials'), severity: 'secondary' };
|
||||
}
|
||||
|
||||
return {
|
||||
value: item.ssh_password ? this.ui.instant('routers.passwordMode') : this.ui.instant('routers.noPassword'),
|
||||
severity: item.ssh_password ? 'warning' : 'secondary'
|
||||
};
|
||||
}
|
||||
|
||||
secondaryAccessTag(item: RouterItem): { value: string; severity: 'success' | 'warning' | 'secondary' | 'info' } {
|
||||
if (item.device_type === 'switchos') {
|
||||
return {
|
||||
value: item.has_effective_password ? this.ui.instant('routers.passwordMode') : this.ui.instant('routers.noPassword'),
|
||||
severity: item.has_effective_password ? 'warning' : 'secondary'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: item.has_effective_ssh_key
|
||||
? this.ui.instant(item.uses_global_ssh_key ? 'routers.globalKeyMode' : 'routers.keyMode')
|
||||
: this.ui.instant('routers.noKey'),
|
||||
severity: item.has_effective_ssh_key ? 'success' : 'secondary'
|
||||
};
|
||||
}
|
||||
|
||||
private applyDeviceDefaults(deviceType: DeviceType) {
|
||||
if (deviceType === 'switchos') {
|
||||
this.form.patchValue({ port: 80, ssh_key: '', ssh_user: this.form.controls.ssh_user.value || '' }, { emitEvent: false });
|
||||
return;
|
||||
}
|
||||
this.form.patchValue({ port: 22, ssh_user: this.form.controls.ssh_user.value || 'admin' }, { emitEvent: false });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
</div>
|
||||
|
||||
<div class="settings-page-side">
|
||||
<details class="settings-collapse settings-collapse--sticky">
|
||||
<details class="settings-collapse settings-collapse--sticky" open>
|
||||
<summary>
|
||||
<span>{{ 'settings.sshDefaultsTitle' | translate }}</span>
|
||||
<small>{{ 'settings.sshDefaultsSubtitle' | translate }}</small>
|
||||
@@ -297,6 +297,25 @@
|
||||
|
||||
<small class="settings-ssh-note" *ngIf="clearStoredSshKey">{{ 'settings.sshKeyClearNotice' | translate }}</small>
|
||||
</div>
|
||||
|
||||
<div class="settings-ssh-panel">
|
||||
<div class="settings-ssh-panel__header">
|
||||
<div>
|
||||
<strong>{{ 'settings.switchosDefaultsTitle' | translate }}</strong>
|
||||
<p>{{ 'settings.switchosDefaultsHint' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-grid-2">
|
||||
<span class="form-field">
|
||||
<label>{{ 'settings.defaultSwitchosUsername' | translate }}</label>
|
||||
<input pInputText formControlName="default_switchos_username" placeholder="admin" />
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'settings.defaultSwitchosPassword' | translate }}</label>
|
||||
<input pInputText formControlName="default_switchos_password" placeholder="••••••••" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
@@ -55,6 +55,9 @@ interface SettingsResponse {
|
||||
connection_test_interval_minutes: number;
|
||||
global_ssh_key: string | null;
|
||||
has_global_ssh_key: boolean;
|
||||
default_switchos_username: string | null;
|
||||
default_switchos_password: string | null;
|
||||
has_default_switchos_credentials: boolean;
|
||||
pushover_token: string | null;
|
||||
pushover_userkey: string | null;
|
||||
notify_failures_only: boolean;
|
||||
@@ -104,6 +107,8 @@ export class SettingsPageComponent implements OnInit, OnDestroy {
|
||||
enable_auto_export: false,
|
||||
connection_test_interval_minutes: [0, Validators.min(0)],
|
||||
global_ssh_key: '',
|
||||
default_switchos_username: '',
|
||||
default_switchos_password: '',
|
||||
pushover_token: '',
|
||||
pushover_userkey: '',
|
||||
notify_failures_only: true,
|
||||
@@ -376,6 +381,8 @@ export class SettingsPageComponent implements OnInit, OnDestroy {
|
||||
enable_auto_export: response.enable_auto_export,
|
||||
connection_test_interval_minutes: Number(response.connection_test_interval_minutes || 0),
|
||||
global_ssh_key: '',
|
||||
default_switchos_username: response.default_switchos_username || '',
|
||||
default_switchos_password: response.default_switchos_password || '',
|
||||
pushover_token: response.pushover_token || '',
|
||||
pushover_userkey: response.pushover_userkey || '',
|
||||
notify_failures_only: response.notify_failures_only,
|
||||
@@ -404,6 +411,8 @@ export class SettingsPageComponent implements OnInit, OnDestroy {
|
||||
enable_auto_export: Boolean(raw.enable_auto_export),
|
||||
connection_test_interval_minutes: Number(raw.connection_test_interval_minutes || 0),
|
||||
global_ssh_key: normalizedKey || null,
|
||||
default_switchos_username: this.normalizeOptionalText(raw.default_switchos_username),
|
||||
default_switchos_password: this.normalizeOptionalText(raw.default_switchos_password),
|
||||
pushover_token: this.normalizeOptionalText(raw.pushover_token),
|
||||
pushover_userkey: this.normalizeOptionalText(raw.pushover_userkey),
|
||||
notify_failures_only: Boolean(raw.notify_failures_only),
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashboard",
|
||||
"routers": "Routers",
|
||||
"routers": "Devices",
|
||||
"files": "Repository",
|
||||
"settings": "Settings",
|
||||
"logs": "Logs",
|
||||
@@ -81,7 +81,7 @@
|
||||
"subtitle": "Overview of backups, exports and operational activity in one place.",
|
||||
"exportAll": "Export all",
|
||||
"binaryAll": "Binary backup",
|
||||
"managedRouters": "Routers",
|
||||
"managedRouters": "Devices",
|
||||
"managedRoutersHint": "All managed devices",
|
||||
"inventoryTag": "Fleet",
|
||||
"exportsCard": "Exports",
|
||||
@@ -134,14 +134,14 @@
|
||||
"storageSnapshotHint": "Quick snapshot of the most important storage and backup indicators."
|
||||
},
|
||||
"routers": {
|
||||
"title": "Routers",
|
||||
"detailTitle": "Router details",
|
||||
"add": "Add router",
|
||||
"title": "Devices",
|
||||
"detailTitle": "Device details",
|
||||
"add": "Add device",
|
||||
"eyebrow": "device inventory",
|
||||
"subtitle": "Manage RouterOS endpoints, credentials and fleet-wide backup jobs.",
|
||||
"subtitle": "Manage RouterOS and SwitchOS devices plus their backups.",
|
||||
"registeredDevices": "Registered devices",
|
||||
"fleetTag": "Fleet",
|
||||
"sshPassword": "SSH password",
|
||||
"sshPassword": "Password",
|
||||
"passwordHint": "Password-based access",
|
||||
"credsTag": "Creds",
|
||||
"sshKey": "SSH key",
|
||||
@@ -150,8 +150,8 @@
|
||||
"defaultPort": "Port 22",
|
||||
"defaultPortHint": "Standard SSH endpoints",
|
||||
"portTag": "Port",
|
||||
"listTitle": "Router list",
|
||||
"listSubtitle": "Compact operational view of every managed device.",
|
||||
"listTitle": "Device list",
|
||||
"listSubtitle": "Unified view for RouterOS and SwitchOS devices.",
|
||||
"name": "Name",
|
||||
"endpoint": "Endpoint",
|
||||
"access": "Access",
|
||||
@@ -161,15 +161,15 @@
|
||||
"keyMode": "Key",
|
||||
"globalKeyMode": "Global key",
|
||||
"noKey": "No key",
|
||||
"createDialogTitle": "Add router",
|
||||
"editDialogTitle": "Edit router",
|
||||
"createDialogTitle": "Add device",
|
||||
"editDialogTitle": "Edit device",
|
||||
"host": "Host",
|
||||
"port": "Port",
|
||||
"sshUser": "SSH user",
|
||||
"sshUser": "Username",
|
||||
"sshPrivateKey": "SSH private key",
|
||||
"optionalPassword": "Optional password",
|
||||
"optionalPrivateKey": "Optional private key",
|
||||
"saveRouter": "Save router",
|
||||
"saveRouter": "Save device",
|
||||
"profileEyebrow": "router profile",
|
||||
"detailSubtitle": "Device operations and backup history",
|
||||
"exportOne": "Export",
|
||||
@@ -184,7 +184,7 @@
|
||||
"connectionLabelHint": "Status from the latest automatic or manual connection test",
|
||||
"probeTag": "Probe",
|
||||
"accessTag": "Access",
|
||||
"sshUserHint": "Current SSH user",
|
||||
"sshUserHint": "Effective device login",
|
||||
"deviceStatusTitle": "Device status",
|
||||
"deviceStatusSubtitle": "Stored metadata from the latest automatic or manual connection test.",
|
||||
"hostname": "Hostname",
|
||||
@@ -200,7 +200,7 @@
|
||||
"exportsTableTitle": "Exports",
|
||||
"exportsTableSubtitle": "Readable RouterOS snapshots.",
|
||||
"binaryTableTitle": "Binary backups",
|
||||
"binaryTableSubtitle": "Files ready for device restore.",
|
||||
"binaryTableSubtitle": "Binary files and SwitchOS backups.",
|
||||
"summaryKeyAccess": "with key-based access",
|
||||
"summaryPasswordAccess": "with password access",
|
||||
"connectionStateTitle": "Connection state",
|
||||
@@ -211,7 +211,28 @@
|
||||
"openPreviewModal": "Open preview",
|
||||
"diffModalHint": "The last loaded diff is available in a modal.",
|
||||
"openDiffModal": "Open diff",
|
||||
"noDiff": "Choose an export and run a diff to see the latest comparison."
|
||||
"noDiff": "Choose an export and run a diff to see the latest comparison.",
|
||||
"routeros": "RouterOS",
|
||||
"switchos": "SwitchOS",
|
||||
"deviceType": "Device type",
|
||||
"defaultCredentials": "Default credentials",
|
||||
"localCredentials": "Local credentials",
|
||||
"noCredentials": "No credentials",
|
||||
"switchUserPlaceholder": "Empty = use settings default",
|
||||
"switchPasswordPlaceholder": "Empty = use settings default",
|
||||
"switchDefaultsHint": "For SwitchOS you can leave username and password empty to use the defaults from settings.",
|
||||
"downloadSwitchBackup": "Download backup",
|
||||
"httpStatus": "HTTP status",
|
||||
"serverHeader": "Server header",
|
||||
"authMode": "Auth mode",
|
||||
"backupEndpoint": "Backup endpoint",
|
||||
"backupAvailable": "Available",
|
||||
"backupUnavailable": "Unavailable",
|
||||
"connectionSectionTitle": "Connection profile",
|
||||
"connectionSectionHint": "Basic device identity and endpoint used to reach it.",
|
||||
"credentialsSectionTitle": "Access and credentials",
|
||||
"routerDialogSubtitle": "Set the device endpoint, SSH access data and your preferred login method.",
|
||||
"switchDialogSubtitle": "Set the SwitchOS endpoint and optional local or shared credentials from settings."
|
||||
},
|
||||
"files": {
|
||||
"title": "Repository",
|
||||
@@ -233,14 +254,14 @@
|
||||
"searchLabel": "Search",
|
||||
"searchPlaceholder": "Search by file or router",
|
||||
"typeLabel": "Type",
|
||||
"routerLabel": "Router",
|
||||
"routerLabel": "Device",
|
||||
"sortLabel": "Sort by",
|
||||
"orderLabel": "Order",
|
||||
"allTypes": "All types",
|
||||
"allRouters": "All routers",
|
||||
"allRouters": "All devices",
|
||||
"sortNewest": "Newest",
|
||||
"sortName": "Name",
|
||||
"sortRouter": "Router",
|
||||
"sortRouter": "Device",
|
||||
"sortType": "Type",
|
||||
"tableTitle": "Repository table",
|
||||
"tableSubtitle": "Artifacts available for download, e-mail and restore.",
|
||||
@@ -248,7 +269,7 @@
|
||||
"compareSelected": "Compare selected exports",
|
||||
"fileColumn": "File",
|
||||
"typeColumn": "Type",
|
||||
"routerColumn": "Router",
|
||||
"routerColumn": "Device",
|
||||
"createdColumn": "Created",
|
||||
"actionsColumn": "Actions",
|
||||
"checksum": "Checksum",
|
||||
@@ -311,8 +332,8 @@
|
||||
"pushoverUserKey": "Pushover user key",
|
||||
"pushoverTokenPlaceholder": "Application token",
|
||||
"pushoverUserKeyPlaceholder": "User key",
|
||||
"sshDefaultsTitle": "SSH defaults",
|
||||
"sshDefaultsSubtitle": "Optional shared private key used across managed routers.",
|
||||
"sshDefaultsTitle": "Default Credentials",
|
||||
"sshDefaultsSubtitle": "Shared SSH key and default SwitchOS login used across managed devices.",
|
||||
"globalSshPrivateKey": "Global SSH private key",
|
||||
"globalSshPrivateKeyPlaceholder": "Paste PEM or OpenSSH private key",
|
||||
"save": "Save settings",
|
||||
@@ -377,7 +398,11 @@
|
||||
"interfacePreferencesHint": "Choose the default language and font family for the whole application.",
|
||||
"interfacePreferencesTag": "Per-user",
|
||||
"fontFamily": "Font family",
|
||||
"fontDefault": "Default"
|
||||
"fontDefault": "Default",
|
||||
"switchosDefaultsTitle": "Default SwitchOS credentials",
|
||||
"switchosDefaultsHint": "Used when a SwitchOS device has no local username or password.",
|
||||
"defaultSwitchosUsername": "Default SwitchOS username",
|
||||
"defaultSwitchosPassword": "Default SwitchOS password"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Logs",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Panel",
|
||||
"routers": "Routers",
|
||||
"routers": "Dispositivos",
|
||||
"files": "Repositorio",
|
||||
"settings": "Ajustes",
|
||||
"logs": "Registros",
|
||||
@@ -81,7 +81,7 @@
|
||||
"subtitle": "Resumen de copias, exportaciones y actividad operativa en un solo lugar.",
|
||||
"exportAll": "Exportar todo",
|
||||
"binaryAll": "Copia binaria",
|
||||
"managedRouters": "Routers",
|
||||
"managedRouters": "Dispositivos",
|
||||
"managedRoutersHint": "Todos los dispositivos gestionados",
|
||||
"inventoryTag": "Flota",
|
||||
"exportsCard": "Exportaciones",
|
||||
@@ -134,14 +134,14 @@
|
||||
"storageSnapshotHint": "Vista rápida de los indicadores más importantes de almacenamiento y copias."
|
||||
},
|
||||
"routers": {
|
||||
"title": "Routers",
|
||||
"detailTitle": "Detalles del router",
|
||||
"add": "Añadir router",
|
||||
"title": "Dispositivos",
|
||||
"detailTitle": "Detalles del dispositivo",
|
||||
"add": "Agregar dispositivo",
|
||||
"eyebrow": "inventario de dispositivos",
|
||||
"subtitle": "Gestiona endpoints de RouterOS, credenciales y tareas de copia para toda la flota.",
|
||||
"subtitle": "Administra dispositivos RouterOS y SwitchOS y sus copias.",
|
||||
"registeredDevices": "Dispositivos registrados",
|
||||
"fleetTag": "Flota",
|
||||
"sshPassword": "Contraseña SSH",
|
||||
"sshPassword": "Contraseña",
|
||||
"passwordHint": "Acceso con contraseña",
|
||||
"credsTag": "Credenciales",
|
||||
"sshKey": "Clave SSH",
|
||||
@@ -150,8 +150,8 @@
|
||||
"defaultPort": "Puerto 22",
|
||||
"defaultPortHint": "Endpoints SSH estándar",
|
||||
"portTag": "Puerto",
|
||||
"listTitle": "Lista de routers",
|
||||
"listSubtitle": "Vista operativa compacta de todos los dispositivos gestionados.",
|
||||
"listTitle": "Lista de dispositivos",
|
||||
"listSubtitle": "Vista unificada para RouterOS y SwitchOS.",
|
||||
"name": "Nombre",
|
||||
"endpoint": "Endpoint",
|
||||
"access": "Acceso",
|
||||
@@ -161,15 +161,15 @@
|
||||
"keyMode": "Clave",
|
||||
"globalKeyMode": "Clave global",
|
||||
"noKey": "Sin clave",
|
||||
"createDialogTitle": "Añadir router",
|
||||
"editDialogTitle": "Editar router",
|
||||
"createDialogTitle": "Agregar dispositivo",
|
||||
"editDialogTitle": "Editar dispositivo",
|
||||
"host": "Host",
|
||||
"port": "Puerto",
|
||||
"sshUser": "Usuario SSH",
|
||||
"sshUser": "Usuario",
|
||||
"sshPrivateKey": "Clave privada SSH",
|
||||
"optionalPassword": "Contraseña opcional",
|
||||
"optionalPrivateKey": "Clave privada opcional",
|
||||
"saveRouter": "Guardar router",
|
||||
"saveRouter": "Guardar dispositivo",
|
||||
"profileEyebrow": "perfil del router",
|
||||
"detailSubtitle": "Operaciones del dispositivo e historial de copias",
|
||||
"exportOne": "Exportar",
|
||||
@@ -211,7 +211,28 @@
|
||||
"openPreviewModal": "Abrir vista previa",
|
||||
"diffModalHint": "El último diff cargado está disponible en un modal.",
|
||||
"openDiffModal": "Abrir diff",
|
||||
"noDiff": "Elige una exportación y ejecuta un diff para ver la última comparación."
|
||||
"noDiff": "Elige una exportación y ejecuta un diff para ver la última comparación.",
|
||||
"routeros": "RouterOS",
|
||||
"switchos": "SwitchOS",
|
||||
"deviceType": "Tipo de dispositivo",
|
||||
"defaultCredentials": "Credenciales por defecto",
|
||||
"localCredentials": "Credenciales locales",
|
||||
"noCredentials": "Sin credenciales",
|
||||
"switchUserPlaceholder": "Vacío = usar ajustes",
|
||||
"switchPasswordPlaceholder": "Vacío = usar ajustes",
|
||||
"switchDefaultsHint": "Para SwitchOS puedes dejar usuario y contraseña vacíos para usar los valores por defecto.",
|
||||
"downloadSwitchBackup": "Descargar copia",
|
||||
"httpStatus": "Estado HTTP",
|
||||
"serverHeader": "Cabecera Server",
|
||||
"authMode": "Modo de autenticación",
|
||||
"backupEndpoint": "Endpoint de copia",
|
||||
"backupAvailable": "Disponible",
|
||||
"backupUnavailable": "No disponible",
|
||||
"connectionSectionTitle": "Perfil de conexión",
|
||||
"connectionSectionHint": "Identidad básica del dispositivo y endpoint usado para alcanzarlo.",
|
||||
"credentialsSectionTitle": "Acceso y credenciales",
|
||||
"routerDialogSubtitle": "Configura el endpoint del dispositivo, los datos SSH y el método de acceso preferido.",
|
||||
"switchDialogSubtitle": "Configura el endpoint de SwitchOS y las credenciales locales u opcionales compartidas desde ajustes."
|
||||
},
|
||||
"files": {
|
||||
"title": "Repositorio",
|
||||
@@ -233,14 +254,14 @@
|
||||
"searchLabel": "Buscar",
|
||||
"searchPlaceholder": "Buscar por archivo o router",
|
||||
"typeLabel": "Tipo",
|
||||
"routerLabel": "Router",
|
||||
"routerLabel": "Dispositivo",
|
||||
"sortLabel": "Ordenar por",
|
||||
"orderLabel": "Orden",
|
||||
"allTypes": "Todos los tipos",
|
||||
"allRouters": "Todos los routers",
|
||||
"allRouters": "Todos los dispositivos",
|
||||
"sortNewest": "Más nuevo",
|
||||
"sortName": "Nombre",
|
||||
"sortRouter": "Router",
|
||||
"sortRouter": "Dispositivo",
|
||||
"sortType": "Tipo",
|
||||
"tableTitle": "Tabla del repositorio",
|
||||
"tableSubtitle": "Artefactos disponibles para descarga, correo y restauración.",
|
||||
@@ -248,7 +269,7 @@
|
||||
"compareSelected": "Comparar exportaciones seleccionadas",
|
||||
"fileColumn": "Archivo",
|
||||
"typeColumn": "Tipo",
|
||||
"routerColumn": "Router",
|
||||
"routerColumn": "Dispositivo",
|
||||
"createdColumn": "Creado",
|
||||
"actionsColumn": "Acciones",
|
||||
"checksum": "Checksum",
|
||||
@@ -311,8 +332,8 @@
|
||||
"pushoverUserKey": "Clave de usuario de Pushover",
|
||||
"pushoverTokenPlaceholder": "Token de la aplicación",
|
||||
"pushoverUserKeyPlaceholder": "Clave de usuario",
|
||||
"sshDefaultsTitle": "Valores SSH por defecto",
|
||||
"sshDefaultsSubtitle": "Clave privada compartida opcional usada en todos los routers gestionados.",
|
||||
"sshDefaultsTitle": "Credenciales predeterminadas",
|
||||
"sshDefaultsSubtitle": "Clave SSH compartida y acceso por defecto de SwitchOS usados por los dispositivos gestionados.",
|
||||
"globalSshPrivateKey": "Clave privada SSH global",
|
||||
"globalSshPrivateKeyPlaceholder": "Pega la clave privada PEM u OpenSSH",
|
||||
"globalSshPrivateKeyHiddenPlaceholder": "La clave guardada está oculta. Introduce la contraseña arriba para verla o pega aquí una nueva clave para reemplazarla.",
|
||||
@@ -377,7 +398,11 @@
|
||||
"interfacePreferencesHint": "Elige el idioma predeterminado y la familia tipográfica para toda la aplicación.",
|
||||
"interfacePreferencesTag": "Por usuario",
|
||||
"fontFamily": "Familia tipográfica",
|
||||
"fontDefault": "Predeterminada"
|
||||
"fontDefault": "Predeterminada",
|
||||
"switchosDefaultsTitle": "Credenciales por defecto de SwitchOS",
|
||||
"switchosDefaultsHint": "Se usan cuando un dispositivo SwitchOS no tiene usuario o contraseña local.",
|
||||
"defaultSwitchosUsername": "Usuario SwitchOS por defecto",
|
||||
"defaultSwitchosPassword": "Contraseña SwitchOS por defecto"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Registros",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashbord",
|
||||
"routers": "Rutere",
|
||||
"routers": "Enheter",
|
||||
"files": "Repository",
|
||||
"settings": "Innstillinger",
|
||||
"logs": "Logger",
|
||||
@@ -81,7 +81,7 @@
|
||||
"subtitle": "Oversikt over backuper, eksportfiler og operativ aktivitet på ett sted.",
|
||||
"exportAll": "Eksporter alle",
|
||||
"binaryAll": "Binær backup",
|
||||
"managedRouters": "Rutere",
|
||||
"managedRouters": "Enheter",
|
||||
"managedRoutersHint": "Alle administrerte enheter",
|
||||
"inventoryTag": "Flåte",
|
||||
"exportsCard": "Eksporter",
|
||||
@@ -134,14 +134,14 @@
|
||||
"storageSnapshotHint": "Rask oversikt over de viktigste lagrings- og backupindikatorene."
|
||||
},
|
||||
"routers": {
|
||||
"title": "Rutere",
|
||||
"detailTitle": "Ruterdetaljer",
|
||||
"add": "Legg til ruter",
|
||||
"title": "Enheter",
|
||||
"detailTitle": "Enhetsdetaljer",
|
||||
"add": "Legg til enhet",
|
||||
"eyebrow": "enhetsinventar",
|
||||
"subtitle": "Administrer RouterOS-endepunkter, legitimasjon og backupjobber for hele flåten.",
|
||||
"subtitle": "Administrer RouterOS- og SwitchOS-enheter og sikkerhetskopier.",
|
||||
"registeredDevices": "Registrerte enheter",
|
||||
"fleetTag": "Flåte",
|
||||
"sshPassword": "SSH-passord",
|
||||
"sshPassword": "Passord",
|
||||
"passwordHint": "Passordbasert tilgang",
|
||||
"credsTag": "Tilgang",
|
||||
"sshKey": "SSH-nøkkel",
|
||||
@@ -150,8 +150,8 @@
|
||||
"defaultPort": "Port 22",
|
||||
"defaultPortHint": "Standard SSH-endepunkter",
|
||||
"portTag": "Port",
|
||||
"listTitle": "Ruterliste",
|
||||
"listSubtitle": "Kompakt driftsvisning av alle administrerte enheter.",
|
||||
"listTitle": "Enhetsliste",
|
||||
"listSubtitle": "Felles visning for RouterOS og SwitchOS.",
|
||||
"name": "Navn",
|
||||
"endpoint": "Endepunkt",
|
||||
"access": "Tilgang",
|
||||
@@ -161,15 +161,15 @@
|
||||
"keyMode": "Nøkkel",
|
||||
"globalKeyMode": "Global nøkkel",
|
||||
"noKey": "Ingen nøkkel",
|
||||
"createDialogTitle": "Legg til ruter",
|
||||
"editDialogTitle": "Rediger ruter",
|
||||
"createDialogTitle": "Legg til enhet",
|
||||
"editDialogTitle": "Rediger enhet",
|
||||
"host": "Vert",
|
||||
"port": "Port",
|
||||
"sshUser": "SSH-bruker",
|
||||
"sshUser": "Bruker",
|
||||
"sshPrivateKey": "SSH privat nøkkel",
|
||||
"optionalPassword": "Valgfritt passord",
|
||||
"optionalPrivateKey": "Valgfri privat nøkkel",
|
||||
"saveRouter": "Lagre ruter",
|
||||
"saveRouter": "Lagre enhet",
|
||||
"profileEyebrow": "ruterprofil",
|
||||
"detailSubtitle": "Enhetsoperasjoner og backuphistorikk",
|
||||
"exportOne": "Eksport",
|
||||
@@ -211,7 +211,28 @@
|
||||
"openPreviewModal": "Åpne forhåndsvisning",
|
||||
"diffModalHint": "Sist lastede diff er tilgjengelig i en modal.",
|
||||
"openDiffModal": "Åpne diff",
|
||||
"noDiff": "Velg en eksport og kjør diff for å se siste sammenligning."
|
||||
"noDiff": "Velg en eksport og kjør diff for å se siste sammenligning.",
|
||||
"routeros": "RouterOS",
|
||||
"switchos": "SwitchOS",
|
||||
"deviceType": "Enhetstype",
|
||||
"defaultCredentials": "Standard legitimasjon",
|
||||
"localCredentials": "Lokal legitimasjon",
|
||||
"noCredentials": "Ingen legitimasjon",
|
||||
"switchUserPlaceholder": "Tom = bruk innstillinger",
|
||||
"switchPasswordPlaceholder": "Tom = bruk innstillinger",
|
||||
"switchDefaultsHint": "For SwitchOS kan du la bruker og passord være tomme for å bruke standardverdier fra innstillinger.",
|
||||
"downloadSwitchBackup": "Last ned backup",
|
||||
"httpStatus": "HTTP-status",
|
||||
"serverHeader": "Server-header",
|
||||
"authMode": "Autentiseringsmodus",
|
||||
"backupEndpoint": "Backup-endepunkt",
|
||||
"backupAvailable": "Tilgjengelig",
|
||||
"backupUnavailable": "Utilgjengelig",
|
||||
"connectionSectionTitle": "Tilkoblingsprofil",
|
||||
"connectionSectionHint": "Grunnleggende enhetsidentitet og endpoint som brukes for å nå den.",
|
||||
"credentialsSectionTitle": "Tilgang og legitimasjon",
|
||||
"routerDialogSubtitle": "Sett enhetens endpoint, SSH-data og foretrukket innloggingsmetode.",
|
||||
"switchDialogSubtitle": "Sett SwitchOS-endpoint og valgfrie lokale eller delte standarddata fra innstillinger."
|
||||
},
|
||||
"files": {
|
||||
"title": "Repository",
|
||||
@@ -233,14 +254,14 @@
|
||||
"searchLabel": "Søk",
|
||||
"searchPlaceholder": "Søk etter fil eller ruter",
|
||||
"typeLabel": "Type",
|
||||
"routerLabel": "Ruter",
|
||||
"routerLabel": "Enhet",
|
||||
"sortLabel": "Sorter etter",
|
||||
"orderLabel": "Rekkefølge",
|
||||
"allTypes": "Alle typer",
|
||||
"allRouters": "Alle rutere",
|
||||
"allRouters": "Alle enheter",
|
||||
"sortNewest": "Nyeste",
|
||||
"sortName": "Navn",
|
||||
"sortRouter": "Ruter",
|
||||
"sortRouter": "Enhet",
|
||||
"sortType": "Type",
|
||||
"tableTitle": "Repositorytabell",
|
||||
"tableSubtitle": "Artefakter tilgjengelige for nedlasting, e-post og gjenoppretting.",
|
||||
@@ -248,7 +269,7 @@
|
||||
"compareSelected": "Sammenlign valgte eksporter",
|
||||
"fileColumn": "Fil",
|
||||
"typeColumn": "Type",
|
||||
"routerColumn": "Ruter",
|
||||
"routerColumn": "Enhet",
|
||||
"createdColumn": "Opprettet",
|
||||
"actionsColumn": "Handlinger",
|
||||
"checksum": "Checksum",
|
||||
@@ -311,8 +332,8 @@
|
||||
"pushoverUserKey": "Pushover-brukernøkkel",
|
||||
"pushoverTokenPlaceholder": "Applikasjonstoken",
|
||||
"pushoverUserKeyPlaceholder": "Brukernøkkel",
|
||||
"sshDefaultsTitle": "SSH-standarder",
|
||||
"sshDefaultsSubtitle": "Valgfri delt privat nøkkel som brukes på tvers av administrerte rutere.",
|
||||
"sshDefaultsTitle": "Standard legitimasjon",
|
||||
"sshDefaultsSubtitle": "Delt SSH-nøkkel og standard innlogging for SwitchOS brukt på administrerte enheter.",
|
||||
"globalSshPrivateKey": "Global SSH privat nøkkel",
|
||||
"globalSshPrivateKeyPlaceholder": "Lim inn PEM- eller OpenSSH-privat nøkkel",
|
||||
"globalSshPrivateKeyHiddenPlaceholder": "Den lagrede nøkkelen er skjult. Skriv inn passordet over for å se den, eller lim inn en ny nøkkel her for å erstatte den.",
|
||||
@@ -377,7 +398,11 @@
|
||||
"interfacePreferencesHint": "Velg standardspråk og skriftfamilie for hele applikasjonen.",
|
||||
"interfacePreferencesTag": "Per bruker",
|
||||
"fontFamily": "Skriftfamilie",
|
||||
"fontDefault": "Standard"
|
||||
"fontDefault": "Standard",
|
||||
"switchosDefaultsTitle": "Standard SwitchOS-legitimasjon",
|
||||
"switchosDefaultsHint": "Brukes når en SwitchOS-enhet ikke har lokalt brukernavn eller passord.",
|
||||
"defaultSwitchosUsername": "Standard SwitchOS-bruker",
|
||||
"defaultSwitchosPassword": "Standard SwitchOS-passord"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Logger",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashboard",
|
||||
"routers": "Routery",
|
||||
"routers": "Urządzenia",
|
||||
"files": "Repozytorium",
|
||||
"settings": "Ustawienia",
|
||||
"logs": "Logi",
|
||||
@@ -81,7 +81,7 @@
|
||||
"subtitle": "Przegląd backupów, eksportów i aktywności operacyjnej w jednym miejscu.",
|
||||
"exportAll": "Eksportuj wszystko",
|
||||
"binaryAll": "Backup binarny",
|
||||
"managedRouters": "Routery",
|
||||
"managedRouters": "Urządzenia",
|
||||
"managedRoutersHint": "Wszystkie zarządzane urządzenia",
|
||||
"inventoryTag": "Flota",
|
||||
"exportsCard": "Eksporty",
|
||||
@@ -134,14 +134,14 @@
|
||||
"storageSnapshotHint": "Szybki podgląd najważniejszych wskaźników przestrzeni i backupów."
|
||||
},
|
||||
"routers": {
|
||||
"title": "Routery",
|
||||
"detailTitle": "Szczegóły routera",
|
||||
"add": "Dodaj router",
|
||||
"title": "Urządzenia",
|
||||
"detailTitle": "Szczegóły urządzenia",
|
||||
"add": "Dodaj urządzenie",
|
||||
"eyebrow": "inwentaryzacja urządzeń",
|
||||
"subtitle": "Zarządzaj endpointami RouterOS, poświadczeniami i zadaniami backupu dla całej floty.",
|
||||
"subtitle": "Zarządzaj urządzeniami RouterOS i SwitchOS oraz ich kopiami.",
|
||||
"registeredDevices": "Zarejestrowane urządzenia",
|
||||
"fleetTag": "Flota",
|
||||
"sshPassword": "Hasło SSH",
|
||||
"sshPassword": "Hasło",
|
||||
"passwordHint": "Dostęp hasłem",
|
||||
"credsTag": "Dostęp",
|
||||
"sshKey": "Klucz SSH",
|
||||
@@ -150,8 +150,8 @@
|
||||
"defaultPort": "Port 22",
|
||||
"defaultPortHint": "Standardowe endpointy SSH",
|
||||
"portTag": "Port",
|
||||
"listTitle": "Lista routerów",
|
||||
"listSubtitle": "Zwięzły widok operacyjny wszystkich zarządzanych urządzeń.",
|
||||
"listTitle": "Lista urządzeń",
|
||||
"listSubtitle": "Wspólny widok RouterOS i SwitchOS.",
|
||||
"name": "Nazwa",
|
||||
"endpoint": "Endpoint",
|
||||
"access": "Dostęp",
|
||||
@@ -161,15 +161,15 @@
|
||||
"keyMode": "Klucz",
|
||||
"globalKeyMode": "Klucz globalny",
|
||||
"noKey": "Bez klucza",
|
||||
"createDialogTitle": "Dodaj router",
|
||||
"editDialogTitle": "Edytuj router",
|
||||
"createDialogTitle": "Dodaj urządzenie",
|
||||
"editDialogTitle": "Edytuj urządzenie",
|
||||
"host": "Host",
|
||||
"port": "Port",
|
||||
"sshUser": "Użytkownik SSH",
|
||||
"sshUser": "Użytkownik",
|
||||
"sshPrivateKey": "Klucz prywatny SSH",
|
||||
"optionalPassword": "Opcjonalne hasło",
|
||||
"optionalPrivateKey": "Opcjonalny klucz prywatny",
|
||||
"saveRouter": "Zapisz router",
|
||||
"saveRouter": "Zapisz urządzenie",
|
||||
"profileEyebrow": "profil routera",
|
||||
"detailSubtitle": "Operacje urządzenia i historia backupów",
|
||||
"exportOne": "Eksport",
|
||||
@@ -184,7 +184,7 @@
|
||||
"connectionLabelHint": "Status z ostatniego automatycznego lub ręcznego testu połączenia",
|
||||
"probeTag": "Test",
|
||||
"accessTag": "Dostęp",
|
||||
"sshUserHint": "Bieżący użytkownik SSH",
|
||||
"sshUserHint": "Efektywny login urządzenia",
|
||||
"deviceStatusTitle": "Status urządzenia",
|
||||
"deviceStatusSubtitle": "Zapisane metadane z ostatniego automatycznego lub ręcznego testu połączenia.",
|
||||
"hostname": "Hostname",
|
||||
@@ -200,7 +200,7 @@
|
||||
"exportsTableTitle": "Eksporty",
|
||||
"exportsTableSubtitle": "Czytelne snapshoty RouterOS.",
|
||||
"binaryTableTitle": "Backupy binarne",
|
||||
"binaryTableSubtitle": "Pliki do odtworzenia urządzenia.",
|
||||
"binaryTableSubtitle": "Pliki binarne i kopie SwitchOS.",
|
||||
"summaryKeyAccess": "z dostępem kluczem",
|
||||
"summaryPasswordAccess": "z dostępem hasłem",
|
||||
"connectionStateTitle": "Stan połączenia",
|
||||
@@ -211,7 +211,28 @@
|
||||
"openPreviewModal": "Otwórz podgląd",
|
||||
"diffModalHint": "Ostatnio załadowany diff jest dostępny w modalu.",
|
||||
"openDiffModal": "Otwórz diff",
|
||||
"noDiff": "Wybierz eksport i uruchom diff, aby zobaczyć ostatnie porównanie."
|
||||
"noDiff": "Wybierz eksport i uruchom diff, aby zobaczyć ostatnie porównanie.",
|
||||
"routeros": "RouterOS",
|
||||
"switchos": "SwitchOS",
|
||||
"deviceType": "Typ urządzenia",
|
||||
"defaultCredentials": "Domyślne dane",
|
||||
"localCredentials": "Lokalne dane",
|
||||
"noCredentials": "Brak danych",
|
||||
"switchUserPlaceholder": "Puste = z ustawień",
|
||||
"switchPasswordPlaceholder": "Puste = z ustawień",
|
||||
"switchDefaultsHint": "Dla SwitchOS możesz zostawić użytkownika i hasło puste, aby użyć wartości domyślnych z ustawień.",
|
||||
"downloadSwitchBackup": "Pobierz backup",
|
||||
"httpStatus": "Status HTTP",
|
||||
"serverHeader": "Nagłówek Server",
|
||||
"authMode": "Tryb autoryzacji",
|
||||
"backupEndpoint": "Endpoint backupu",
|
||||
"backupAvailable": "Dostępny",
|
||||
"backupUnavailable": "Niedostępny",
|
||||
"connectionSectionTitle": "Profil połączenia",
|
||||
"connectionSectionHint": "Podstawowa tożsamość urządzenia i endpoint używany do połączenia.",
|
||||
"credentialsSectionTitle": "Dostęp i poświadczenia",
|
||||
"routerDialogSubtitle": "Ustaw adres urządzenia, dane dostępu SSH i preferowaną metodę logowania.",
|
||||
"switchDialogSubtitle": "Ustaw endpoint SwitchOS i opcjonalne poświadczenia lokalne lub domyślne z ustawień."
|
||||
},
|
||||
"files": {
|
||||
"title": "Repozytorium",
|
||||
@@ -233,14 +254,14 @@
|
||||
"searchLabel": "Szukaj",
|
||||
"searchPlaceholder": "Szukaj po pliku lub routerze",
|
||||
"typeLabel": "Typ",
|
||||
"routerLabel": "Router",
|
||||
"routerLabel": "Urządzenie",
|
||||
"sortLabel": "Sortowanie",
|
||||
"orderLabel": "Kolejność",
|
||||
"allTypes": "Wszystkie typy",
|
||||
"allRouters": "Wszystkie routery",
|
||||
"allRouters": "Wszystkie urządzenia",
|
||||
"sortNewest": "Najnowsze",
|
||||
"sortName": "Nazwa",
|
||||
"sortRouter": "Router",
|
||||
"sortRouter": "Urządzenie",
|
||||
"sortType": "Typ",
|
||||
"tableTitle": "Tabela repozytorium",
|
||||
"tableSubtitle": "Artefakty dostępne do pobrania, wysyłki e-mail i przywracania.",
|
||||
@@ -248,7 +269,7 @@
|
||||
"compareSelected": "Porównaj zaznaczone eksporty",
|
||||
"fileColumn": "Plik",
|
||||
"typeColumn": "Typ",
|
||||
"routerColumn": "Router",
|
||||
"routerColumn": "Urządzenie",
|
||||
"createdColumn": "Utworzono",
|
||||
"actionsColumn": "Akcje",
|
||||
"checksum": "Checksum",
|
||||
@@ -311,8 +332,8 @@
|
||||
"pushoverUserKey": "Klucz użytkownika Pushover",
|
||||
"pushoverTokenPlaceholder": "Token aplikacji",
|
||||
"pushoverUserKeyPlaceholder": "Klucz użytkownika",
|
||||
"sshDefaultsTitle": "Domyślne SSH",
|
||||
"sshDefaultsSubtitle": "Opcjonalny współdzielony klucz prywatny używany przez zarządzane routery.",
|
||||
"sshDefaultsTitle": "Domyślne Poświadczenia",
|
||||
"sshDefaultsSubtitle": "Wspólny klucz SSH oraz domyślne logowanie SwitchOS używane przez urządzenia.",
|
||||
"globalSshPrivateKey": "Globalny klucz prywatny SSH",
|
||||
"globalSshPrivateKeyPlaceholder": "Wklej klucz prywatny PEM lub OpenSSH",
|
||||
"save": "Zapisz ustawienia",
|
||||
@@ -377,7 +398,11 @@
|
||||
"interfacePreferencesHint": "Wybierz domyślny język i rodzinę fontów dla całej aplikacji.",
|
||||
"interfacePreferencesTag": "Per-user",
|
||||
"fontFamily": "Rodzina fontów",
|
||||
"fontDefault": "Domyślna"
|
||||
"fontDefault": "Domyślna",
|
||||
"switchosDefaultsTitle": "Domyślne dane SwitchOS",
|
||||
"switchosDefaultsHint": "Używane, gdy urządzenie SwitchOS nie ma własnego loginu lub hasła.",
|
||||
"defaultSwitchosUsername": "Domyślny użytkownik SwitchOS",
|
||||
"defaultSwitchosPassword": "Domyślne hasło SwitchOS"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Logi",
|
||||
|
||||
@@ -3389,3 +3389,198 @@ body.dark-theme .p-confirm-dialog .p-confirm-dialog-icon{
|
||||
@media (max-width: 991px) {
|
||||
|
||||
}
|
||||
|
||||
.router-dialog .p-dialog-header{
|
||||
padding: 1.15rem 1.2rem 1rem;
|
||||
align-items: flex-start;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(75, 144, 217, 0.16), rgba(79, 181, 147, 0.1)),
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0)),
|
||||
var(--surface-1);
|
||||
border-bottom: 1px solid rgba(75, 144, 217, 0.18);
|
||||
}
|
||||
|
||||
.router-dialog .p-dialog-header-icons{
|
||||
align-self: flex-start;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.router-dialog .p-dialog-content{
|
||||
padding: 0 1.2rem 1.2rem;
|
||||
background: linear-gradient(180deg, rgba(75, 144, 217, 0.06) 0%, rgba(75, 144, 217, 0) 180px), var(--surface-1);
|
||||
}
|
||||
|
||||
.router-dialog-header{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.9rem;
|
||||
width: calc(100% - 0.5rem);
|
||||
}
|
||||
|
||||
.router-dialog-header__icon{
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: 18px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, rgba(75, 144, 217, 0.24), rgba(79, 181, 147, 0.14));
|
||||
border: 1px solid rgba(75, 144, 217, 0.2);
|
||||
color: var(--primary);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.router-dialog-header__icon .pi{
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.router-dialog-header__text{
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.router-dialog-header__eyebrow{
|
||||
font-family: var(--font-title);
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-soft);
|
||||
}
|
||||
|
||||
.router-dialog-header__title{
|
||||
margin-top: 0.2rem;
|
||||
font-family: var(--font-title);
|
||||
font-size: 1.18rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.router-dialog-header__text small{
|
||||
display: block;
|
||||
margin-top: 0.3rem;
|
||||
max-width: 42rem;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.router-dialog-form{
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.router-dialog-panel{
|
||||
padding: 1rem;
|
||||
border-radius: 22px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0)), var(--surface-0);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.router-dialog-panel:first-child{
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.router-dialog-panel__header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.95rem;
|
||||
}
|
||||
|
||||
.router-dialog-panel__header strong{
|
||||
display: block;
|
||||
font-family: var(--font-title);
|
||||
font-size: 0.88rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.router-dialog-panel__header p{
|
||||
margin: 0.35rem 0 0;
|
||||
color: var(--text-soft);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.router-dialog-pill{
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
padding: 0.55rem 0.85rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(75, 144, 217, 0.18);
|
||||
background: rgba(75, 144, 217, 0.08);
|
||||
color: var(--text-main);
|
||||
font-family: var(--font-title);
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.router-dialog-grid{
|
||||
gap: 0.95rem 1rem;
|
||||
}
|
||||
|
||||
.router-dialog-note{
|
||||
margin-top: 0.9rem;
|
||||
padding: 0.85rem 0.95rem;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(75, 144, 217, 0.18);
|
||||
background: rgba(75, 144, 217, 0.08);
|
||||
color: var(--text-soft);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.65rem;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.router-dialog-note .pi{
|
||||
margin-top: 0.1rem;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.router-dialog .p-inputtext,
|
||||
.router-dialog .p-dropdown,
|
||||
.router-dialog .p-inputtextarea{
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
|
||||
.router-dialog .p-inputtextarea{
|
||||
min-height: 11rem;
|
||||
}
|
||||
|
||||
.router-dialog-actions{
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
padding-top: 0.1rem;
|
||||
}
|
||||
|
||||
.router-dialog-actions .p-button{
|
||||
min-width: 11rem;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.router-dialog .p-dialog-header{
|
||||
padding: 1rem 0.85rem 0.85rem;
|
||||
}
|
||||
|
||||
.router-dialog .p-dialog-content{
|
||||
padding: 0 0.85rem 0.95rem;
|
||||
}
|
||||
|
||||
.router-dialog-header{
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.router-dialog-panel__header{
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.router-dialog-actions{
|
||||
flex-direction: column-reverse;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.router-dialog-actions .p-button{
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user