first commit
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"projects": {
|
||||
"routeros-backup-manager-next-ui": {
|
||||
"mikrotik-backup-system-ui": {
|
||||
"projectType": "application",
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
@@ -11,7 +11,7 @@
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:application",
|
||||
"options": {
|
||||
"outputPath": "dist/routeros-backup-manager-next-ui",
|
||||
"outputPath": "dist/mikrotik-backup-system-ui",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
"polyfills": [
|
||||
@@ -24,8 +24,6 @@
|
||||
],
|
||||
"styles": [
|
||||
"node_modules/primeicons/primeicons.css",
|
||||
"node_modules/primeng/resources/themes/lara-light-blue/theme.css",
|
||||
"node_modules/primeng/resources/primeng.min.css",
|
||||
"src/styles.css"
|
||||
]
|
||||
},
|
||||
@@ -38,8 +36,8 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "1mb",
|
||||
"maximumError": "2mb"
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "3mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
@@ -59,14 +57,14 @@
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"buildTarget": "routeros-backup-manager-next-ui:build"
|
||||
"buildTarget": "mikrotik-backup-system-ui:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "routeros-backup-manager-next-ui:build:production"
|
||||
"buildTarget": "mikrotik-backup-system-ui:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "routeros-backup-manager-next-ui:build:development"
|
||||
"buildTarget": "mikrotik-backup-system-ui:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
|
||||
9716
frontend/package-lock.json
generated
9716
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "routeros-backup-manager-next-ui",
|
||||
"name": "mikrotik-backup-system-ui",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -11,27 +11,28 @@
|
||||
"build:dev": "ng build --configuration development"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^17.3.0",
|
||||
"@angular/common": "^17.3.0",
|
||||
"@angular/compiler": "^17.3.0",
|
||||
"@angular/core": "^17.3.0",
|
||||
"@angular/forms": "^17.3.0",
|
||||
"@angular/platform-browser": "^17.3.0",
|
||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||
"@angular/router": "^17.3.0",
|
||||
"@ngx-translate/core": "^15.0.0",
|
||||
"@ngx-translate/http-loader": "^8.0.0",
|
||||
"@angular/animations": "^20.3.0",
|
||||
"@angular/common": "^20.3.0",
|
||||
"@angular/compiler": "^20.3.0",
|
||||
"@angular/core": "^20.3.0",
|
||||
"@angular/forms": "^20.3.0",
|
||||
"@angular/platform-browser": "^20.3.0",
|
||||
"@angular/platform-browser-dynamic": "^20.3.0",
|
||||
"@angular/router": "^20.3.0",
|
||||
"@ngx-translate/core": "^17.0.0",
|
||||
"@ngx-translate/http-loader": "^17.0.0",
|
||||
"primeicons": "^7.0.0",
|
||||
"primeng": "^17.18.0",
|
||||
"primeng": "^20.1.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"tslib": "^2.6.2",
|
||||
"zone.js": "^0.14.4"
|
||||
"tslib": "^2.8.0",
|
||||
"zone.js": "~0.15.0",
|
||||
"@primeuix/themes": "^1.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.3.0",
|
||||
"@angular/cli": "^17.3.0",
|
||||
"@angular/compiler-cli": "^17.3.0",
|
||||
"typescript": "^5.4.0",
|
||||
"@angular-devkit/build-angular": "^20.3.0",
|
||||
"@angular/cli": "^20.3.0",
|
||||
"@angular/compiler-cli": "^20.3.0",
|
||||
"typescript": "~5.8.0",
|
||||
"ansi-colors": "^4.1.3",
|
||||
"esbuild": "^0.25.0",
|
||||
"semver": "^7.7.1",
|
||||
|
||||
@@ -53,7 +53,7 @@ export class AppComponent {
|
||||
|
||||
readonly menuItems = [
|
||||
{ label: 'nav.dashboard', link: '/', icon: 'pi pi-home', exact: true },
|
||||
{ label: 'nav.routers', link: '/routers', icon: 'pi pi-server', exact: false },
|
||||
{ label: 'nav.routers', link: '/devices', 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.logs', link: '/logs', icon: 'pi pi-history', exact: false },
|
||||
@@ -108,11 +108,11 @@ export class AppComponent {
|
||||
}
|
||||
|
||||
private updatePageLabel(url: string) {
|
||||
if (url.startsWith('/routers/')) {
|
||||
if (url.startsWith('/devices/') || url.startsWith('/routers/')) {
|
||||
this.pageLabel = 'routers.detailTitle';
|
||||
return;
|
||||
}
|
||||
if (url.startsWith('/routers')) {
|
||||
if (url.startsWith('/devices') || url.startsWith('/routers')) {
|
||||
this.pageLabel = 'routers.title';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@ export const routes: Routes = [
|
||||
{ path: 'register', component: RegisterPageComponent },
|
||||
{ path: 'change-password', canActivate: [authGuard], component: ChangePasswordPageComponent },
|
||||
{ path: '', canActivate: [authGuard], component: DashboardPageComponent },
|
||||
{ path: 'routers', canActivate: [authGuard], component: RoutersPageComponent },
|
||||
{ path: 'routers/:id', canActivate: [authGuard], component: RouterDetailPageComponent },
|
||||
{ path: 'devices', canActivate: [authGuard], component: RoutersPageComponent },
|
||||
{ path: 'devices/:id', canActivate: [authGuard], component: RouterDetailPageComponent },
|
||||
{ path: 'routers', redirectTo: 'devices', pathMatch: 'full' },
|
||||
{ path: 'routers/:id', redirectTo: 'devices/:id', pathMatch: 'full' },
|
||||
{ path: 'files', canActivate: [authGuard], component: FilesPageComponent },
|
||||
{ path: 'diff-configs', canActivate: [authGuard], component: DiffConfigsPageComponent },
|
||||
{ path: 'settings', canActivate: [authGuard], component: SettingsPageComponent },
|
||||
|
||||
@@ -19,7 +19,23 @@ export class ThemeService {
|
||||
|
||||
set(mode: 'light' | 'dark') {
|
||||
this.modeState.set(mode);
|
||||
document.body.classList.toggle('dark-theme', mode === 'dark');
|
||||
|
||||
const isDark = mode === 'dark';
|
||||
const html = document.documentElement;
|
||||
const body = document.body;
|
||||
|
||||
html.classList.toggle('dark-theme', isDark);
|
||||
body.classList.toggle('dark-theme', isDark);
|
||||
|
||||
html.setAttribute('data-theme', mode);
|
||||
body.setAttribute('data-theme', mode);
|
||||
html.style.colorScheme = isDark ? 'dark' : 'light';
|
||||
body.style.colorScheme = isDark ? 'dark' : 'light';
|
||||
|
||||
localStorage.setItem(this.key, mode);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
134
frontend/src/app/core/theme-preset.ts
Normal file
134
frontend/src/app/core/theme-preset.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { definePreset } from '@primeuix/themes';
|
||||
import Lara from '@primeuix/themes/lara';
|
||||
|
||||
const AppPreset = definePreset(Lara, {
|
||||
primitive: {
|
||||
borderRadius: {
|
||||
none: '0',
|
||||
xs: '8px',
|
||||
sm: '10px',
|
||||
md: '12px',
|
||||
lg: '16px',
|
||||
xl: '20px'
|
||||
}
|
||||
},
|
||||
semantic: {
|
||||
primary: {
|
||||
50: '#f6eee8',
|
||||
100: '#ecd7c8',
|
||||
200: '#dfb79e',
|
||||
300: '#cf9571',
|
||||
400: '#b9754d',
|
||||
500: '#8d593a',
|
||||
600: '#794a30',
|
||||
700: '#653d28',
|
||||
800: '#533220',
|
||||
900: '#43291a',
|
||||
950: '#2a1910'
|
||||
},
|
||||
colorScheme: {
|
||||
light: {
|
||||
surface: {
|
||||
0: '#ffffff',
|
||||
50: '#f8f8f5',
|
||||
100: '#f1f1ed',
|
||||
200: '#e6e6e0',
|
||||
300: '#dfdfd8',
|
||||
400: '#d0d0c8',
|
||||
500: '#b7b7ae',
|
||||
600: '#8f8f86',
|
||||
700: '#6e6e67',
|
||||
800: '#4f4f49',
|
||||
900: '#31312d',
|
||||
950: '#1e1e1b'
|
||||
},
|
||||
content: {
|
||||
background: '#f8f8f5',
|
||||
hoverBackground: '#f1f1ed',
|
||||
borderColor: 'rgba(17, 20, 23, 0.12)',
|
||||
color: '#111417',
|
||||
hoverColor: '#111417'
|
||||
},
|
||||
formField: {
|
||||
background: 'rgba(255, 255, 255, 0.5)',
|
||||
disabledBackground: '#f1f1ed',
|
||||
borderColor: 'rgba(17, 20, 23, 0.2)',
|
||||
hoverBorderColor: '#8d593a',
|
||||
focusBorderColor: '#8d593a',
|
||||
color: '#111417',
|
||||
placeholderColor: '#5e666e',
|
||||
floatLabelColor: '#5e666e'
|
||||
},
|
||||
overlay: {
|
||||
select: {
|
||||
background: '#f8f8f5',
|
||||
borderColor: 'rgba(17, 20, 23, 0.12)',
|
||||
color: '#111417'
|
||||
},
|
||||
popover: {
|
||||
background: '#f8f8f5',
|
||||
borderColor: 'rgba(17, 20, 23, 0.12)',
|
||||
color: '#111417'
|
||||
},
|
||||
modal: {
|
||||
background: '#f8f8f5',
|
||||
borderColor: 'rgba(17, 20, 23, 0.12)',
|
||||
color: '#111417'
|
||||
}
|
||||
}
|
||||
},
|
||||
dark: {
|
||||
surface: {
|
||||
0: '#17212b',
|
||||
50: '#1d2733',
|
||||
100: '#222d3a',
|
||||
200: '#2d3947',
|
||||
300: '#3a4858',
|
||||
400: '#516173',
|
||||
500: '#6c7c8d',
|
||||
600: '#93a5b6',
|
||||
700: '#b7c7d6',
|
||||
800: '#dae4ec',
|
||||
900: '#edf2f7',
|
||||
950: '#f7fbff'
|
||||
},
|
||||
content: {
|
||||
background: '#1d2733',
|
||||
hoverBackground: '#222d3a',
|
||||
borderColor: 'rgba(146, 170, 194, 0.16)',
|
||||
color: '#dae4ec',
|
||||
hoverColor: '#dae4ec'
|
||||
},
|
||||
formField: {
|
||||
background: 'rgba(255, 255, 255, 0.03)',
|
||||
disabledBackground: '#222d3a',
|
||||
borderColor: 'rgba(146, 170, 194, 0.25)',
|
||||
hoverBorderColor: '#4b90d9',
|
||||
focusBorderColor: '#4b90d9',
|
||||
color: '#dae4ec',
|
||||
placeholderColor: '#93a5b6',
|
||||
floatLabelColor: '#93a5b6'
|
||||
},
|
||||
overlay: {
|
||||
select: {
|
||||
background: '#1d2733',
|
||||
borderColor: 'rgba(146, 170, 194, 0.16)',
|
||||
color: '#dae4ec'
|
||||
},
|
||||
popover: {
|
||||
background: '#1d2733',
|
||||
borderColor: 'rgba(146, 170, 194, 0.16)',
|
||||
color: '#dae4ec'
|
||||
},
|
||||
modal: {
|
||||
background: '#1d2733',
|
||||
borderColor: 'rgba(146, 170, 194, 0.16)',
|
||||
color: '#dae4ec'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default AppPreset;
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="stats-grid" *ngIf="data">
|
||||
<app-stat-card [label]="'dashboard.managedRouters' | translate" [value]="data.routers_count" [hint]="'dashboard.managedRoutersHint' | translate" [tag]="'dashboard.inventoryTag' | translate" icon="pi pi-server" iconClass="icon-blue"></app-stat-card>
|
||||
<app-stat-card [label]="'dashboard.exportsCard' | translate" [value]="data.export_count" [hint]="'dashboard.exportsHint' | translate" [tag]="'dashboard.textTag' | translate" severity="success" icon="pi pi-file-export" iconClass="icon-emerald"></app-stat-card>
|
||||
<app-stat-card [label]="'dashboard.binaryCard' | translate" [value]="data.binary_count" [hint]="'dashboard.binaryHint' | translate" [tag]="'dashboard.binaryTag' | translate" severity="warning" icon="pi pi-database" iconClass="icon-amber"></app-stat-card>
|
||||
<app-stat-card [label]="'dashboard.binaryCard' | translate" [value]="data.binary_count" [hint]="'dashboard.binaryHint' | translate" [tag]="'dashboard.binaryTag' | translate" severity="warn" icon="pi pi-database" iconClass="icon-amber"></app-stat-card>
|
||||
<app-stat-card [label]="'dashboard.allFilesCard' | translate" [value]="data.total_backups" [hint]="'dashboard.allFilesHint' | translate" [tag]="'dashboard.archiveTag' | translate" severity="info" icon="pi pi-folder" iconClass="icon-violet"></app-stat-card>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="stats-grid compact-grid">
|
||||
<app-stat-card [label]="'diffConfigs.exportsCard' | translate" [value]="availableExportsCount" [hint]="'diffConfigs.exportsCardHint' | translate" [tag]="'files.exportType' | translate" severity="success" icon="pi pi-file-export" iconClass="icon-emerald"></app-stat-card>
|
||||
<app-stat-card [label]="'diffConfigs.scopeCard' | translate" [value]="selectedRouterLabel" [hint]="'diffConfigs.scopeCardHint' | translate" [tag]="'diffConfigs.scopeTag' | translate" severity="info" icon="pi pi-server" iconClass="icon-blue"></app-stat-card>
|
||||
<app-stat-card [label]="'diffConfigs.readyCard' | translate" [value]="compareReady ? ('common.ok' | translate) : ('common.idle' | translate)" [hint]="'diffConfigs.readyCardHint' | translate" [tag]="'diffConfigs.readyTag' | translate" severity="warning" icon="pi pi-code" iconClass="icon-amber"></app-stat-card>
|
||||
<app-stat-card [label]="'diffConfigs.readyCard' | translate" [value]="compareReady ? ('common.ok' | translate) : ('common.idle' | translate)" [hint]="'diffConfigs.readyCardHint' | translate" [tag]="'diffConfigs.readyTag' | translate" severity="warn" icon="pi pi-code" iconClass="icon-amber"></app-stat-card>
|
||||
<app-stat-card [label]="'diffConfigs.lastDiffCard' | translate" [value]="lastDiffLabel" [hint]="'diffConfigs.lastDiffCardHint' | translate" [tag]="'diffConfigs.lastDiffTag' | translate" severity="secondary" icon="pi pi-history" iconClass="icon-violet"></app-stat-card>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="diff-workspace__toolbar">
|
||||
<span class="form-field diff-workspace__router">
|
||||
<label>{{ 'files.routerLabel' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="routerOptions" [(ngModel)]="routerId" optionLabel="label" optionValue="value" (onChange)="load()"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="routerOptions" [(ngModel)]="routerId" optionLabel="label" optionValue="value" (onChange)="load()"></p-select>
|
||||
</span>
|
||||
<div class="diff-workspace__actions">
|
||||
<button pButton type="button" severity="secondary" icon="pi pi-refresh" [label]="'common.reset' | translate" (click)="routerId = null; compareLeftId = null; compareRightId = null; load()"></button>
|
||||
@@ -31,7 +31,7 @@
|
||||
<strong>{{ 'files.compareOlder' | translate }}</strong>
|
||||
<p-tag [value]="compareLeft ? ('common.ok' | translate) : ('diffConfigs.waitingTag' | translate)" [severity]="compareLeft ? 'success' : 'secondary'"></p-tag>
|
||||
</div>
|
||||
<p-dropdown [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareLeftId" optionLabel="label" optionValue="value" [placeholder]="'files.pickOlder' | translate"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareLeftId" optionLabel="label" optionValue="value" [placeholder]="'files.pickOlder' | translate"></p-select>
|
||||
<div class="diff-pick-card__meta" *ngIf="compareLeft as item">
|
||||
<strong>{{ item.file_name }}</strong>
|
||||
<small>{{ item.router_name || item.router_id }} · {{ relativeAge(item.created_at) }}</small>
|
||||
@@ -48,7 +48,7 @@
|
||||
<strong>{{ 'files.compareNewer' | translate }}</strong>
|
||||
<p-tag [value]="compareRight ? ('common.ok' | translate) : ('diffConfigs.waitingTag' | translate)" [severity]="compareRight ? 'success' : 'secondary'"></p-tag>
|
||||
</div>
|
||||
<p-dropdown [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareRightId" optionLabel="label" optionValue="value" [placeholder]="'files.pickNewer' | translate"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareRightId" optionLabel="label" optionValue="value" [placeholder]="'files.pickNewer' | translate"></p-select>
|
||||
<div class="diff-pick-card__meta" *ngIf="compareRight as item">
|
||||
<strong>{{ item.file_name }}</strong>
|
||||
<small>{{ item.router_name || item.router_id }} · {{ relativeAge(item.created_at) }}</small>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { FormsModule } from '@angular/forms';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DialogModule } from 'primeng/dialog';
|
||||
import { DropdownModule } from 'primeng/dropdown';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { TagModule } from 'primeng/tag';
|
||||
|
||||
@@ -53,7 +53,7 @@ interface BackupDiffResponse {
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule, TranslateModule, ButtonModule, DialogModule, DropdownModule, TableModule, TagModule, PageHeaderComponent, SectionCardComponent, StatCardComponent],
|
||||
imports: [CommonModule, FormsModule, TranslateModule, ButtonModule, DialogModule, SelectModule, TableModule, TagModule, PageHeaderComponent, SectionCardComponent, StatCardComponent],
|
||||
templateUrl: './diff-configs-page.component.html'
|
||||
})
|
||||
export class DiffConfigsPageComponent implements OnInit {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<app-stat-card [label]="'files.visibleFiles' | translate" [value]="files.length" [hint]="'files.visibleFilesHint' | translate" [tag]="'files.liveTag' | translate" icon="pi pi-folder-open" iconClass="icon-blue"></app-stat-card>
|
||||
<app-stat-card [label]="'files.selected' | translate" [value]="selectedIds.length" [hint]="'files.selectedHint' | translate" [tag]="'files.batchTag' | translate" severity="secondary" icon="pi pi-check-square" iconClass="icon-violet"></app-stat-card>
|
||||
<app-stat-card [label]="'files.exportsCard' | translate" [value]="exportCount" [hint]="'files.exportsHint' | translate" [tag]="'dashboard.textTag' | translate" severity="success" icon="pi pi-file-export" iconClass="icon-emerald"></app-stat-card>
|
||||
<app-stat-card [label]="'files.binaryCard' | translate" [value]="binaryCount" [hint]="'files.binaryHint' | translate" [tag]="'dashboard.binaryTag' | translate" severity="warning" icon="pi pi-database" iconClass="icon-amber"></app-stat-card>
|
||||
<app-stat-card [label]="'files.binaryCard' | translate" [value]="binaryCount" [hint]="'files.binaryHint' | translate" [tag]="'dashboard.binaryTag' | translate" severity="warn" icon="pi pi-database" iconClass="icon-amber"></app-stat-card>
|
||||
</div>
|
||||
|
||||
<app-section-card [title]="'files.filtersTitle' | translate" [subtitle]="'files.filtersSubtitle' | translate">
|
||||
@@ -24,12 +24,12 @@
|
||||
|
||||
<span class="form-field">
|
||||
<label>{{ 'files.typeLabel' | translate }}</label>
|
||||
<p-dropdown [options]="typeOptions" [(ngModel)]="backupType" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [options]="typeOptions" [(ngModel)]="backupType" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
|
||||
<span class="form-field">
|
||||
<label>{{ 'files.routerLabel' | translate }}</label>
|
||||
<p-dropdown [options]="routerOptions" [(ngModel)]="routerId" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [options]="routerOptions" [(ngModel)]="routerId" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
|
||||
<span class="form-field">
|
||||
@@ -39,12 +39,12 @@
|
||||
|
||||
<span class="form-field">
|
||||
<label>{{ 'files.sortLabel' | translate }}</label>
|
||||
<p-dropdown [options]="sortOptions" [(ngModel)]="sortBy" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [options]="sortOptions" [(ngModel)]="sortBy" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
|
||||
<span class="form-field">
|
||||
<label>{{ 'files.orderLabel' | translate }}</label>
|
||||
<p-dropdown [options]="orderOptions" [(ngModel)]="order" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [options]="orderOptions" [(ngModel)]="order" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
|
||||
<div class="filters-actions repository-toolbar__actions">
|
||||
@@ -68,14 +68,14 @@
|
||||
<div class="repository-compare__grid">
|
||||
<div class="compare-strip__slot repository-compare__slot">
|
||||
<label>{{ 'files.compareOlder' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareLeftId" optionLabel="label" optionValue="value" [placeholder]="'files.pickOlder' | translate"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareLeftId" optionLabel="label" optionValue="value" [placeholder]="'files.pickOlder' | translate"></p-select>
|
||||
</div>
|
||||
|
||||
<button pButton type="button" severity="secondary" icon="pi pi-sort-alt" styleClass="compare-strip__swap" (click)="swapCompare()" [disabled]="!compareLeftId && !compareRightId"></button>
|
||||
|
||||
<div class="compare-strip__slot repository-compare__slot">
|
||||
<label>{{ 'files.compareNewer' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareRightId" optionLabel="label" optionValue="value" [placeholder]="'files.pickNewer' | translate"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="compareOptions" [(ngModel)]="compareRightId" optionLabel="label" optionValue="value" [placeholder]="'files.pickNewer' | translate"></p-select>
|
||||
</div>
|
||||
|
||||
<div class="compare-strip__actions repository-compare__actions">
|
||||
@@ -111,7 +111,7 @@
|
||||
<div class="table-primary">{{ item.router_name || item.router_id }}</div>
|
||||
<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><p-tag [value]="item.backup_type === 'export' ? ('files.exportType' | translate) : ('files.binaryType' | translate)" [severity]="item.backup_type === 'export' ? 'success' : 'warn'"></p-tag></td>
|
||||
<td>
|
||||
<div class="table-primary">{{ item.created_at | date: 'dd.MM.yyyy HH:mm' }}</div>
|
||||
<small class="table-secondary">{{ relativeAge(item.created_at) }}</small>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { FormsModule } from '@angular/forms';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DialogModule } from 'primeng/dialog';
|
||||
import { DropdownModule } from 'primeng/dropdown';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { TagModule } from 'primeng/tag';
|
||||
@@ -57,7 +57,7 @@ interface BackupDiffResponse {
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule, TranslateModule, ButtonModule, DialogModule, DropdownModule, InputTextModule, TableModule, TagModule, PageHeaderComponent, SectionCardComponent, StatCardComponent],
|
||||
imports: [CommonModule, FormsModule, TranslateModule, ButtonModule, DialogModule, SelectModule, InputTextModule, TableModule, TagModule, PageHeaderComponent, SectionCardComponent, StatCardComponent],
|
||||
templateUrl: './files-page.component.html'
|
||||
})
|
||||
export class FilesPageComponent implements OnInit {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<div class="stats-grid compact-grid">
|
||||
<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.binaryLabel' | translate" [value]="binaryBackups.length" [hint]="'routers.binaryLabelHint' | translate" [tag]="'files.binaryType' | translate" severity="warn" 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?.effective_username || '-'" [hint]="'routers.sshUserHint' | translate" [tag]="'routers.accessTag' | translate" severity="secondary" icon="pi pi-user" iconClass="icon-violet"></app-stat-card>
|
||||
</div>
|
||||
|
||||
@@ -252,7 +252,7 @@ export class RouterDetailPageComponent implements OnInit {
|
||||
}
|
||||
this.deletingRouter = true;
|
||||
this.api.http.delete(`${this.api.baseUrl}/routers/${this.routerId}`).subscribe({
|
||||
next: () => this.router.navigate(['/routers']),
|
||||
next: () => this.router.navigate(['/devices']),
|
||||
complete: () => {
|
||||
this.deletingRouter = false;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.deviceType' | translate }}</label>
|
||||
<p-dropdown [options]="deviceTypeOptions" formControlName="device_type" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [options]="deviceTypeOptions" formControlName="device_type" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'routers.host' | translate }}</label>
|
||||
@@ -138,7 +138,7 @@
|
||||
</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>
|
||||
<textarea pTextarea formControlName="ssh_key" rows="8" [placeholder]="'routers.optionalPrivateKey' | translate"></textarea>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ 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 { SelectModule } from 'primeng/select';
|
||||
import { TextareaModule } from 'primeng/textarea';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { TagModule } from 'primeng/tag';
|
||||
@@ -42,9 +42,9 @@ interface RouterItem {
|
||||
TranslateModule,
|
||||
ButtonModule,
|
||||
DialogModule,
|
||||
DropdownModule,
|
||||
SelectModule,
|
||||
InputTextModule,
|
||||
InputTextareaModule,
|
||||
TextareaModule,
|
||||
TableModule,
|
||||
TagModule,
|
||||
PageHeaderComponent,
|
||||
@@ -163,7 +163,7 @@ export class RoutersPageComponent implements OnInit {
|
||||
}
|
||||
|
||||
open(id: number) {
|
||||
this.router.navigate(['/routers', id]);
|
||||
this.router.navigate(['/devices', id]);
|
||||
}
|
||||
|
||||
deviceTypeLabel(item: RouterItem): string {
|
||||
@@ -174,7 +174,7 @@ export class RoutersPageComponent implements OnInit {
|
||||
return item.effective_username || item.ssh_user || '—';
|
||||
}
|
||||
|
||||
primaryAccessTag(item: RouterItem): { value: string; severity: 'success' | 'warning' | 'secondary' | 'info' } {
|
||||
primaryAccessTag(item: RouterItem): { value: string; severity: 'success' | 'warn' | 'secondary' | 'info' } {
|
||||
if (item.device_type === 'switchos') {
|
||||
if (item.uses_global_switchos_credentials) {
|
||||
return { value: this.ui.instant('routers.defaultCredentials'), severity: 'info' };
|
||||
@@ -187,15 +187,15 @@ export class RoutersPageComponent implements OnInit {
|
||||
|
||||
return {
|
||||
value: item.ssh_password ? this.ui.instant('routers.passwordMode') : this.ui.instant('routers.noPassword'),
|
||||
severity: item.ssh_password ? 'warning' : 'secondary'
|
||||
severity: item.ssh_password ? 'warn' : 'secondary'
|
||||
};
|
||||
}
|
||||
|
||||
secondaryAccessTag(item: RouterItem): { value: string; severity: 'success' | 'warning' | 'secondary' | 'info' } {
|
||||
secondaryAccessTag(item: RouterItem): { value: string; severity: 'success' | 'warn' | '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'
|
||||
severity: item.has_effective_password ? 'warn' : 'secondary'
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<div class="scheduler-card__grid">
|
||||
<span class="form-field">
|
||||
<label>{{ 'settings.scheduleMode' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="scheduleModeOptions" [(ngModel)]="scheduleEditors.export.mode" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="scheduleModeOptions" [(ngModel)]="scheduleEditors.export.mode" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
<span class="form-field" *ngIf="scheduleEditors.export.mode !== 'custom' && scheduleEditors.export.mode !== 'disabled'">
|
||||
<label>{{ 'settings.scheduleTime' | translate }}</label>
|
||||
@@ -60,7 +60,7 @@
|
||||
</span>
|
||||
<span class="form-field" *ngIf="scheduleEditors.export.mode === 'weekly'">
|
||||
<label>{{ 'settings.scheduleWeekday' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="weekdayOptions" [(ngModel)]="scheduleEditors.export.weekday" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="weekdayOptions" [(ngModel)]="scheduleEditors.export.weekday" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
<span class="form-field form-field--full" *ngIf="scheduleEditors.export.mode === 'custom'">
|
||||
<label>{{ 'settings.exportCron' | translate }}</label>
|
||||
@@ -81,7 +81,7 @@
|
||||
<div class="scheduler-card__grid">
|
||||
<span class="form-field">
|
||||
<label>{{ 'settings.scheduleMode' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="scheduleModeOptions" [(ngModel)]="scheduleEditors.binary.mode" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="scheduleModeOptions" [(ngModel)]="scheduleEditors.binary.mode" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
<span class="form-field" *ngIf="scheduleEditors.binary.mode !== 'custom' && scheduleEditors.binary.mode !== 'disabled'">
|
||||
<label>{{ 'settings.scheduleTime' | translate }}</label>
|
||||
@@ -93,7 +93,7 @@
|
||||
</span>
|
||||
<span class="form-field" *ngIf="scheduleEditors.binary.mode === 'weekly'">
|
||||
<label>{{ 'settings.scheduleWeekday' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="weekdayOptions" [(ngModel)]="scheduleEditors.binary.weekday" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="weekdayOptions" [(ngModel)]="scheduleEditors.binary.weekday" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
<span class="form-field form-field--full" *ngIf="scheduleEditors.binary.mode === 'custom'">
|
||||
<label>{{ 'settings.binaryCron' | translate }}</label>
|
||||
@@ -122,7 +122,7 @@
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'settings.scheduleMode' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="scheduleModeOptions" [(ngModel)]="scheduleEditors.retention.mode" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="scheduleModeOptions" [(ngModel)]="scheduleEditors.retention.mode" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
<span class="form-field" *ngIf="scheduleEditors.retention.mode !== 'custom' && scheduleEditors.retention.mode !== 'disabled'">
|
||||
<label>{{ 'settings.scheduleTime' | translate }}</label>
|
||||
@@ -134,7 +134,7 @@
|
||||
</span>
|
||||
<span class="form-field" *ngIf="scheduleEditors.retention.mode === 'weekly'">
|
||||
<label>{{ 'settings.scheduleWeekday' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [options]="weekdayOptions" [(ngModel)]="scheduleEditors.retention.weekday" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" [options]="weekdayOptions" [(ngModel)]="scheduleEditors.retention.weekday" [ngModelOptions]="{ standalone: true }" optionLabel="label" optionValue="value"></p-select>
|
||||
</span>
|
||||
<span class="form-field form-field--full" *ngIf="scheduleEditors.retention.mode === 'custom'">
|
||||
<label>{{ 'settings.retentionCron' | translate }}</label>
|
||||
@@ -180,11 +180,11 @@
|
||||
<div class="form-grid-2">
|
||||
<span class="form-field">
|
||||
<label>{{ 'topbar.languageSelector' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" [autoDisplayFirst]="false" formControlName="preferred_language" [options]="languageOptions" optionLabel="label" optionValue="value" (onChange)="previewLanguage($event.value)"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" formControlName="preferred_language" [options]="languageOptions" optionLabel="label" optionValue="value" (onChange)="previewLanguage($event.value)"></p-select>
|
||||
</span>
|
||||
<span class="form-field">
|
||||
<label>{{ 'settings.fontFamily' | translate }}</label>
|
||||
<p-dropdown [appendTo]="'body'" formControlName="preferred_font" [options]="fontOptions" optionLabel="label" optionValue="value" (onChange)="previewFont()"></p-dropdown>
|
||||
<p-select [appendTo]="'body'" formControlName="preferred_font" [options]="fontOptions" optionLabel="label" optionValue="value" (onChange)="previewFont()"></p-select>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -283,7 +283,7 @@
|
||||
<div class="form-field form-field--full">
|
||||
<label>{{ 'settings.globalSshPrivateKey' | translate }}</label>
|
||||
<textarea
|
||||
pInputTextarea
|
||||
pTextarea
|
||||
formControlName="global_ssh_key"
|
||||
rows="14"
|
||||
[placeholder]="(hasStoredSshKey && !sshKeyVisible && !clearStoredSshKey) ? ('settings.globalSshPrivateKeyHiddenPlaceholder' | translate) : ('settings.globalSshPrivateKeyPlaceholder' | translate)"
|
||||
|
||||
@@ -3,9 +3,9 @@ import { Component, OnDestroy, OnInit, effect, inject } from '@angular/core';
|
||||
import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DropdownModule } from 'primeng/dropdown';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { InputTextareaModule } from 'primeng/inputtextarea';
|
||||
import { TextareaModule } from 'primeng/textarea';
|
||||
import { TagModule } from 'primeng/tag';
|
||||
import { Subject, finalize, forkJoin, takeUntil } from 'rxjs';
|
||||
|
||||
@@ -71,7 +71,7 @@ interface SettingsResponse {
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, ButtonModule, DropdownModule, InputTextModule, InputTextareaModule, TagModule, PageHeaderComponent],
|
||||
imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, ButtonModule, SelectModule, InputTextModule, TextareaModule, TagModule, PageHeaderComponent],
|
||||
templateUrl: './settings-page.component.html'
|
||||
})
|
||||
export class SettingsPageComponent implements OnInit, OnDestroy {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<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="warning" [value]="'switchosBeta.betaTag' | translate"></p-tag>
|
||||
<p-tag severity="warn" [value]="'switchosBeta.betaTag' | translate"></p-tag>
|
||||
</div>
|
||||
</app-page-header>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<strong>{{ 'switchosBeta.warningHeadline' | translate }}</strong>
|
||||
<p>{{ 'switchosBeta.warningBody' | translate }}</p>
|
||||
</div>
|
||||
<p-tag severity="warning" [value]="'switchosBeta.betaTag' | translate"></p-tag>
|
||||
<p-tag severity="warn" [value]="'switchosBeta.betaTag' | translate"></p-tag>
|
||||
</div>
|
||||
</app-section-card>
|
||||
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
<i [class]="icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<p-tag *ngIf="tag" [value]="tag" [severity]="severity"></p-tag>
|
||||
<p-tag *ngIf="tag" [value]="tag" [severity]="tagSeverity"></p-tag>
|
||||
</p-card>
|
||||
|
||||
@@ -16,5 +16,9 @@ export class StatCardComponent {
|
||||
@Input() tag = '';
|
||||
@Input() icon = 'pi pi-chart-bar';
|
||||
@Input() iconClass = '';
|
||||
@Input() severity: 'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | undefined = 'info';
|
||||
@Input() severity: 'success' | 'info' | 'warning' | 'warn' | 'danger' | 'secondary' | 'contrast' | undefined = 'info';
|
||||
|
||||
get tagSeverity(): 'success' | 'secondary' | 'info' | 'warn' | 'danger' | 'contrast' | null | undefined {
|
||||
return this.severity === 'warning' ? 'warn' : this.severity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
"menu": "Menu"
|
||||
},
|
||||
"sidebar": {
|
||||
"title": "MikroTik backup",
|
||||
"subtitle": "RouterOS manager"
|
||||
"title": "Mikrotik Backup System",
|
||||
"subtitle": "Device backup platform"
|
||||
},
|
||||
"topbar": {
|
||||
"caption": "mikrotik / control center",
|
||||
@@ -127,7 +127,7 @@
|
||||
"storageViewMixHint": "Split of all snapshots into text exports and binary backups.",
|
||||
"storageViewActivity": "7-day activity",
|
||||
"storageViewActivityHint": "Number of new backups created during the last seven days.",
|
||||
"storageViewRouters": "Top routers",
|
||||
"storageViewRouters": "Top devices",
|
||||
"storageViewRoutersHint": "Devices with the highest number of snapshots in the repository.",
|
||||
"storageChartEmpty": "There is not enough data to draw this chart yet.",
|
||||
"storageSnapshotTitle": "Repository metrics",
|
||||
@@ -299,8 +299,8 @@
|
||||
"compareSubtitle": "Pick two .rsc files and launch the diff without digging through the whole table.",
|
||||
"exportPoolLabel": "exports ready to compare",
|
||||
"compareSelectionHint": "Pick an older and a newer file",
|
||||
"compareReadySameRouter": "Pair ready · router {{router}}",
|
||||
"compareReadyMixedRouters": "Pair ready · mixed routers"
|
||||
"compareReadySameRouter": "Pair ready · device {{router}}",
|
||||
"compareReadyMixedRouters": "Pair ready · mixed devices"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Settings",
|
||||
@@ -436,8 +436,8 @@
|
||||
"selectedBackupsDeleted": "Selected backups deleted.",
|
||||
"diffLoaded": "Diff loaded.",
|
||||
"archivePrepared": "Archive prepared.",
|
||||
"exportedRouters": "Export completed for {{count}} routers.",
|
||||
"binaryCompletedRouters": "Binary backup completed for {{count}} routers.",
|
||||
"exportedRouters": "Export completed for {{count}} devices.",
|
||||
"binaryCompletedRouters": "Binary backup completed for {{count}} devices.",
|
||||
"routerCreated": "Router created.",
|
||||
"routerUpdated": "Router updated.",
|
||||
"routerDeleted": "Router deleted.",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"title": "copia de MikroTik",
|
||||
"subtitle": "gestor de RouterOS"
|
||||
"subtitle": "gestor de RouterOS/SwitchOS"
|
||||
},
|
||||
"topbar": {
|
||||
"caption": "mikrotik / centro de control",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"title": "MikroTik-backup",
|
||||
"subtitle": "RouterOS-behandler"
|
||||
"subtitle": "RouterOS/SwitchOS-behandler"
|
||||
},
|
||||
"topbar": {
|
||||
"caption": "mikrotik / kontrollsenter",
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
"menu": "Menu"
|
||||
},
|
||||
"sidebar": {
|
||||
"title": "kopie MikroTik",
|
||||
"subtitle": "manager RouterOS"
|
||||
"title": "Mikrotik Backup System",
|
||||
"subtitle": "Device backup platform"
|
||||
},
|
||||
"topbar": {
|
||||
"caption": "mikrotik / control center",
|
||||
@@ -369,7 +369,7 @@
|
||||
"binaryPlannerHint": "Oddzielne okno dla pełnych backupów binarnych, gdy potrzebujesz punktów odtworzenia.",
|
||||
"retentionPlannerHint": "Retencja czyści stare backupy i logi według osobnego planu.",
|
||||
"connectionTestsTitle": "Automatyczne testy połączeń",
|
||||
"connectionTestsHint": "Aplikacja może sama odświeżać status routerów. Ustaw 0, aby wyłączyć automatyczne testy.",
|
||||
"connectionTestsHint": "Aplikacja może sama odświeżać status urządzeń. Ustaw 0, aby wyłączyć automatyczne testy.",
|
||||
"connectionTestIntervalMinutes": "Test co X minut",
|
||||
"connectionTestsEverySummary": "Co {{minutes}} min",
|
||||
"connectionTestsDisabledHint": "Automatyczne testy połączeń są wyłączone.",
|
||||
@@ -436,8 +436,8 @@
|
||||
"selectedBackupsDeleted": "Wybrane backupy zostały usunięte.",
|
||||
"diffLoaded": "Załadowano diff.",
|
||||
"archivePrepared": "Archiwum zostało przygotowane.",
|
||||
"exportedRouters": "Wykonano eksport dla {{count}} routerów.",
|
||||
"binaryCompletedRouters": "Wykonano backup binarny dla {{count}} routerów.",
|
||||
"exportedRouters": "Wykonano eksport dla {{count}} urządzeń.",
|
||||
"binaryCompletedRouters": "Wykonano backup binarny dla {{count}} urządzeń.",
|
||||
"routerCreated": "Router został dodany.",
|
||||
"routerUpdated": "Router został zaktualizowany.",
|
||||
"routerDeleted": "Router został usunięty.",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>RouterOS Backup Manager Next</title>
|
||||
<title>Mikrotik Backup System</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script>
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
import { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { importProvidersFrom } from '@angular/core';
|
||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { providePrimeNG } from 'primeng/config';
|
||||
import AppPreset from './app/core/theme-preset';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { provideTranslateService } from '@ngx-translate/core';
|
||||
import { provideTranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { routes } from './app/app.routes';
|
||||
import { authInterceptor } from './app/core/interceptors/auth.interceptor';
|
||||
|
||||
export function httpLoaderFactory(http: HttpClient) {
|
||||
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||
}
|
||||
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [
|
||||
provideAnimations(),
|
||||
provideHttpClient(withInterceptors([authInterceptor])),
|
||||
provideRouter(routes),
|
||||
providePrimeNG({
|
||||
theme: {
|
||||
preset: AppPreset,
|
||||
options: {
|
||||
darkModeSelector: '.dark-theme',
|
||||
cssLayer: false
|
||||
}
|
||||
}
|
||||
}),
|
||||
provideTranslateService({
|
||||
loader: provideTranslateHttpLoader({
|
||||
prefix: './assets/i18n/',
|
||||
suffix: '.json'
|
||||
}),
|
||||
lang: 'en',
|
||||
fallbackLang: 'en'
|
||||
}),
|
||||
MessageService,
|
||||
ConfirmationService,
|
||||
importProvidersFrom(
|
||||
TranslateModule.forRoot({
|
||||
defaultLanguage: 'pl',
|
||||
loader: { provide: TranslateLoader, useFactory: httpLoaderFactory, deps: [HttpClient] }
|
||||
})
|
||||
)
|
||||
ConfirmationService
|
||||
]
|
||||
}).catch((err) => console.error(err));
|
||||
|
||||
@@ -96,26 +96,12 @@ body.dark-theme .topbar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.topbar__lang-select,
|
||||
.auth-toolbar__select {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
min-width: 10.5rem;
|
||||
min-height: 2.4rem;
|
||||
padding: 0.55rem 2.15rem 0.55rem 0.95rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: color-mix(in srgb, var(--surface-1) 92%, transparent);
|
||||
color: var(--text-main);
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.topbar__lang-picker::after,
|
||||
.auth-toolbar__select-wrap::after {
|
||||
content: '\e902';
|
||||
font-family: 'primeicons';
|
||||
position: absolute;
|
||||
right: 0.85rem;
|
||||
right: 1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
@@ -123,15 +109,48 @@ body.dark-theme .topbar {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.topbar__lang-select,
|
||||
.auth-toolbar__select {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
min-width: 10.5rem;
|
||||
min-height: 2.95rem;
|
||||
padding: 0.72rem 2.7rem 0.72rem 1rem;
|
||||
border-radius: 14px;
|
||||
border: 1px solid var(--border-strong);
|
||||
background: color-mix(in srgb, var(--surface-1) 88%, white 12%);
|
||||
color: var(--text-main);
|
||||
font: inherit;
|
||||
font-size: 0.96rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.35;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.16s ease, box-shadow 0.16s ease, background-color 0.16s ease;
|
||||
}
|
||||
|
||||
.topbar__lang-select:hover,
|
||||
.auth-toolbar__select:hover {
|
||||
border-color: color-mix(in srgb, var(--accent) 56%, var(--border-strong));
|
||||
}
|
||||
|
||||
.topbar__lang-select:focus,
|
||||
.auth-toolbar__select:focus {
|
||||
outline: none;
|
||||
border-color: color-mix(in srgb, var(--blue) 72%, var(--border-strong));
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 18%, transparent);
|
||||
}
|
||||
|
||||
.topbar__lang-select option,
|
||||
.auth-toolbar__select option {
|
||||
color: #111417;
|
||||
background: #ffffff;
|
||||
color: var(--text-main);
|
||||
background: var(--surface-1);
|
||||
}
|
||||
|
||||
body.dark-theme .topbar__lang-select,
|
||||
body.dark-theme .auth-toolbar__select {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
body.dark-theme .topbar__lang-select option,
|
||||
@@ -140,24 +159,6 @@ body.dark-theme .auth-toolbar__select option {
|
||||
background: #1c2631;
|
||||
}
|
||||
|
||||
.app-auth-view {
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.app-auth-view__content {
|
||||
min-height: 0;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.app-auth-view__content > * {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.layout-footer--auth {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.layout-shell,
|
||||
|
||||
@@ -262,7 +262,7 @@ body.dark-theme .topbar{
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.24);
|
||||
border-radius: 10px;
|
||||
border-radius: 12px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-family: var(--font-title);
|
||||
@@ -301,7 +301,7 @@ body.dark-theme .topbar{
|
||||
gap: 0.85rem;
|
||||
min-height: 44px;
|
||||
padding: 0.75rem 0.85rem;
|
||||
border-radius: 12px;
|
||||
border-radius: 14px;
|
||||
color: rgba(230, 238, 245, 0.84);
|
||||
border: 1px solid transparent;
|
||||
transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
|
||||
@@ -337,11 +337,6 @@ body.dark-theme .topbar{
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.layout-sidebar app-sidebar{
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-header{
|
||||
display: flex;
|
||||
@@ -759,7 +754,7 @@ body.dark-theme .app-table .p-datatable-tbody > tr:hover > td{
|
||||
}
|
||||
|
||||
.p-dropdown-panel .p-dropdown-items{
|
||||
padding: 0.35rem;
|
||||
padding: 0.45rem;
|
||||
}
|
||||
|
||||
.p-dropdown-panel .p-dropdown-item{
|
||||
@@ -1997,48 +1992,6 @@ body.dark-theme .settings-actions--sticky{
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalize PrimeNG dropdown labels so selected values inherit the field style
|
||||
instead of rendering like nested inputs. */
|
||||
.p-dropdown{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 2.75rem;
|
||||
}
|
||||
|
||||
.p-dropdown .p-dropdown-label, .p-dropdown .p-dropdown-label.p-inputtext, .p-multiselect .p-multiselect-label{
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.25;
|
||||
letter-spacing: 0;
|
||||
text-transform: none;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.p-dropdown .p-dropdown-label.p-placeholder, .p-multiselect .p-multiselect-label.p-placeholder{
|
||||
color: var(--text-soft);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.p-dropdown .p-dropdown-trigger, .p-multiselect .p-multiselect-trigger{
|
||||
display: grid;
|
||||
place-items: center;
|
||||
align-self: stretch;
|
||||
color: var(--text-soft);
|
||||
}
|
||||
|
||||
.p-dropdown-panel .p-dropdown-item, .p-multiselect-panel .p-multiselect-item{
|
||||
font-size: 0.84rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
/* patch set: settings, dashboard, repository, logs */
|
||||
.inline-summary{
|
||||
@@ -2270,12 +2223,6 @@ body.dark-theme .inline-summary{
|
||||
}
|
||||
|
||||
|
||||
.app-auth-view{
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layout-footer a{
|
||||
@@ -2312,10 +2259,6 @@ body.dark-theme .inline-summary{
|
||||
box-shadow: 0 0 0 4px rgba(240, 180, 91, 0.14);
|
||||
}
|
||||
|
||||
.layout-footer--auth{
|
||||
margin-top: auto;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.api-connection-banner{
|
||||
position: fixed;
|
||||
@@ -2415,45 +2358,7 @@ body.dark-theme .api-connection-banner{
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
/* --- language selector + settings layout --- */
|
||||
.topbar__lang-picker{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.topbar__lang-select{
|
||||
min-height: 2.5rem;
|
||||
padding: 0.55rem 2.15rem 0.55rem 0.85rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: color-mix(in srgb, var(--surface-1) 92%, transparent);
|
||||
color: var(--text-main);
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
box-shadow: var(--shadow-sm);
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
.topbar__lang-select{
|
||||
min-width: 132px;
|
||||
}
|
||||
|
||||
.topbar__lang-select option{
|
||||
background: var(--surface-1);
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
body.dark-theme .topbar__lang-select{
|
||||
background: rgba(15, 21, 29, 0.92);
|
||||
color: var(--text-main);
|
||||
border-color: var(--border-color);
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
body.dark-theme .topbar__lang-select option{
|
||||
background: #1d2733;
|
||||
color: #dae4ec;
|
||||
}
|
||||
/* --- settings layout --- */
|
||||
|
||||
.settings-page-shell{
|
||||
display: grid;
|
||||
@@ -3584,3 +3489,329 @@ body.dark-theme .p-confirm-dialog .p-confirm-dialog-icon{
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* PrimeNG v20 compatibility bridge */
|
||||
.p-select,
|
||||
.p-dropdown,
|
||||
.p-multiselect,
|
||||
.p-inputtext,
|
||||
.p-textarea,
|
||||
.p-inputtextarea,
|
||||
textarea.p-inputtextarea,
|
||||
textarea.p-textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.p-button:not(.p-button-secondary):not(.p-button-help):not(.p-button-danger):not(.p-button-text):not(.p-button-outlined) {
|
||||
background: var(--primary);
|
||||
border-color: var(--primary);
|
||||
color: #f8fbff;
|
||||
}
|
||||
|
||||
body.dark-theme .p-button:not(.p-button-secondary):not(.p-button-help):not(.p-button-danger):not(.p-button-text):not(.p-button-outlined) {
|
||||
background: var(--primary);
|
||||
border-color: var(--primary);
|
||||
color: #17212b;
|
||||
}
|
||||
|
||||
.p-select,
|
||||
.p-dropdown,
|
||||
.p-textarea,
|
||||
.p-inputtextarea,
|
||||
.p-inputtext,
|
||||
textarea.p-inputtextarea,
|
||||
textarea.p-textarea {
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--border-strong);
|
||||
background: color-mix(in srgb, var(--surface-1) 90%, white 10%);
|
||||
color: var(--text-main);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
body.dark-theme .p-select,
|
||||
body.dark-theme .p-dropdown,
|
||||
body.dark-theme .p-textarea,
|
||||
body.dark-theme .p-inputtextarea,
|
||||
body.dark-theme .p-inputtext,
|
||||
body.dark-theme textarea.p-inputtextarea,
|
||||
body.dark-theme textarea.p-textarea {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: var(--text-main);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.p-select,
|
||||
.p-dropdown {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 2.95rem;
|
||||
}
|
||||
|
||||
.p-select .p-select-label,
|
||||
.p-select .p-select-label.p-placeholder,
|
||||
.p-dropdown .p-dropdown-label,
|
||||
.p-dropdown .p-dropdown-label.p-inputtext,
|
||||
.p-dropdown .p-dropdown-label.p-placeholder,
|
||||
.p-multiselect .p-multiselect-label,
|
||||
.p-multiselect .p-multiselect-label.p-placeholder {
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
padding: 0.78rem 0 0.78rem 1rem;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.96rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.35;
|
||||
letter-spacing: 0;
|
||||
text-transform: none;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.p-select .p-select-label.p-placeholder,
|
||||
.p-dropdown .p-dropdown-label.p-placeholder,
|
||||
.p-multiselect .p-multiselect-label.p-placeholder {
|
||||
font-weight: 400;
|
||||
color: var(--text-soft);
|
||||
}
|
||||
|
||||
.repository-toolbar .p-select .p-select-label,
|
||||
.repository-compare .p-select .p-select-label,
|
||||
.diff-configs-compare .p-select .p-select-label,
|
||||
.repository-toolbar .p-dropdown .p-dropdown-label,
|
||||
.repository-compare .p-dropdown .p-dropdown-label {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.p-select .p-select-dropdown,
|
||||
.p-dropdown .p-dropdown-trigger,
|
||||
.p-multiselect .p-multiselect-trigger {
|
||||
width: 2.85rem;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
align-self: stretch;
|
||||
color: var(--text-soft);
|
||||
flex: 0 0 2.85rem;
|
||||
}
|
||||
|
||||
.p-select.p-focus,
|
||||
.p-dropdown:not(.p-disabled).p-focus,
|
||||
.p-inputtext:enabled:focus,
|
||||
.p-textarea:enabled:focus,
|
||||
.p-inputtextarea:enabled:focus,
|
||||
textarea.p-inputtextarea:enabled:focus,
|
||||
textarea.p-textarea:enabled:focus {
|
||||
border-color: color-mix(in srgb, var(--blue) 72%, var(--border-strong));
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 18%, transparent);
|
||||
}
|
||||
|
||||
body.dark-theme .auth-card .p-inputtext,
|
||||
body.dark-theme .auth-card .p-password-input,
|
||||
body.dark-theme .auth-card .p-select,
|
||||
body.dark-theme .auth-card .p-textarea,
|
||||
body.dark-theme .auth-card .p-inputtextarea {
|
||||
color: var(--text-main);
|
||||
border-color: var(--border-color);
|
||||
background: rgba(255, 255, 255, 0.035);
|
||||
}
|
||||
|
||||
body.dark-theme .auth-card .p-inputtext::placeholder,
|
||||
body.dark-theme .auth-card .p-password-input::placeholder,
|
||||
body.dark-theme .auth-card .p-textarea::placeholder,
|
||||
body.dark-theme .auth-card .p-inputtextarea::placeholder {
|
||||
color: var(--text-soft);
|
||||
}
|
||||
|
||||
body.dark-theme .auth-card .p-inputtext:enabled:focus,
|
||||
body.dark-theme .auth-card .p-password-input:enabled:focus,
|
||||
body.dark-theme .auth-card .p-textarea:enabled:focus,
|
||||
body.dark-theme .auth-card .p-inputtextarea:enabled:focus {
|
||||
border-color: var(--blue);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 18%, transparent);
|
||||
}
|
||||
|
||||
.p-select-overlay,
|
||||
.p-dropdown-panel,
|
||||
.p-multiselect-panel,
|
||||
.p-component-overlay {
|
||||
backdrop-filter: blur(12px);
|
||||
background: color-mix(in srgb, var(--surface-1) 97%, white 3%);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--text-main);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
body.dark-theme .p-select-overlay,
|
||||
body.dark-theme .p-dropdown-panel,
|
||||
body.dark-theme .p-multiselect-panel,
|
||||
body.dark-theme .p-component-overlay {
|
||||
background: #1f2935;
|
||||
border-color: rgba(146, 170, 194, 0.2);
|
||||
}
|
||||
|
||||
.p-select-list,
|
||||
.p-dropdown-panel .p-dropdown-items,
|
||||
.p-multiselect-panel .p-multiselect-items {
|
||||
padding: 0.35rem;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
body.dark-theme .p-select-list,
|
||||
body.dark-theme .p-dropdown-panel .p-dropdown-items,
|
||||
body.dark-theme .p-multiselect-panel .p-multiselect-items {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.p-select-option,
|
||||
.p-dropdown-panel .p-dropdown-item,
|
||||
.p-multiselect-panel .p-multiselect-item {
|
||||
border-radius: 10px;
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.35;
|
||||
color: var(--text-main);
|
||||
transition: background-color 0.12s ease, color 0.12s ease;
|
||||
}
|
||||
|
||||
.p-select-option.p-focus,
|
||||
.p-select-option:hover,
|
||||
.p-dropdown-panel .p-dropdown-item.p-focus,
|
||||
.p-dropdown-panel .p-dropdown-item:hover,
|
||||
.p-multiselect-panel .p-multiselect-item.p-focus,
|
||||
.p-multiselect-panel .p-multiselect-item:hover {
|
||||
background: #dbe5f0;
|
||||
color: #13202c;
|
||||
}
|
||||
|
||||
.p-select-option.p-select-option-selected,
|
||||
.p-dropdown-panel .p-dropdown-item.p-highlight,
|
||||
.p-multiselect-panel .p-multiselect-item.p-highlight {
|
||||
background: #c8d8ea;
|
||||
color: #13202c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body.dark-theme .p-select-option,
|
||||
body.dark-theme .p-dropdown-panel .p-dropdown-item,
|
||||
body.dark-theme .p-multiselect-panel .p-multiselect-item {
|
||||
color: #dbe5ef;
|
||||
}
|
||||
|
||||
body.dark-theme .p-select-option.p-focus,
|
||||
body.dark-theme .p-select-option:hover,
|
||||
body.dark-theme .p-dropdown-panel .p-dropdown-item.p-focus,
|
||||
body.dark-theme .p-dropdown-panel .p-dropdown-item:hover,
|
||||
body.dark-theme .p-multiselect-panel .p-multiselect-item.p-focus,
|
||||
body.dark-theme .p-multiselect-panel .p-multiselect-item:hover {
|
||||
background: #314355;
|
||||
color: #f4f8fb;
|
||||
}
|
||||
|
||||
body.dark-theme .p-select-option.p-select-option-selected,
|
||||
body.dark-theme .p-dropdown-panel .p-dropdown-item.p-highlight,
|
||||
body.dark-theme .p-multiselect-panel .p-multiselect-item.p-highlight {
|
||||
background: #d9e1ea;
|
||||
color: #13202c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.p-textarea,
|
||||
.p-inputtextarea,
|
||||
textarea.p-textarea,
|
||||
textarea.p-inputtextarea {
|
||||
padding: 0.82rem 0.9rem;
|
||||
}
|
||||
|
||||
.router-dialog.p-dialog {
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--surface-1);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
body.dark-theme .router-dialog.p-dialog {
|
||||
border-color: color-mix(in srgb, var(--border-color) 65%, transparent);
|
||||
}
|
||||
|
||||
.router-dialog .p-dialog-header {
|
||||
padding: 1.1rem 1.2rem 0.95rem;
|
||||
background: linear-gradient(180deg, color-mix(in srgb, var(--surface-1) 98%, transparent), color-mix(in srgb, var(--surface-0) 98%, transparent));
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.router-dialog .p-dialog-content {
|
||||
padding: 0 1.2rem 1.2rem;
|
||||
background: color-mix(in srgb, var(--surface-0) 98%, transparent);
|
||||
}
|
||||
|
||||
.router-dialog .p-dialog-header-icons {
|
||||
align-self: flex-start;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.router-dialog-panel {
|
||||
background: color-mix(in srgb, var(--surface-0) 96%, transparent);
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.router-dialog .p-select,
|
||||
.router-dialog .p-textarea,
|
||||
.router-dialog .p-inputtextarea,
|
||||
.router-dialog .p-inputtext {
|
||||
background: color-mix(in srgb, var(--surface-1) 90%, transparent);
|
||||
}
|
||||
|
||||
body.dark-theme .router-dialog .p-select,
|
||||
body.dark-theme .router-dialog .p-textarea,
|
||||
body.dark-theme .router-dialog .p-inputtextarea,
|
||||
body.dark-theme .router-dialog .p-inputtext,
|
||||
body.dark-theme .router-dialog-panel {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.repository-toolbar__search .p-input-icon-left {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.repository-toolbar__search .p-input-icon-left > i {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0.9rem;
|
||||
transform: translateY(-50%);
|
||||
margin: 0;
|
||||
z-index: 1;
|
||||
color: var(--text-soft);
|
||||
pointer-events: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.repository-toolbar__search .p-input-icon-left > .p-inputtext {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 2.75rem;
|
||||
padding-left: 2.5rem;
|
||||
}
|
||||
|
||||
|
||||
body.dark-theme .p-toast .p-toast-summary,
|
||||
body.dark-theme .p-toast .p-toast-detail,
|
||||
body.dark-theme .p-toast .p-toast-message-icon,
|
||||
body.dark-theme .p-toast .p-toast-icon-close {
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.repository-table .p-paginator .p-paginator-pages .p-paginator-page,
|
||||
.repository-table .p-paginator .p-paginator-next,
|
||||
.repository-table .p-paginator .p-paginator-prev,
|
||||
.repository-table .p-paginator .p-select {
|
||||
min-width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
Reference in New Issue
Block a user