This repository has been archived on 2026-04-14. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
routeros_backup_next/frontend/src/app/features/files/files-page.component.html
Mateusz Gruszczyński ff7dbcb4e4 first commit
2026-04-12 21:26:12 +02:00

187 lines
12 KiB
HTML

<app-page-header [eyebrow]="'files.eyebrow' | translate" [title]="'files.title' | translate" [subtitle]="'files.subtitle' | translate">
<div header-actions class="header-actions-row">
<button pButton type="button" icon="pi pi-download" [label]="'files.downloadZip' | translate" [loading]="bulkBusy && selectedIds.length > 0" (click)="bulkDownload()" [disabled]="selectedIds.length===0"></button>
<button pButton type="button" severity="danger" icon="pi pi-trash" [label]="'common.delete' | translate" [loading]="bulkBusy && selectedIds.length > 0" (click)="bulkDelete()" [disabled]="selectedIds.length===0"></button>
</div>
</app-page-header>
<div class="stats-grid compact-grid">
<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>
</div>
<app-section-card [title]="'files.filtersTitle' | translate" [subtitle]="'files.filtersSubtitle' | translate">
<div class="repository-toolbar">
<span class="form-field repository-toolbar__search">
<label>{{ 'files.searchLabel' | translate }}</label>
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<input pInputText [(ngModel)]="search" [placeholder]="'files.searchPlaceholder' | translate" />
</span>
</span>
<span class="form-field">
<label>{{ 'files.typeLabel' | translate }}</label>
<p-dropdown [options]="typeOptions" [(ngModel)]="backupType" optionLabel="label" optionValue="value"></p-dropdown>
</span>
<span class="form-field">
<label>{{ 'files.routerLabel' | translate }}</label>
<p-dropdown [options]="routerOptions" [(ngModel)]="routerId" optionLabel="label" optionValue="value"></p-dropdown>
</span>
<span class="form-field">
<label>{{ 'files.sortLabel' | translate }}</label>
<p-dropdown [options]="sortOptions" [(ngModel)]="sortBy" optionLabel="label" optionValue="value"></p-dropdown>
</span>
<span class="form-field">
<label>{{ 'files.orderLabel' | translate }}</label>
<p-dropdown [options]="orderOptions" [(ngModel)]="order" optionLabel="label" optionValue="value"></p-dropdown>
</span>
<div class="filters-actions repository-toolbar__actions">
<button pButton type="button" [label]="'common.apply' | translate" icon="pi pi-filter" [loading]="loading" (click)="load()"></button>
<button pButton type="button" severity="secondary" [label]="'common.reset' | translate" icon="pi pi-refresh" (click)="resetFilters()"></button>
</div>
</div>
<div class="repository-compare">
<div class="repository-compare__header">
<div>
<strong>{{ 'files.compareTitle' | translate }}</strong>
<p>{{ 'files.compareSubtitle' | translate }}</p>
</div>
<div class="repository-compare__status">
<p-tag [value]="exportCount + ' ' + ('files.exportPoolLabel' | translate)" severity="success"></p-tag>
<p-tag [value]="compareContextLabel" [severity]="compareReady ? 'info' : 'secondary'"></p-tag>
</div>
</div>
<div class="repository-compare__grid">
<div class="compare-strip__slot repository-compare__slot">
<label>{{ 'files.compareOlder' | translate }}</label>
<p-dropdown [options]="compareOptions" [(ngModel)]="compareLeftId" optionLabel="label" optionValue="value" [placeholder]="'files.pickOlder' | translate"></p-dropdown>
</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 [options]="compareOptions" [(ngModel)]="compareRightId" optionLabel="label" optionValue="value" [placeholder]="'files.pickNewer' | translate"></p-dropdown>
</div>
<div class="compare-strip__actions repository-compare__actions">
<button pButton type="button" severity="secondary" icon="pi pi-star" [label]="'files.compareLatestPair' | translate" (click)="fillLatestPair()" [disabled]="exportFiles.length < 2"></button>
<button pButton type="button" severity="help" icon="pi pi-code" [label]="'files.compareSelected' | translate" (click)="openStructuredDiff()" [disabled]="!compareReady" [loading]="compareBusy"></button>
</div>
</div>
</div>
</app-section-card>
<app-section-card class="repository-table-section" [title]="'files.tableTitle' | translate" [subtitle]="'files.tableSubtitle' | translate">
<p-table [value]="files" [(selection)]="selected" dataKey="id" [rows]="10" [loading]="loading" [paginator]="files.length > 10" responsiveLayout="scroll" styleClass="app-table repository-table">
<ng-template pTemplate="header">
<tr>
<th style="width:3rem"></th>
<th>{{ 'files.fileColumn' | translate }}</th>
<th>{{ 'files.routerColumn' | translate }}</th>
<th>{{ 'files.typeColumn' | translate }}</th>
<th>{{ 'files.createdColumn' | translate }}</th>
<th>{{ 'files.sizeColumn' | translate }}</th>
<th>{{ 'files.compareColumn' | translate }}</th>
<th>{{ 'files.actionsColumn' | translate }}</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-item>
<tr [attr.data-compare-role]="compareRole(item)">
<td><p-tableCheckbox [value]="item"></p-tableCheckbox></td>
<td>
<div class="table-primary">{{ item.file_name }}</div>
<small class="table-secondary">{{ 'files.checksum' | translate }}: {{ checksumShort(item.checksum) }}</small>
</td>
<td>
<div class="table-primary">{{ item.router_name || item.router_id }}</div>
<small class="table-secondary">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>
<div class="table-primary">{{ item.created_at | date: 'dd.MM.yyyy HH:mm' }}</div>
<small class="table-secondary">{{ relativeAge(item.created_at) }}</small>
</td>
<td>
<div class="table-primary">{{ formatBytes(item.file_size) }}</div>
<small class="table-secondary">{{ item.backup_type === 'export' ? '.rsc' : '.backup' }}</small>
</td>
<td>
<div class="table-actions table-actions--stack" *ngIf="item.backup_type === 'export'; else noCompare">
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="secondary" icon="pi pi-arrow-left" [label]="'files.setOlder' | translate" (click)="assignCompare('left', item)"></button>
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="secondary" icon="pi pi-arrow-right" [label]="'files.setNewer' | translate" (click)="assignCompare('right', item)"></button>
<button pButton type="button" size="small" styleClass="table-action-btn table-action-btn--wide" severity="help" icon="pi pi-code" [label]="'files.latestForRouter' | translate" (click)="compareClosestForRouter(item)"></button>
</div>
<ng-template #noCompare>
<small class="table-secondary">{{ 'files.binaryNoCompare' | translate }}</small>
</ng-template>
</td>
<td>
<div class="table-actions table-actions--labels table-actions--stack">
<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 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>
</tr>
</ng-template>
</p-table>
</app-section-card>
<p-dialog [(visible)]="previewVisible" [modal]="true" [header]="previewTitle || ('files.previewDialogTitle' | translate)" [style]="{ width: 'min(1100px, 92vw)' }" styleClass="preview-dialog">
<pre class="code-preview preview-dialog__content">{{ viewedExport }}</pre>
</p-dialog>
<p-dialog [(visible)]="diffVisible" [modal]="true" [header]="'files.diffDialogTitle' | translate" [style]="{ width: 'min(1420px, 96vw)' }" styleClass="preview-dialog preview-dialog--diff">
<div class="diff-layout" *ngIf="diffData as diff">
<div class="diff-layout__summary">
<div>
<div class="table-primary">{{ diff.left_file_name }}</div>
<small class="table-secondary">{{ 'files.compareOlder' | translate }}</small>
</div>
<div class="diff-layout__summary-arrow"><i class="pi pi-arrow-right"></i></div>
<div>
<div class="table-primary">{{ diff.right_file_name }}</div>
<small class="table-secondary">{{ 'files.compareNewer' | translate }}</small>
</div>
<div class="diff-stats" *ngIf="diff.stats">
<span class="diff-stats__pill diff-stats__pill--added">+{{ diff.stats.added }}</span>
<span class="diff-stats__pill diff-stats__pill--removed">-{{ diff.stats.removed }}</span>
<span class="diff-stats__pill diff-stats__pill--modified">~{{ diff.stats.modified }}</span>
</div>
<div class="dialog-actions preview-dialog__actions">
<button pButton type="button" severity="secondary" icon="pi pi-align-left" [label]="'files.openPlainDiff' | translate" (click)="diffText = diff.diff_text"></button>
<button pButton type="button" severity="help" icon="pi pi-external-link" [label]="'files.openHtmlDiff' | translate" (click)="openHtmlDiff()"></button>
</div>
</div>
<div class="github-diff" *ngIf="diff.lines?.length; else plainDiffFallback">
<div class="github-diff__row" *ngFor="let line of diff.lines" [attr.data-type]="line.type">
<div class="github-diff__cell github-diff__cell--left">
<span class="github-diff__number">{{ line.left_number || '' }}</span>
<pre>{{ line.left_text || ' ' }}</pre>
</div>
<div class="github-diff__cell github-diff__cell--right">
<span class="github-diff__number">{{ line.right_number || '' }}</span>
<pre>{{ line.right_text || ' ' }}</pre>
</div>
</div>
</div>
<ng-template #plainDiffFallback>
<pre class="code-preview preview-dialog__content">{{ diff.diff_text }}</pre>
</ng-template>
</div>
</p-dialog>