mirror of
https://github.com/MikroWizard/mikrofront.git
synced 2025-12-06 01:59:29 +00:00
feat: settings redesign and core improvements
- Redesign settings interface with improved UX - Enhanced dashboard functionality - Improved device detail views - Updated core data providers - Minor snippet management improvements
This commit is contained in:
parent
07808822f7
commit
433dcff5db
9 changed files with 1290 additions and 246 deletions
|
|
@ -278,13 +278,14 @@ export class dataProvider {
|
|||
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/update_save_group", data);
|
||||
}
|
||||
|
||||
get_snippets(name:string,desc:string,content:string,page:number=0,size:number=1000){
|
||||
get_snippets(name:string,desc:string,content:string,page:number=0,size:number=1000,limit:any=false){
|
||||
var data={
|
||||
'name':name,
|
||||
'description':desc,
|
||||
'content':content,
|
||||
'page':page,
|
||||
'size':size
|
||||
'size':size,
|
||||
'limit':limit
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/list", data);
|
||||
}
|
||||
|
|
@ -601,6 +602,34 @@ export class dataProvider {
|
|||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dhcp-history/get", data);
|
||||
}
|
||||
|
||||
getNetworkMap(){
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/networkmap/get", {});
|
||||
}
|
||||
|
||||
bulk_add_devices(devices: any[]){
|
||||
var data = {
|
||||
'devices': devices
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/bulk_add", data);
|
||||
}
|
||||
|
||||
bulk_add_status(taskId: string){
|
||||
var data = {
|
||||
'taskId': taskId
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/bulk_add_status", data);
|
||||
}
|
||||
|
||||
group_firmware_action(groupId: number, action: string){
|
||||
var data = {
|
||||
'groupId': groupId,
|
||||
'action': action
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/firmware_action", data);
|
||||
}
|
||||
|
||||
|
||||
////
|
||||
//// End api funcs
|
||||
////
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
<c-row *ngIf="stats">
|
||||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card *ngIf="stats" class="mb-1">
|
||||
<c-card class="mb-1">
|
||||
<c-card-header>Past 24 Hour Statics</c-card-header>
|
||||
<c-card-body>
|
||||
<c-row>
|
||||
<c-col md="12" xl="12" xs="12">
|
||||
<c-row>
|
||||
<c-row *ngIf="!stats">
|
||||
<c-col class="mb-sm-1 mb-0" *ngFor="let item of [1,2,3,4,5]">
|
||||
<c-card class="mb-1">
|
||||
<c-card-body>
|
||||
<div class="placeholder-glow">
|
||||
<div class="placeholder col-3 mb-2" style="height: 40px;"></div>
|
||||
<div class="placeholder col-6"></div>
|
||||
</div>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<c-row *ngIf="stats">
|
||||
<c-col class="mb-sm-1 mb-0">
|
||||
<c-widget-stat-f [title]="'Failed Logins'" class="mb-1" color="danger" padding
|
||||
value="{{stats['FailedLogins']}}">
|
||||
|
|
@ -53,7 +65,17 @@
|
|||
<c-col xs>
|
||||
<c-row>
|
||||
<c-col md="12" xl="12" xs="12">
|
||||
<c-row>
|
||||
<c-row *ngIf="!stats">
|
||||
<c-col class="mb-0 pb-0" *ngFor="let item of [1,2,3,4,5]">
|
||||
<div class="border-start border-start-4 border-start-info pt-1 px-3 mb-1">
|
||||
<div class="placeholder-glow">
|
||||
<div class="placeholder col-8"></div>
|
||||
<div class="placeholder col-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<c-row *ngIf="stats">
|
||||
<c-col class="mb-0 pb-0">
|
||||
<div class="border-start border-start-4 border-start-info pt-1 px-3 mb-1">
|
||||
<div class="text-medium-emphasis small">Total users</div>
|
||||
|
|
@ -120,16 +142,28 @@
|
|||
</form>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<c-chart [data]="chart_data" [options]="options" [height]="250" type="line">
|
||||
<div *ngIf="!chart_data.datasets" style="height: 250px;">
|
||||
<div class="placeholder-glow" style="height: 100%;">
|
||||
<div class="placeholder col-12" style="height: 250px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<c-chart *ngIf="chart_data.datasets" [data]="chart_data" [options]="options" [height]="250" type="line">
|
||||
</c-chart>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
<c-row>
|
||||
<c-col xl="6" *ngIf="stats" lg="12" class="h-100" style="min-height: 160px!important;display: grid">
|
||||
<c-col xl="6" lg="12" class="h-100" style="min-height: 160px!important;display: grid">
|
||||
<c-card class="mb-1 p-1 h-100" style="padding-left: 5px!important;">
|
||||
<div class="my-1">
|
||||
<h4 style="display: inline-block;">Version and Serial information</h4>
|
||||
|
||||
</div>
|
||||
<div *ngIf="!stats">
|
||||
<div class="placeholder-glow">
|
||||
<div class="placeholder col-8"></div>
|
||||
<div class="placeholder col-6"></div>
|
||||
<div class="placeholder col-10"></div>
|
||||
<div class="placeholder col-7"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="!stats['license']" class="my-1">
|
||||
<div style="display: inline-block;margin-right: 5px;">
|
||||
|
|
@ -199,8 +233,18 @@
|
|||
</c-card>
|
||||
</c-col>
|
||||
<c-col xl="6" lg="12" class="h-100" style="min-height: 160px!important;display: grid;">
|
||||
<c-card class="h-100" *ngIf="stats" style="padding: 0!important;margin: 0!important;">
|
||||
<c-carousel [dark]="true" [animate]="false" [wrap]="false" [interval]="1000000">
|
||||
<c-card class="h-100" style="padding: 0!important;margin: 0!important;">
|
||||
<div *ngIf="!stats" style="padding: 20px;">
|
||||
<div class="placeholder-glow">
|
||||
<div class="placeholder col-4" style="height: 150px; float: left; margin-right: 20px;"></div>
|
||||
<div class="placeholder col-7">
|
||||
<div class="placeholder col-12"></div>
|
||||
<div class="placeholder col-10"></div>
|
||||
<div class="placeholder col-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<c-carousel *ngIf="stats" [dark]="true" [animate]="false" [wrap]="false" [interval]="1000000">
|
||||
<c-carousel-indicators></c-carousel-indicators>
|
||||
<c-carousel-inner>
|
||||
<c-carousel-item style="display: flex;" *ngFor="let slide of stats['blog']; index as i;">
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import { ClipboardModule } from "@angular/cdk/clipboard";
|
|||
ReactiveFormsModule,
|
||||
ButtonModule,
|
||||
TemplateIdDirective,
|
||||
ButtonModule,
|
||||
ButtonGroupModule,
|
||||
ChartjsModule,
|
||||
CarouselModule,
|
||||
|
|
|
|||
|
|
@ -509,6 +509,7 @@ export class DeviceComponent implements OnInit, OnDestroy {
|
|||
// loop in dhcp_server_data and create a new object with the data for chart for each dhcp server
|
||||
_self.reloading = false;
|
||||
_self.dhcp_server_data.forEach((element:any) => {
|
||||
if(element.pools.length>0){
|
||||
var pooldata=element.pools[0];
|
||||
element.chartpools = {
|
||||
labels: ['Used', 'Free'],
|
||||
|
|
@ -517,6 +518,7 @@ export class DeviceComponent implements OnInit, OnDestroy {
|
|||
data: [pooldata.used_ips, pooldata.available_ips]
|
||||
}]
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,230 +1,510 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>Firmware Manager</c-card-header>
|
||||
<c-card-body>
|
||||
<c-input-group class="mb-3">
|
||||
<h5>Firmware in repository:</h5>
|
||||
<div class="settings-container">
|
||||
<c-card class="settings-card">
|
||||
<c-card-header class="settings-header">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fa-solid fa-cog me-2 text-primary"></i>
|
||||
<h4 class="mb-0">System Settings</h4>
|
||||
</div>
|
||||
<c-badge color="info" class="fs-6">Admin Panel</c-badge>
|
||||
</div>
|
||||
</c-card-header>
|
||||
|
||||
<div class="settings-tabs">
|
||||
<button class="tab-link" [class.active]="activeTab === 'firmware'" (click)="activeTab = 'firmware'">
|
||||
<i class="fa-solid fa-microchip me-2"></i>Firmware Manager
|
||||
</button>
|
||||
<button class="tab-link" [class.active]="activeTab === 'system'" (click)="activeTab = 'system'">
|
||||
<i class="fa-solid fa-server me-2"></i>System Configuration
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Firmware Tab -->
|
||||
<c-card-body *ngIf="activeTab === 'firmware'" class="tab-content">
|
||||
<!-- Repository Status -->
|
||||
<div class="status-section mb-4">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h5 class="section-title mb-0">
|
||||
<i class="fa-solid fa-database me-2 text-success"></i>Firmware Repository
|
||||
<i class="fa-solid fa-info-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'Local firmware repository stores RouterOS versions for offline installation. Devices can be updated without internet access.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h5>
|
||||
<c-badge color="success" class="fs-6">
|
||||
<i class="fa-solid fa-check-circle me-1"></i>{{source.length}} Versions Available
|
||||
</c-badge>
|
||||
</div>
|
||||
<div class="info-banner mb-3">
|
||||
<i class="fa-solid fa-lightbulb me-2"></i>
|
||||
<span><strong>Tip:</strong> Keep multiple firmware versions for compatibility. Always test updates on non-critical devices first.</span>
|
||||
</div>
|
||||
|
||||
<gui-grid [autoResizeWidth]="true" [source]="source" [columnMenu]="columnMenu" [sorting]="sorting"
|
||||
[infoPanel]="infoPanel" [autoResizeWidth]=true [paging]="paging">
|
||||
[infoPanel]="infoPanel" [paging]="paging" class="compact-grid">
|
||||
<gui-grid-column header="Version" field="version">
|
||||
<ng-template let-value="item.version" let-item="item" let-index="index">
|
||||
{{value}} </ng-template>
|
||||
<c-badge color="primary" class="version-badge">{{value}}</c-badge>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="arch" field="architecture">
|
||||
<gui-grid-column header="Architecture" field="architecture">
|
||||
<ng-template let-value="item.architecture" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
<c-badge color="secondary">{{value}}</c-badge>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="sha256" field="sha256">
|
||||
<gui-grid-column header="SHA256" field="sha256">
|
||||
<ng-template let-value="item.sha256" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
<small class="text-muted font-monospace">{{value.substring(0, 16)}}...</small>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Actions" width="120" field="action">
|
||||
<gui-grid-column header="Actions" width="100" field="action" align="CENTER">
|
||||
<ng-template let-value="item.id" let-item="item" let-index="index">
|
||||
<button cButton color="danger" size="sm" (click)="delete_fimrware(item);"><i
|
||||
class="fa-regular fa-trash-can"></i></button>
|
||||
<button cButton color="danger" size="sm" variant="outline" (click)="delete_fimrware(item)" title="Delete firmware">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
</c-input-group>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<table>
|
||||
<td>
|
||||
<span>Add new Permission</span>
|
||||
</td>
|
||||
<td *ngIf="loading">
|
||||
<button cButton class="m-1" disabled>
|
||||
<c-spinner aria-hidden="true" size="sm"></c-spinner>
|
||||
Fetching Information from mikrotik website...
|
||||
</button>
|
||||
</td>
|
||||
<td *ngIf="!loading">
|
||||
<mat-form-field>
|
||||
<mat-select cFormControl [(ngModel)]="firmtodownload" placeholder="Select Version For Download Group"
|
||||
#singleSelect>
|
||||
<mat-option>
|
||||
<ngx-mat-select-search placeholderLabel="Search"
|
||||
[hideClearSearchButton]="true"></ngx-mat-select-search>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let firm of firms" [value]="firm">
|
||||
<!-- Download Section -->
|
||||
<div class="download-section mb-4">
|
||||
<div class="section-card">
|
||||
<div class="section-header">
|
||||
<i class="fa-solid fa-download me-2 text-primary"></i>
|
||||
<span class="fw-semibold">Download New Firmware</span>
|
||||
<i class="fa-solid fa-question-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'Downloads firmware from MikroTik servers. Requires internet access. Downloaded files are verified for integrity.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</div>
|
||||
<div class="warning-banner mb-2" *ngIf="!loading">
|
||||
<i class="fa-solid fa-wifi me-2"></i>
|
||||
<span><strong>Internet Required:</strong> Downloads from mikrotik.com. Ensure stable connection and access to mikrotik.com domain.</span>
|
||||
</div>
|
||||
<c-row class="g-3 mt-2" *ngIf="!loading">
|
||||
<c-col md="8">
|
||||
<div class="search-select-wrapper">
|
||||
<label class="form-label">Select RouterOS Version</label>
|
||||
<input cFormControl
|
||||
[(ngModel)]="firmwareSearch"
|
||||
(input)="filterFirmwares($event)"
|
||||
(focus)="showFirmwareDropdown = true"
|
||||
(blur)="hideFirmwareDropdown()"
|
||||
placeholder="Search and select version..."
|
||||
class="search-input"
|
||||
autocomplete="off" />
|
||||
<div *ngIf="showFirmwareDropdown && filteredFirmwares.length > 0" class="search-dropdown">
|
||||
<div *ngFor="let firm of filteredFirmwares"
|
||||
class="search-option"
|
||||
(mousedown)="selectFirmware(firm)">
|
||||
{{firm}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</td>
|
||||
<td>
|
||||
<button *ngIf="!loading" cButton color="primary" (click)="ConfirmModalVisible=true">Download to
|
||||
repository</button>
|
||||
<!-- <button *ngIf="SelectedUser['action']=='add'" cButton color="primary" (click)="loading=!loading">++</button> -->
|
||||
</td>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
<c-input-group class="mb-3">
|
||||
<label cInputGroupText for="inputGroupSelect01">
|
||||
V6 Firmware update Behavior
|
||||
</label>
|
||||
<select cSelect [(ngModel)]="updateBehavior" id="inputGroupSelect01">
|
||||
<option>Choose...</option>
|
||||
<option value="keep">Keep v6 and don't update to v7</option>
|
||||
<option value="update">install latest</option>
|
||||
</select>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Choose how Mikrowizard should update old v6 firmwares</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
<c-input-group class="mb-3">
|
||||
<label cInputGroupText for="inputGroupSelect01">
|
||||
Firmware version to install
|
||||
</label>
|
||||
<select cSelect [(ngModel)]="firmwaretoinstall" id="inputGroupSelect01">
|
||||
<option>Choose...</option>
|
||||
<option *ngFor="let f of available_firmwares" [value]="f">{{f}}</option>
|
||||
|
||||
</select>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* The version of firmware to install routers</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
<c-input-group *ngIf="updateBehavior=='keep'" class="mb-3">
|
||||
<label cInputGroupText for="inputGroupSelect01">
|
||||
Firmware version v6 to install
|
||||
</label>
|
||||
<select cSelect [(ngModel)]="firmwaretoinstallv6" id="inputGroupSelect01">
|
||||
<option>Choose...</option>
|
||||
<option *ngFor="let f of available_firmwaresv6" [value]="f">{{f}}</option>
|
||||
</select>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* The version of firmware to install on V6 routers</c-form-feedback>
|
||||
</c-input-group>
|
||||
<button cButton color="primary" (click)="saveFirmwareSetting()">Save</button>
|
||||
</c-card-body>
|
||||
|
||||
</c-card>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>System Settings</c-card-header>
|
||||
<c-card-body *ngIf="!SysConfigloading">
|
||||
|
||||
<c-input-group class="mt-3">
|
||||
<span cInputGroupText>Rad Secret</span>
|
||||
<input cFormControl id="floatingInput" placeholder="rad_secret"
|
||||
[(ngModel)]="sysconfigs['rad_secret']['value']" />
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Radius Secret of Mikrowizard Radius Server</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
|
||||
<c-input-group class="mt-3">
|
||||
<span cInputGroupText>System URL</span>
|
||||
<input cFormControl id="floatingInput" placeholder="System URL"
|
||||
[(ngModel)]="sysconfigs['system_url']['value']" />
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Default system access URl</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
<c-input-group class="mt-3">
|
||||
<span cInputGroupText>Default IP</span>
|
||||
<input cFormControl id="floatingInput" placeholder="System URL"
|
||||
[(ngModel)]="sysconfigs['default_ip']['value']" />
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Default Mikrowizard Access IP</c-form-feedback>
|
||||
</c-input-group>
|
||||
<c-input-group class="mt-3">
|
||||
<span cInputGroupText>System Time Zone</span>
|
||||
<mat-form-field class="form-control" subscriptSizing="dynamic">
|
||||
<mat-label>Select event type</mat-label>
|
||||
<mat-select cFormControl [(ngModel)]="sysconfigs['timezone']['value']"
|
||||
placeholder="Select Version For Download Group" #singleSelect>
|
||||
<mat-option>
|
||||
<ngx-mat-select-search placeholderLabel="Search" [hideClearSearchButton]="true"></ngx-mat-select-search>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let tz of timezones" [value]="tz.utc[0]">
|
||||
{{tz.text}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Default TimeZone for the system</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
|
||||
<c-input-group class="mt-3">
|
||||
<span cInputGroupText>Default User</span>
|
||||
<input aria-label="Username" type="password" [(ngModel)]="sysconfigs['default_user']['value']" cFormControl />
|
||||
<span cInputGroupText>Default password</span>
|
||||
<input aria-label="Password" type="password" [(ngModel)]="sysconfigs['default_password']['value']"
|
||||
cFormControl />
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Default username and Password for searching new devices</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
<c-input-group class="mb-3">
|
||||
<label cInputGroupText for="inputGroupSelect01">
|
||||
Mikrowizard Update Mode
|
||||
</label>
|
||||
<select cSelect [(ngModel)]="sysconfigs['update_mode']['value']['mode']" id="inputGroupSelect01">
|
||||
<option>Choose...</option>
|
||||
<option value="auto">Automatic Update</option>
|
||||
<option value="manual">Show update only/Update manually</option>
|
||||
</select>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Choose if Mikrowizard should download updates automaticaly when availble or wait for user to download/apply updates</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
<c-input-group class="mt-3 mb-3">
|
||||
<span cInputGroupText>License Username</span>
|
||||
<input aria-label="Username" type="text" [(ngModel)]="sysconfigs['username']['value']" cFormControl />
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* The username that you registred in Mikrowizard.com,Required for License Activation</c-form-feedback>
|
||||
</c-input-group>
|
||||
|
||||
<c-form-check [switch]="true" sizing="xl">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['force_perms']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel>Force Perms</label>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Force User Groups under user>groups configuration of each router to match Mikrowizard Permissions and
|
||||
monitor for any change to prevent/fix the configuration.</c-form-feedback>
|
||||
</c-form-check>
|
||||
|
||||
<c-form-check [switch]="true" sizing="xl">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['force_radius']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel>Force Radius</label>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Force Radius config under radius>client and user>aaa setting of each router that added to Mikrowizard and
|
||||
monitor for any change to prevent/fix the configuration.</c-form-feedback>
|
||||
</c-form-check>
|
||||
|
||||
<c-form-check [switch]="true" sizing="xl">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['force_syslog']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel>Force Syslog</label>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true">
|
||||
* Force Syslog config under system>logs setting of each router that added to Mikrowizard and monitor syslog
|
||||
setting for any change to prevent/fix the configuration.</c-form-feedback>
|
||||
</c-form-check>
|
||||
|
||||
<c-form-check *ngIf="ispro" [switch]="true" sizing="xl">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['safe_install']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel>Safe Update</label>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true"><code style="padding: 0!important;">PRO</code>
|
||||
* Download and install reqired firmware before installing the target firmware . for example it will install
|
||||
latest 7.12 then upgrade to newer version >7.13 or install Required packages before update</c-form-feedback>
|
||||
</c-form-check>
|
||||
|
||||
<c-form-check *ngIf="ispro" [switch]="true" sizing="xl">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['otp_force']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel>Force device otp</label>
|
||||
<c-form-feedback style="display: block;color: #5c5c5c;margin-top: 0;" [valid]="true"><code style="padding: 0!important;">PRO</code>
|
||||
* Force login to devices using otp for all users.(you can make exceptions for each user)</c-form-feedback>
|
||||
</c-form-check>
|
||||
<button cButton color="primary" (click)="saveSysSetting()">Save</button>
|
||||
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="showFirmwareDropdown && filteredFirmwares.length === 0 && firmwareSearch" class="search-no-results">
|
||||
No versions found
|
||||
</div>
|
||||
</div>
|
||||
</c-col>
|
||||
<c-col md="4" class="d-flex align-items-end">
|
||||
<button cButton color="primary" class="w-100" (click)="ConfirmModalVisible=true" [disabled]="!firmtodownload">
|
||||
<i class="fa-solid fa-download me-1"></i>Download
|
||||
</button>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<div *ngIf="loading" class="text-center py-3">
|
||||
<c-spinner size="sm" class="me-2"></c-spinner>
|
||||
<span class="text-muted">Fetching available versions from MikroTik...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Firmware Settings -->
|
||||
<div class="firmware-settings">
|
||||
<h5 class="section-title mb-3">
|
||||
<i class="fa-solid fa-cogs me-2 text-warning"></i>Update Configuration
|
||||
<i class="fa-solid fa-info-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'These settings control how MikroWizard handles firmware updates across your network. Changes affect all future update operations.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h5>
|
||||
<div class="info-banner mb-3">
|
||||
<i class="fa-solid fa-shield-alt me-2"></i>
|
||||
<span><strong>Best Practice:</strong> Use "Keep v6" for legacy devices. Test new firmware versions in lab environment first.</span>
|
||||
</div>
|
||||
|
||||
<c-row class="g-3">
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">V6 Firmware Behavior
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Choose how to handle RouterOS v6 devices: keep them on v6 with selected v6 firmware, or upgrade them to v7 with selected v7 firmware.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<select cSelect [(ngModel)]="updateBehavior" class="form-select">
|
||||
<option value="">Choose behavior...</option>
|
||||
<option value="keep">🛡️ Keep v6 (v6 devices get V6 Firmware Version, v7 devices get Default Firmware Version)</option>
|
||||
<option value="update">⬆️ Upgrade to v7 (all v6 routers will be upgraded to v7)</option>
|
||||
</select>
|
||||
<small class="setting-help">📋 <strong>Keep v6:</strong> v6 devices use V6 Firmware Version, v7 devices use Default Firmware Version</small>
|
||||
</div>
|
||||
</c-col>
|
||||
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">Default Firmware Version
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'This version will be installed on new devices added to MikroWizard. Choose stable LTS versions for production.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<select cSelect [(ngModel)]="firmwaretoinstall" class="form-select">
|
||||
<option value="">Choose version...</option>
|
||||
<option *ngFor="let f of available_firmwares" [value]="f">{{f}}</option>
|
||||
</select>
|
||||
<small class="setting-help">💡 <strong>Tip:</strong> Choose stable releases for production. LTS versions are only available for v6 firmware</small>
|
||||
</div>
|
||||
</c-col>
|
||||
|
||||
<c-col md="6" *ngIf="updateBehavior === 'keep'">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">V6 Firmware Version</label>
|
||||
<select cSelect [(ngModel)]="firmwaretoinstallv6" class="form-select">
|
||||
<option value="">Choose v6 version...</option>
|
||||
<option *ngFor="let f of available_firmwaresv6" [value]="f">{{f}}</option>
|
||||
</select>
|
||||
<small class="setting-help">Firmware version for RouterOS v6 devices</small>
|
||||
</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
<div class="mt-3">
|
||||
<button cButton color="primary" (click)="saveFirmwareSetting()">
|
||||
<i class="fa-solid fa-save me-1"></i>Save Firmware Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</c-card-body>
|
||||
|
||||
<!-- System Tab -->
|
||||
<c-card-body *ngIf="activeTab === 'system' && !SysConfigloading" class="tab-content">
|
||||
<!-- Network Configuration -->
|
||||
<div class="config-section mb-4">
|
||||
<h5 class="section-title mb-3">
|
||||
<i class="fa-solid fa-network-wired me-2 text-primary"></i>Network Configuration
|
||||
<i class="fa-solid fa-info-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'Basic network settings for MikroWizard system access and device communication. Ensure these match your network setup.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h5>
|
||||
<div class="info-banner mb-3">
|
||||
<i class="fa-solid fa-network-wired me-2"></i>
|
||||
<span><strong>Network Setup:</strong> Configure these settings to match your network infrastructure for proper device communication.</span>
|
||||
</div>
|
||||
|
||||
<c-row class="g-3">
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">System URL
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'URL or IP address where MikroWizard is accessible. Used for email notifications and API callbacks. Must be reachable by managed devices.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<input cFormControl [(ngModel)]="sysconfigs['system_url']['value']"
|
||||
placeholder="https://mikrowizard.yourdomain.com or 192.168.1.100" class="form-control" />
|
||||
<small class="setting-help">🌐 <strong>Examples:</strong> https://mikrowizard.company.com or 192.168.1.100</small>
|
||||
</div>
|
||||
</c-col>
|
||||
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">Default IP Address
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'IP address where MikroWizard web interface is accessible. Used as fallback when domain is not available.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<input cFormControl [(ngModel)]="sysconfigs['default_ip']['value']"
|
||||
placeholder="192.168.1.100" class="form-control" />
|
||||
<small class="setting-help">🔧 <strong>Tip:</strong> Use static IP outside DHCP range (e.g., 192.168.1.100-200)</small>
|
||||
</div>
|
||||
</c-col>
|
||||
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">RADIUS Secret
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Secret used by MikroWizard internal RADIUS server for authenticating MikroTik system users. This is for device admin authentication, not end users.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<input cFormControl [(ngModel)]="sysconfigs['rad_secret']['value']"
|
||||
placeholder="Enter MikroWizard RADIUS secret" class="form-control" type="password" />
|
||||
<small class="setting-help">🔐 <strong>Internal RADIUS:</strong> Secret for MikroWizard's built-in RADIUS server (for MikroTik admin authentication)</small>
|
||||
</div>
|
||||
</c-col>
|
||||
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">System Timezone</label>
|
||||
<div class="search-select-wrapper">
|
||||
<input cFormControl
|
||||
[(ngModel)]="timezoneSearch"
|
||||
(input)="filterTimezones($event)"
|
||||
(focus)="showTimezoneDropdown = true"
|
||||
(blur)="hideTimezoneDropdown()"
|
||||
placeholder="Search and select timezone..."
|
||||
class="search-input"
|
||||
autocomplete="off" />
|
||||
<div *ngIf="showTimezoneDropdown && filteredTimezones.length > 0" class="search-dropdown">
|
||||
<div *ngFor="let tz of filteredTimezones"
|
||||
class="search-option"
|
||||
(mousedown)="selectTimezone(tz)">
|
||||
{{tz.text}}
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="showTimezoneDropdown && filteredTimezones.length === 0 && timezoneSearch" class="search-no-results">
|
||||
No timezones found
|
||||
</div>
|
||||
</div>
|
||||
<small class="setting-help">Default system timezone</small>
|
||||
</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</div>
|
||||
|
||||
<!-- Authentication -->
|
||||
<div class="config-section mb-4">
|
||||
<h5 class="section-title mb-3">
|
||||
<i class="fa-solid fa-key me-2 text-warning"></i>Device Discovery Credentials
|
||||
<i class="fa-solid fa-info-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'Default credentials for discovering and connecting to new MikroTik devices. Keep these secure and change default passwords immediately.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h5>
|
||||
<div class="warning-banner mb-3">
|
||||
<i class="fa-solid fa-shield-exclamation me-2"></i>
|
||||
<span><strong>Security Warning:</strong> Change default passwords immediately after device setup. Use strong, unique credentials.</span>
|
||||
</div>
|
||||
|
||||
<c-row class="g-3">
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">Default Username
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Username for discovering and connecting to MikroTik devices in your network. This is used to find devices with default/common credentials.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<input cFormControl [(ngModel)]="sysconfigs['default_user']['value']"
|
||||
placeholder="admin" class="form-control" type="password" />
|
||||
<small class="setting-help">🔍 <strong>Device Discovery:</strong> Username for finding MikroTik devices with default credentials in your network</small>
|
||||
</div>
|
||||
</c-col>
|
||||
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">Default Password
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Password for discovering and connecting to MikroTik devices. Many new devices have empty password. Used to find devices with default/common credentials.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<input cFormControl [(ngModel)]="sysconfigs['default_password']['value']"
|
||||
placeholder="(often empty on new devices)" class="form-control" type="password" />
|
||||
<small class="setting-help">🔍 <strong>Device Discovery:</strong> Password for finding MikroTik devices with default credentials (often empty on new devices)</small>
|
||||
</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</div>
|
||||
|
||||
<!-- License Configuration -->
|
||||
<div class="config-section mb-4">
|
||||
<h5 class="section-title mb-3">
|
||||
<i class="fa-solid fa-certificate me-2 text-primary"></i>License Configuration
|
||||
<i class="fa-solid fa-info-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'MikroWizard license activation and registration settings. Required for system activation and PRO features.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h5>
|
||||
|
||||
<c-row class="g-3">
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">License Username
|
||||
<i class="fa-solid fa-exclamation-triangle ms-1 text-warning help-icon"
|
||||
[cTooltip]="'Your username from MikroWizard.com account. Same username you use to login to mikrowizard.com website. Required for license activation.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<input cFormControl [(ngModel)]="sysconfigs['username']['value']"
|
||||
placeholder="Same as your mikrowizard.com login" class="form-control" />
|
||||
<small class="setting-help text-warning">🔑 <strong>Same username</strong> you use to login to mikrowizard.com website</small>
|
||||
</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</div>
|
||||
|
||||
<!-- System Behavior -->
|
||||
<div class="config-section mb-4">
|
||||
<h5 class="section-title mb-3">
|
||||
<i class="fa-solid fa-cogs me-2 text-success"></i>System Behavior
|
||||
<i class="fa-solid fa-info-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'Controls how MikroWizard handles automatic updates and system maintenance. Choose based on your change management policy.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h5>
|
||||
|
||||
<c-row class="g-3">
|
||||
<c-col md="6">
|
||||
<div class="setting-group">
|
||||
<label class="setting-label">Update Mode
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Automatic updates install immediately when available. Manual mode shows notifications in dashboard and waits for user confirmation.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</label>
|
||||
<select cSelect [(ngModel)]="sysconfigs['update_mode']['value']['mode']" class="form-select">
|
||||
<option value="">Choose mode...</option>
|
||||
<option value="auto">🔄 Automatic Updates (Install immediately)</option>
|
||||
<option value="manual">✋ Manual Updates (Confirm actions in dashboard view)</option>
|
||||
</select>
|
||||
<small class="setting-help">📊 <strong>Manual Mode:</strong> Updates require confirmation and actions in dashboard view</small>
|
||||
</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</div>
|
||||
|
||||
<!-- Security Features -->
|
||||
<div class="config-section mb-4">
|
||||
<h5 class="section-title mb-3">
|
||||
<i class="fa-solid fa-shield-alt me-2 text-danger"></i>Security & Enforcement
|
||||
<i class="fa-solid fa-info-circle ms-2 text-info help-icon"
|
||||
[cTooltip]="'Security policies automatically enforced on all managed devices. These settings override local device configurations for consistency.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h5>
|
||||
<div class="warning-banner mb-3">
|
||||
<i class="fa-solid fa-exclamation-triangle me-2"></i>
|
||||
<span><strong>Important:</strong> These settings will override device configurations. Test in lab environment before enabling in production.</span>
|
||||
</div>
|
||||
|
||||
<div class="security-switches">
|
||||
<div class="switch-item">
|
||||
<div class="switch-content">
|
||||
<div class="switch-info">
|
||||
<h6 class="switch-title">Force Permissions
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Synchronizes MikroTik user groups with MikroWizard permissions. Ensures consistent access control across all managed devices.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h6>
|
||||
<p class="switch-description">🔄 Sync MikroTik user groups with MikroWizard permissions
|
||||
<br><small class="text-info">💡 Ensures consistent user access control across all devices</small>
|
||||
</p>
|
||||
</div>
|
||||
<c-form-check [switch]="true" sizing="lg">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['force_perms']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel></label>
|
||||
</c-form-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="switch-item">
|
||||
<div class="switch-content">
|
||||
<div class="switch-info">
|
||||
<h6 class="switch-title">Force RADIUS
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Configures MikroTik devices to use MikroWizard RADIUS for admin user authentication. This is for MikroTik system users, not end users.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h6>
|
||||
<p class="switch-description">🔐 Configure RADIUS on MikroTik devices for admin user authentication
|
||||
<br><small class="text-info">👥 For MikroTik system users authentication (not end users)</small>
|
||||
</p>
|
||||
</div>
|
||||
<c-form-check [switch]="true" sizing="lg">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['force_radius']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel></label>
|
||||
</c-form-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="switch-item">
|
||||
<div class="switch-content">
|
||||
<div class="switch-info">
|
||||
<h6 class="switch-title">Force Syslog
|
||||
<i class="fa-solid fa-exclamation-triangle ms-1 text-warning help-icon"
|
||||
[cTooltip]="'CRITICAL: Will overwrite syslog configuration on all devices. If MikroWizard server is unreachable, devices may stop logging or experience performance issues.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h6>
|
||||
<p class="switch-description">📊 Automatically configure syslog settings on managed devices
|
||||
<br><small class="text-warning">⚠️ Will OVERWRITE existing syslog configurations on devices</small>
|
||||
</p>
|
||||
</div>
|
||||
<c-form-check [switch]="true" sizing="lg">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['force_syslog']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel></label>
|
||||
</c-form-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="switch-item" *ngIf="ispro">
|
||||
<div class="switch-content">
|
||||
<div class="switch-info">
|
||||
<h6 class="switch-title">Safe Updates <c-badge color="warning" class="ms-2">PRO</c-badge>
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Prevents firmware update failures by installing intermediate versions first. Reduces risk of device brick but takes longer.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h6>
|
||||
<p class="switch-description">🛡️ Install required intermediate firmware versions before target version
|
||||
<br><small class="text-success">✅ Highly recommended for production environments</small>
|
||||
</p>
|
||||
</div>
|
||||
<c-form-check [switch]="true" sizing="lg">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['safe_install']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel></label>
|
||||
</c-form-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="switch-item" *ngIf="ispro">
|
||||
<div class="switch-content">
|
||||
<div class="switch-info">
|
||||
<h6 class="switch-title">Force Device OTP <c-badge color="warning" class="ms-2">PRO</c-badge>
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Requires two-factor authentication for device access. Users must have OTP configured. Significantly improves security.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h6>
|
||||
<p class="switch-description">🔐 Require OTP authentication for all device access
|
||||
<br><small class="text-warning">⚠️ Ensure users have OTP configured before enabling</small>
|
||||
</p>
|
||||
</div>
|
||||
<c-form-check [switch]="true" sizing="lg">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['otp_force']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel></label>
|
||||
</c-form-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="switch-item" *ngIf="ispro">
|
||||
<div class="switch-content">
|
||||
<div class="switch-info">
|
||||
<h6 class="switch-title">WebFig Auto Login <c-badge color="warning" class="ms-2">PRO</c-badge>
|
||||
<i class="fa-solid fa-question-circle ms-1 text-info help-icon"
|
||||
[cTooltip]="'Creates temporary OTP password for automatic WebFig login. Users don\'t need to enter credentials when accessing device WebFig through MikroWizard.'"
|
||||
cTooltipPlacement="top"></i>
|
||||
</h6>
|
||||
<p class="switch-description">🌐 Create temporary OTP for automatic WebFig login
|
||||
<br><small class="text-success">🔑 Users don't need to input passwords to access WebFig admin interface</small>
|
||||
</p>
|
||||
</div>
|
||||
<c-form-check [switch]="true" sizing="lg">
|
||||
<input cFormCheckInput [(ngModel)]="sysconfigs['proxy_auto_login']['value']" type="checkbox" />
|
||||
<label cFormCheckLabel></label>
|
||||
</c-form-check>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="save-section">
|
||||
<button cButton color="primary" size="lg" (click)="saveSysSetting()">
|
||||
<i class="fa-solid fa-save me-2"></i>Save System Settings
|
||||
</button>
|
||||
</div>
|
||||
</c-card-body>
|
||||
|
||||
<!-- Loading State -->
|
||||
<c-card-body *ngIf="activeTab === 'system' && SysConfigloading" class="text-center py-5">
|
||||
<c-spinner size="sm" class="mb-3"></c-spinner>
|
||||
<h5 class="text-muted">Loading system configuration...</h5>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</div>
|
||||
|
||||
<c-modal #ConfirmModal backdrop="static" [(visible)]="ConfirmModalVisible" id="runConfirmModal">
|
||||
<c-modal-header>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,629 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mdc-line-ripple.mdc-line-ripple--deactivating.ng-star-inserted {
|
||||
display: none!important;
|
||||
}
|
||||
.form-check-label{
|
||||
font-weight: bold;
|
||||
|
||||
/* Settings Container */
|
||||
.settings-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.settings-card {
|
||||
border: none;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.settings-header {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
padding: 1.25rem 1.5rem;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.settings-tabs {
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
padding: 0 1.5rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tab-link {
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
padding: 1rem 1.5rem;
|
||||
font-weight: 500;
|
||||
color: #6c757d;
|
||||
transition: all 0.2s ease;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tab-link:hover {
|
||||
color: #495057;
|
||||
background: rgba(13, 110, 253, 0.05);
|
||||
}
|
||||
|
||||
.tab-link.active {
|
||||
color: #0d6efd;
|
||||
background: white;
|
||||
border-bottom-color: #0d6efd;
|
||||
}
|
||||
|
||||
/* Tab Content */
|
||||
.tab-content {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
/* Section Titles */
|
||||
.section-title {
|
||||
color: #495057;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Status Section */
|
||||
.status-section {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
/* Download Section */
|
||||
.download-section {
|
||||
.section-card {
|
||||
background: linear-gradient(135deg, #e7f3ff 0%, #f8f9fa 100%);
|
||||
border: 2px dashed #0d6efd;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.section-card:hover {
|
||||
border-color: #0a58ca;
|
||||
background: linear-gradient(135deg, #cfe2ff 0%, #e7f3ff 100%);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
}
|
||||
}
|
||||
|
||||
/* Firmware Settings */
|
||||
.firmware-settings {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
/* Config Sections */
|
||||
.config-section {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
/* Setting Groups */
|
||||
.setting-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.setting-help {
|
||||
color: #6c757d;
|
||||
font-size: 0.8rem;
|
||||
margin-top: 0.25rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Security Switches */
|
||||
.security-switches {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.switch-item {
|
||||
background: white;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 8px;
|
||||
padding: 1.25rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.switch-item:hover {
|
||||
border-color: #0d6efd;
|
||||
box-shadow: 0 2px 4px rgba(13, 110, 253, 0.1);
|
||||
}
|
||||
|
||||
.switch-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.switch-info {
|
||||
flex: 1;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.switch-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
margin-bottom: 0.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.switch-description {
|
||||
color: #6c757d;
|
||||
font-size: 0.85rem;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Compact Grid */
|
||||
.compact-grid {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
/* Version Badge */
|
||||
.version-badge {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Form Controls */
|
||||
.form-control, .form-select {
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ced4da;
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.form-control:focus, .form-select:focus {
|
||||
border-color: #0d6efd;
|
||||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
/* Save Section */
|
||||
.save-section {
|
||||
text-align: center;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
/* Form Check Labels */
|
||||
.form-check-label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Button Enhancements */
|
||||
.btn {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Badge Enhancements */
|
||||
.badge {
|
||||
font-weight: 500;
|
||||
padding: 0.4em 0.6em;
|
||||
}
|
||||
|
||||
/* Mobile Responsive for Informative Elements */
|
||||
@media (max-width: 768px) {
|
||||
.info-banner,
|
||||
.warning-banner,
|
||||
.success-banner {
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.help-icon {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.setting-help {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.switch-description {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.switch-description small {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
::ng-deep .tooltip-inner {
|
||||
max-width: 250px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.info-banner,
|
||||
.warning-banner,
|
||||
.success-banner {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Original Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.settings-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.settings-tabs {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.tab-link {
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.status-section,
|
||||
.config-section,
|
||||
.firmware-settings {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.download-section .section-card {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.switch-content {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.switch-info {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.settings-container {
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
.settings-card {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.status-section,
|
||||
.config-section,
|
||||
.firmware-settings {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search Select Components */
|
||||
.search-select-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: #0d6efd;
|
||||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.search-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
border: 1px solid #ced4da;
|
||||
border-top: none;
|
||||
border-radius: 0 0 6px 6px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.search-option {
|
||||
padding: 0.5rem 0.75rem;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #f8f9fa;
|
||||
transition: background-color 0.15s ease-in-out;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.search-option:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.search-option:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.search-no-results {
|
||||
padding: 0.75rem;
|
||||
text-align: center;
|
||||
color: #6c757d;
|
||||
font-style: italic;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* Animation for dropdown */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(-10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.search-dropdown {
|
||||
animation: fadeIn 0.2s ease-out;
|
||||
}
|
||||
|
||||
/* Informative Design Elements */
|
||||
.help-icon {
|
||||
font-size: 0.8rem;
|
||||
cursor: help;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.help-icon:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.help-icon.text-danger {
|
||||
color: #dc3545 !important;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.help-icon.text-warning {
|
||||
color: #fd7e14 !important;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.info-banner {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border: 1px solid #2196f3;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #0d47a1;
|
||||
font-size: 0.85rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.warning-banner {
|
||||
background: linear-gradient(135deg, #fff3e0 0%, #ffcc80 100%);
|
||||
border: 1px solid #ff9800;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #e65100;
|
||||
font-size: 0.85rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.success-banner {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
|
||||
border: 1px solid #4caf50;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #2e7d32;
|
||||
font-size: 0.85rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Enhanced Setting Help */
|
||||
.setting-help {
|
||||
color: #6c757d;
|
||||
font-size: 0.8rem;
|
||||
margin-top: 0.25rem;
|
||||
display: block;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.setting-help strong {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
/* Enhanced Form Labels */
|
||||
.setting-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Enhanced Switch Descriptions */
|
||||
.switch-description {
|
||||
color: #6c757d;
|
||||
font-size: 0.85rem;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.switch-description small {
|
||||
display: block;
|
||||
margin-top: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.switch-description .text-warning {
|
||||
color: #856404 !important;
|
||||
}
|
||||
|
||||
.switch-description .text-info {
|
||||
color: #0c5460 !important;
|
||||
}
|
||||
|
||||
.switch-description .text-success {
|
||||
color: #155724 !important;
|
||||
}
|
||||
|
||||
.switch-description .text-danger {
|
||||
color: #721c24 !important;
|
||||
}
|
||||
|
||||
.setting-help.text-danger {
|
||||
color: #721c24 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.setting-help.text-warning {
|
||||
color: #856404 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Enhanced Section Titles */
|
||||
.section-title {
|
||||
color: #495057;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Tooltip Enhancements */
|
||||
::ng-deep .tooltip {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
::ng-deep .tooltip-inner {
|
||||
max-width: 300px;
|
||||
text-align: left;
|
||||
background-color: #2c3e50;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
/* Enhanced Form Controls with Status */
|
||||
.form-control.has-warning {
|
||||
border-color: #ffc107;
|
||||
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.25);
|
||||
}
|
||||
|
||||
.form-control.has-success {
|
||||
border-color: #28a745;
|
||||
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
|
||||
}
|
||||
|
||||
.form-control.has-error {
|
||||
border-color: #dc3545;
|
||||
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
|
||||
}
|
||||
|
||||
/* Enhanced Select Options */
|
||||
.form-select option {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
/* Status Indicators */
|
||||
.status-indicator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.status-indicator.recommended {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status-indicator.warning {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
border: 1px solid #ffeaa7;
|
||||
}
|
||||
|
||||
.status-indicator.critical {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
/* Grid Enhancements */
|
||||
::ng-deep .gui-grid {
|
||||
.gui-grid-header {
|
||||
background: #f8f9fa;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.gui-grid-cell {
|
||||
padding: 0.75rem 0.5rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,17 @@ export class SettingsComponent implements OnInit {
|
|||
public filters: any = {};
|
||||
public firms: any = {};
|
||||
public firmtodownload: any = {};
|
||||
public activeTab: string = 'firmware';
|
||||
|
||||
// Search functionality properties
|
||||
public firmwareSearch: string = '';
|
||||
public showFirmwareDropdown: boolean = false;
|
||||
public filteredFirmwares: any[] = [];
|
||||
|
||||
public timezoneSearch: string = '';
|
||||
public showTimezoneDropdown: boolean = false;
|
||||
public filteredTimezones: any[] = [];
|
||||
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
|
|
@ -293,6 +304,12 @@ export class SettingsComponent implements OnInit {
|
|||
_self.sysconfigs["default_user"]["value"] = "";
|
||||
_self.sysconfigs["default_password"]["value"] = "";
|
||||
_self.timezones = _self.TimeZones.timezones;
|
||||
_self.filteredTimezones = _self.TimeZones.timezones;
|
||||
// Set initial timezone search display
|
||||
const currentTz = _self.timezones.find((tz: any) => tz.utc[0] === _self.sysconfigs['timezone']['value']);
|
||||
if (currentTz) {
|
||||
_self.timezoneSearch = currentTz.text;
|
||||
}
|
||||
_self.sysconfigs["force_syslog"]["value"] = /true/i.test(
|
||||
_self.sysconfigs["force_syslog"]["value"]
|
||||
);
|
||||
|
|
@ -310,6 +327,16 @@ export class SettingsComponent implements OnInit {
|
|||
_self.sysconfigs["otp_force"]["value"]
|
||||
);
|
||||
}
|
||||
if(_self.ispro && "proxy_auto_login" in _self.sysconfigs){
|
||||
_self.sysconfigs["proxy_auto_login"]["value"] = /true/i.test(
|
||||
_self.sysconfigs["proxy_auto_login"]["value"]
|
||||
);
|
||||
}
|
||||
else if(_self.ispro){
|
||||
_self.sysconfigs["proxy_auto_login"] = {
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
//check if update_mode is in the sysconfigs
|
||||
if ("update_mode" in _self.sysconfigs){
|
||||
//convert string to json
|
||||
|
|
@ -335,7 +362,50 @@ export class SettingsComponent implements OnInit {
|
|||
this.data_provider.get_downloadable_firms().then((res) => {
|
||||
let index = 1;
|
||||
_self.firms = res.versions;
|
||||
_self.filteredFirmwares = res.versions;
|
||||
_self.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
// Firmware search methods
|
||||
filterFirmwares(event: any): void {
|
||||
const searchTerm = event.target.value.toLowerCase();
|
||||
this.firmwareSearch = searchTerm;
|
||||
this.filteredFirmwares = this.firms.filter((firm: string) =>
|
||||
firm.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
}
|
||||
|
||||
selectFirmware(firmware: string): void {
|
||||
this.firmtodownload = firmware;
|
||||
this.firmwareSearch = firmware;
|
||||
this.showFirmwareDropdown = false;
|
||||
}
|
||||
|
||||
hideFirmwareDropdown(): void {
|
||||
setTimeout(() => {
|
||||
this.showFirmwareDropdown = false;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// Timezone search methods
|
||||
filterTimezones(event: any): void {
|
||||
const searchTerm = event.target.value.toLowerCase();
|
||||
this.timezoneSearch = searchTerm;
|
||||
this.filteredTimezones = this.timezones.filter((tz: any) =>
|
||||
tz.text.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
}
|
||||
|
||||
selectTimezone(timezone: any): void {
|
||||
this.sysconfigs['timezone']['value'] = timezone.utc[0];
|
||||
this.timezoneSearch = timezone.text;
|
||||
this.showTimezoneDropdown = false;
|
||||
}
|
||||
|
||||
hideTimezoneDropdown(): void {
|
||||
setTimeout(() => {
|
||||
this.showTimezoneDropdown = false;
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ import {
|
|||
SpinnerModule,
|
||||
ToastModule,
|
||||
ModalModule,
|
||||
BadgeModule,
|
||||
TooltipModule,
|
||||
} from "@coreui/angular";
|
||||
import { SettingsRoutingModule } from "./settings-routing.module";
|
||||
import { SettingsComponent } from "./settings.component";
|
||||
import { GuiGridModule } from "@generic-ui/ngx-grid";
|
||||
|
||||
import { FormsModule } from "@angular/forms";
|
||||
import { MatSelectModule } from "@angular/material/select";
|
||||
import { NgxMatSelectSearchModule } from "ngx-mat-select-search";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
|
@ -30,11 +30,11 @@ import { NgxMatSelectSearchModule } from "ngx-mat-select-search";
|
|||
ButtonModule,
|
||||
ButtonGroupModule,
|
||||
GuiGridModule,
|
||||
MatSelectModule,
|
||||
NgxMatSelectSearchModule,
|
||||
SpinnerModule,
|
||||
ToastModule,
|
||||
ModalModule,
|
||||
BadgeModule,
|
||||
TooltipModule,
|
||||
],
|
||||
declarations: [SettingsComponent],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ export class SnippetsComponent implements OnInit, OnDestroy {
|
|||
|
||||
initGridTable(): void {
|
||||
var _self = this;
|
||||
_self.data_provider.get_snippets("", "", "", 0, 1000).then((res) => {
|
||||
_self.data_provider.get_snippets("", "", "", 0, 1000,false).then((res) => {
|
||||
_self.source = res.map((x: any) => {
|
||||
x.created = [
|
||||
x.created.split("T")[0],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue