mirror of
https://github.com/farcasclaudiu/LanBackup.git
synced 2026-06-22 09:01:11 +03:00
missing component
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<span>
|
||||||
|
Backup configurations
|
||||||
|
</span>
|
||||||
|
<div class="pull-right mypointerlink">
|
||||||
|
<a (click)="doRefresh()" class="nounderline">
|
||||||
|
<i class="fa fa-refresh fa-fw" [ngClass]="{ 'fa-spin': isloading }" aria-hidden="true"></i> Refresh
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- modal trigger button -->
|
||||||
|
<button type="button" class="btn btn btn-success pull-right" data-toggle="modal" data-target="#myModal" *ngIf="isAdmin()" (click)="doNew()">
|
||||||
|
<i class="fa fa-plus" aria-hidden="true"></i> New Configuration
|
||||||
|
</button>
|
||||||
|
<!-- Modal EDIT -->
|
||||||
|
<div>
|
||||||
|
<app-modal #modalEdit id="modalEdit">
|
||||||
|
<div class="app-modal-header">
|
||||||
|
<button type="button" class="close" (click)="modalEdit.hide()">×</button>
|
||||||
|
<h4 class="modal-title">{{EditTitle}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="app-modal-body">
|
||||||
|
<form>
|
||||||
|
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="control-group">
|
||||||
|
<!-- Client IP -->
|
||||||
|
<label class="control-label" for="clientIP">Computer IP</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="clientIP" name="clientIP" placeholder="computer ip address" class="input-xlarge validate" [(ngModel)]="editItem.clientIP">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="control-group">
|
||||||
|
<!-- Src Folder -->
|
||||||
|
<label class="control-label" for="srcFolder">Source Folder</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="srcFolder" name="srcFolder" placeholder="source folder path" class="input-xlarge validate" [(ngModel)]="editItem.srcFolder">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6" class="control-group">
|
||||||
|
<!-- Dest Folder -->
|
||||||
|
<label class="control-label" for="destLanFolder">Destination Folder</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="destLanFolder" name="destLanFolder" placeholder="destination lan folder path" class="input-xlarge validate" [(ngModel)]="editItem.destLanFolder">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="control-group">
|
||||||
|
<!-- Src User -->
|
||||||
|
<label class="control-label" for="srcUser">Source user</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="srcUser" name="srcUser" placeholder="source user (john@computer)" class="input-xlarge validate" [(ngModel)]="editItem.srcUser">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6" class="control-group">
|
||||||
|
<!-- Dest User -->
|
||||||
|
<label class="control-label" for="destUser">Destination user</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="destUser" name="destUser" placeholder="destination user (mary@server)" class="input-xlarge validate" [(ngModel)]="editItem.destUser">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="control-group">
|
||||||
|
<!-- Src Pass -->
|
||||||
|
<label class="control-label" for="srcPass">Source password</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="password" id="srcPass" name="srcPass" placeholder="source pass (*****)" class="input-xlarge validate" [(ngModel)]="editItem.srcPass">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6" class="control-group">
|
||||||
|
<!-- Dest User -->
|
||||||
|
<label class="control-label" for="destPass">Destination password</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="password" id="destPass" name="destPass" placeholder="destination pass (*****)" class="input-xlarge validate" [(ngModel)]="editItem.destPass">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 control-group">
|
||||||
|
<!-- CRONTAB -->
|
||||||
|
<label class="control-label" for="crontab">Crontab shedule expression</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="crontab" name="crontab" placeholder="crontab expression" class="input-xlarge validate" [(ngModel)]="editItem.crontab">
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<p>to create expressions please lick <a href="http://www.cronmaker.com/" target="_blank">here</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1></h1>
|
||||||
|
<span>{{errorMsg}}</span>
|
||||||
|
<h1></h1>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="app-modal-footer">
|
||||||
|
<button type="button" class="btn btn-default pull-left" (click)="modalEdit.hide()">Close</button>
|
||||||
|
<button type="button" class="btn btn-success" (click)="doSave()">Save</button>
|
||||||
|
</div>
|
||||||
|
</app-modal>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- end Modal -->
|
||||||
|
<!-- Modal DELETE -->
|
||||||
|
<div>
|
||||||
|
<app-modal #modalDelete id="modalDelete">
|
||||||
|
<div class="app-modal-header">
|
||||||
|
<button type="button" class="close" (click)="modalDelete.hide()">×</button>
|
||||||
|
<h4 class="modal-title">Delete confirmation</h4>
|
||||||
|
</div>
|
||||||
|
<div class="app-modal-body">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Confim removal of {{editItem.clientIP}} from {{editItem.srcFolder}} to {{editItem.destLanFolder}}?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="app-modal-footer">
|
||||||
|
<button type="button" class="btn btn-default pull-left" (click)="modalDelete.hide()">Close</button>
|
||||||
|
<button type="button" class="btn btn-danger" (click)="doDeleteConfirm()">Confirm</button>
|
||||||
|
</div>
|
||||||
|
</app-modal>
|
||||||
|
</div>
|
||||||
|
<!-- end Modal -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tabledesc">
|
||||||
|
Here are all scheduled backups. <br />
|
||||||
|
Only "Admin" users can create, update, enable, disable and delete these. <br />
|
||||||
|
If you need to perform these actions and you can't, please contact your system administrator <a href="mailto:{{adminEmail}}">here</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="table-responsive tableminim well">
|
||||||
|
<table class="table table-hover table-fixed table-condensed table-striped anyLoadingTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Computer IP</th>
|
||||||
|
<th>Source</th>
|
||||||
|
<th>Destination</th>
|
||||||
|
<th>Details</th>
|
||||||
|
<th class="text-center">Logs</th>
|
||||||
|
<th class="text-center">Active</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr *ngFor="let backup of list.recs | paginate: { id: 'pagedList', itemsPerPage: pageSize, currentPage: currentPage, totalItems: totalPages }">
|
||||||
|
<td>{{backup.id}}</td>
|
||||||
|
<td>{{backup.clientIP}}</td>
|
||||||
|
<td>{{backup.srcFolder}}</td>
|
||||||
|
<td>{{backup.destLanFolder}}</td>
|
||||||
|
<td>{{backup.crontab}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="text-center">
|
||||||
|
<button type="button" class="btn btn-xs btn-default" (click)="seeLogs(backup)">
|
||||||
|
<i class="fa fa-list-alt" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="text-center switchAdjust">
|
||||||
|
<ngSwitch [(ngModel)]="backup.isActive" (change)="toggleActive(backup)" [disabled]="!isAdmin()" size="small" class=""></ngSwitch>
|
||||||
|
<!--<input type="checkbox" [ngModel]="backup.isActive" (change)="toggleActive(backup)" checked data-toggle="toggle" data-size="mini" data-onstyle="info" [disabled]="!isAdmin()">-->
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="text-center">
|
||||||
|
<button type="button" class="btn btn-default btn-xs" (click)="doEdit(backup)" [disabled]="!isAdmin()">
|
||||||
|
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="text-center">
|
||||||
|
<button type="button" class="btn btn-danger btn-xs" (click)="doDelete(backup)" [disabled]="!isAdmin()">
|
||||||
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="spinnercontainer row" [ngClass]="{ 'hidden': !isloading }">
|
||||||
|
<div class="myspinnerback">
|
||||||
|
<div class="myspinner">
|
||||||
|
<i class="fa fa-refresh fa-3x fa-fw fa-spin text-primary" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--pagination-->
|
||||||
|
<div class="panel-footer table-footer">
|
||||||
|
<div class="has-text-centered">
|
||||||
|
<pagination-controls (pageChange)="getPage($event)" id="pagedList" previousLabel="«" nextLabel="»"></pagination-controls>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from '@angular/core';
|
||||||
|
import { BackupConfiguration } from '../../model/BackupConfiguration';
|
||||||
|
import { SaveResult } from '../../model/SaveResult';
|
||||||
|
import { PaginatedList } from '../../model/PaginatedList';
|
||||||
|
import { WebApiService } from '../../services/webapi.service';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { AuthenticationService } from '../../services/authentication.service';
|
||||||
|
import { ModalComponent } from '../../shared/modal/modal.component';
|
||||||
|
|
||||||
|
import { LoggerService } from '../../services/logger.service';
|
||||||
|
import { ToastNotification, ToastType } from '../../services/notifications.service';
|
||||||
|
import { MessageService, Messages } from '../../services/message.service';
|
||||||
|
|
||||||
|
|
||||||
|
import { GlobalRef } from '../../shared/global/global-ref';
|
||||||
|
|
||||||
|
|
||||||
|
const EDIT_BACKUP_TITLE = "Edit backup configuration";
|
||||||
|
const NEW_BACKUP_TITLE = "Create new backup configuration";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'backups',
|
||||||
|
templateUrl: './backups.component.html',
|
||||||
|
styleUrls: ['./backups.component.css'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class BackupsComponent implements OnInit {
|
||||||
|
|
||||||
|
@ViewChild('modalEdit')
|
||||||
|
public readonly modalEdit: ModalComponent;
|
||||||
|
|
||||||
|
@ViewChild('modalDelete')
|
||||||
|
public readonly modalDelete: ModalComponent;
|
||||||
|
|
||||||
|
public list: PaginatedList<BackupConfiguration> = new PaginatedList<BackupConfiguration>(null);
|
||||||
|
|
||||||
|
public EditTitle = NEW_BACKUP_TITLE;
|
||||||
|
public editItem: BackupConfiguration = new BackupConfiguration(null);
|
||||||
|
private prevSaveItem: BackupConfiguration;
|
||||||
|
|
||||||
|
|
||||||
|
currentPage: number = 1;
|
||||||
|
pageSize: number = 5;
|
||||||
|
totalPages: number;
|
||||||
|
public isloading = false;
|
||||||
|
issaving = true;
|
||||||
|
isNew = false;
|
||||||
|
adminEmail = '';
|
||||||
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private webApi: WebApiService,
|
||||||
|
private _service: AuthenticationService,
|
||||||
|
private messageService: MessageService,
|
||||||
|
private log: LoggerService,
|
||||||
|
private _global: GlobalRef
|
||||||
|
) {
|
||||||
|
this.adminEmail = _global.nativeGlobal.clientSettings.admin_email;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
showToast(toast: ToastNotification) {
|
||||||
|
this.messageService.broadcast(Messages.MESSAGE_NOTIFY, toast);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.doRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
seeLogs(item: BackupConfiguration) {
|
||||||
|
//TODO - show schedule logs
|
||||||
|
this.log.debug('see logs ' + item);
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin() {
|
||||||
|
return this._service.checkIsAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
doDelete(item: BackupConfiguration) {
|
||||||
|
if (this.isAdmin()) {
|
||||||
|
//
|
||||||
|
this.editItem = item;
|
||||||
|
this.log.debug('do delete ' + item);
|
||||||
|
this.modalDelete.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doDeleteConfirm() {
|
||||||
|
//remove from webApi
|
||||||
|
this.issaving = true;
|
||||||
|
this.webApi.deleteBackup(this.editItem)
|
||||||
|
.subscribe(
|
||||||
|
(data) => {
|
||||||
|
//update list
|
||||||
|
this.updateListLocal(this.editItem, true);
|
||||||
|
this.modalDelete.hide();
|
||||||
|
this.showToast({ title: "Delete success", body: "Backup configuration was deleted", type: ToastType.success });
|
||||||
|
this.getPage(this.currentPage);
|
||||||
|
this.issaving = false;
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
this.issaving = false;
|
||||||
|
this.showToast({ title: "Delete error", body: err, type: ToastType.error });
|
||||||
|
this.log.error(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
doNew() {
|
||||||
|
if (this.isAdmin()) {
|
||||||
|
this.EditTitle = NEW_BACKUP_TITLE;
|
||||||
|
this.editItem = new BackupConfiguration(null);
|
||||||
|
this.isNew = true;
|
||||||
|
this.modalEdit.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doEdit(item: BackupConfiguration) {
|
||||||
|
if (this.isAdmin()) {
|
||||||
|
//
|
||||||
|
this.EditTitle = EDIT_BACKUP_TITLE;
|
||||||
|
this.prevSaveItem = this.getPrevItem(item.id);
|
||||||
|
this.editItem = jQuery.extend(true, {}, item);//create deep copy of original edited item
|
||||||
|
this.isNew = false;
|
||||||
|
this.log.debug('do edit ' + JSON.stringify(item));
|
||||||
|
this.modalEdit.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleActive(item: BackupConfiguration) {
|
||||||
|
if (this.isAdmin()) {
|
||||||
|
//
|
||||||
|
this.issaving = true;
|
||||||
|
this.prevSaveItem = this.getPrevItem(item.id);
|
||||||
|
item.isActive = !item.isActive;
|
||||||
|
this.log.debug('do toggle active ' + item.isActive);
|
||||||
|
var strAction = item.isActive ? "activated" : "disabled";
|
||||||
|
//save into webapi
|
||||||
|
this.callWebApiSave(item, false,
|
||||||
|
"Update succes", `Backup configuration has been ${strAction}!`,
|
||||||
|
"Update error", null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doSave() {
|
||||||
|
// call API to save
|
||||||
|
this.issaving = true;
|
||||||
|
this.log.debug('saving');
|
||||||
|
this.callWebApiSave(this.editItem, this.isNew,
|
||||||
|
this.isNew ? "Create success" : "Edit success",
|
||||||
|
this.isNew ? "The new backup configuration has been added!" : "The backup has been updated!",
|
||||||
|
this.isNew ? "Create error" : "Edit error",
|
||||||
|
() => {
|
||||||
|
this.modalEdit.hide();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
callWebApiSave(item: BackupConfiguration, isNew: boolean,
|
||||||
|
titleSucces: string, msgSucces: string,
|
||||||
|
titleErr: string, callback) {
|
||||||
|
this.webApi.saveBackup(item, isNew)
|
||||||
|
.subscribe(
|
||||||
|
(data) => {
|
||||||
|
//update list
|
||||||
|
if (!isNew) {
|
||||||
|
this.updateListLocal(data, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.doRefresh();
|
||||||
|
}
|
||||||
|
if (callback) callback();
|
||||||
|
this.showToast({ title: titleSucces, body: msgSucces, type: ToastType.success });
|
||||||
|
this.issaving = false;
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
this.issaving = false;
|
||||||
|
this.updateListLocal(this.prevSaveItem, false);
|
||||||
|
this.showToast({ title: titleErr, body: err, type: ToastType.error });
|
||||||
|
this.log.error(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateListLocal(data: BackupConfiguration, todelete: boolean) {
|
||||||
|
for (let ix = 0; ix < this.list.recs.length; ix++) {
|
||||||
|
if (this.list.recs[ix].id == data.id) {
|
||||||
|
if (todelete) {
|
||||||
|
this.log.debug('local delete');
|
||||||
|
this.list.recs.splice(ix, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.log.debug('local replace');
|
||||||
|
this.list.recs.splice(ix, 1, data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrevItem(id: string) {
|
||||||
|
for (let ix = 0; ix < this.list.recs.length; ix++) {
|
||||||
|
if (this.list.recs[ix].id == id) {
|
||||||
|
return this.list.recs[ix];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
doRefresh() {
|
||||||
|
this.getPage(this.currentPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPage(page: number) {
|
||||||
|
this.isloading = true;
|
||||||
|
this.webApi.getBackupsPage(page, this.pageSize).subscribe(
|
||||||
|
(data) => {
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.list = data;
|
||||||
|
this.currentPage = page
|
||||||
|
this.totalPages = data.tp * this.pageSize;
|
||||||
|
this.isloading = false;
|
||||||
|
}, 300);//TODO - remove - induced delay
|
||||||
|
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
this.log.error(err);
|
||||||
|
this.isloading = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user