mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Directory Picker Rework (#1325)
* Started on the directory picker refactor. * Coded some basic working version. Needs styling and variable cleanup * code cleanup * Implemented the ability to expose swagger on non-development servers. * Implemented the ability to expose swagger on non-development servers.
This commit is contained in:
parent
0f5a7ee6fa
commit
9c851b0f0e
@ -8,6 +8,7 @@ using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.DTOs.JumpBar;
|
||||
using API.DTOs.Search;
|
||||
using API.DTOs.System;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
@ -89,11 +90,15 @@ namespace API.Controllers
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpGet("list")]
|
||||
public ActionResult<IEnumerable<string>> GetDirectories(string path)
|
||||
public ActionResult<IEnumerable<DirectoryDto>> GetDirectories(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return Ok(Directory.GetLogicalDrives());
|
||||
return Ok(Directory.GetLogicalDrives().Select(d => new DirectoryDto()
|
||||
{
|
||||
Name = d,
|
||||
FullPath = d
|
||||
}));
|
||||
}
|
||||
|
||||
if (!Directory.Exists(path)) return BadRequest("This is not a valid path");
|
||||
|
@ -206,6 +206,12 @@ namespace API.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EnableSwaggerUi && updateSettingsDto.EnableSwaggerUi + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = updateSettingsDto.EnableSwaggerUi + string.Empty;
|
||||
_unitOfWork.SettingsRepository.Update(setting);
|
||||
}
|
||||
|
||||
if (setting.Key == ServerSettingKey.EmailServiceUrl && updateSettingsDto.EmailServiceUrl + string.Empty != setting.Value)
|
||||
{
|
||||
setting.Value = string.IsNullOrEmpty(updateSettingsDto.EmailServiceUrl) ? EmailService.DefaultApiUrl : updateSettingsDto.EmailServiceUrl;
|
||||
|
@ -40,5 +40,9 @@ namespace API.DTOs.Settings
|
||||
public string InstallVersion { get; set; }
|
||||
|
||||
public bool ConvertBookmarkToWebP { get; set; }
|
||||
/// <summary>
|
||||
/// If the Swagger UI Should be exposed. Does not require authentication, but does require a JWT.
|
||||
/// </summary>
|
||||
public bool EnableSwaggerUi { get; set; }
|
||||
}
|
||||
}
|
||||
|
13
API/DTOs/System/DirectoryDto.cs
Normal file
13
API/DTOs/System/DirectoryDto.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace API.DTOs.System;
|
||||
|
||||
public class DirectoryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the directory
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Full Directory Path
|
||||
/// </summary>
|
||||
public string FullPath { get; set; }
|
||||
}
|
@ -101,6 +101,7 @@ namespace API.Data
|
||||
new() {Key = ServerSettingKey.BookmarkDirectory, Value = directoryService.BookmarkDirectory},
|
||||
new() {Key = ServerSettingKey.EmailServiceUrl, Value = EmailService.DefaultApiUrl},
|
||||
new() {Key = ServerSettingKey.ConvertBookmarkToWebP, Value = "false"},
|
||||
new() {Key = ServerSettingKey.EnableSwaggerUi, Value = "false"},
|
||||
}.ToArray());
|
||||
|
||||
foreach (var defaultSetting in DefaultSettings)
|
||||
|
@ -81,5 +81,10 @@ namespace API.Entities.Enums
|
||||
/// </summary>
|
||||
[Description("ConvertBookmarkToWebP")]
|
||||
ConvertBookmarkToWebP = 14,
|
||||
/// <summary>
|
||||
/// If the Swagger UI Should be exposed. Does not require authentication, but does require a JWT.
|
||||
/// </summary>
|
||||
[Description("EnableSwaggerUi")]
|
||||
EnableSwaggerUi = 15,
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ namespace API.Helpers.Converters
|
||||
case ServerSettingKey.ConvertBookmarkToWebP:
|
||||
destination.ConvertBookmarkToWebP = bool.Parse(row.Value);
|
||||
break;
|
||||
case ServerSettingKey.EnableSwaggerUi:
|
||||
destination.EnableSwaggerUi = bool.Parse(row.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@ using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using API.DTOs.System;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@ -29,7 +31,7 @@ namespace API.Services
|
||||
/// </summary>
|
||||
/// <param name="rootPath">Absolute path of directory to scan.</param>
|
||||
/// <returns>List of folder names</returns>
|
||||
IEnumerable<string> ListDirectory(string rootPath);
|
||||
IEnumerable<DirectoryDto> ListDirectory(string rootPath);
|
||||
Task<byte[]> ReadFileAsync(string path);
|
||||
bool CopyFilesToDirectory(IEnumerable<string> filePaths, string directoryPath, string prepend = "");
|
||||
bool Exists(string directory);
|
||||
@ -434,14 +436,18 @@ namespace API.Services
|
||||
/// </summary>
|
||||
/// <param name="rootPath"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<string> ListDirectory(string rootPath)
|
||||
public IEnumerable<DirectoryDto> ListDirectory(string rootPath)
|
||||
{
|
||||
if (!FileSystem.Directory.Exists(rootPath)) return ImmutableList<string>.Empty;
|
||||
if (!FileSystem.Directory.Exists(rootPath)) return ImmutableList<DirectoryDto>.Empty;
|
||||
|
||||
var di = FileSystem.DirectoryInfo.FromDirectoryName(rootPath);
|
||||
var dirs = di.GetDirectories()
|
||||
.Where(dir => !(dir.Attributes.HasFlag(FileAttributes.Hidden) || dir.Attributes.HasFlag(FileAttributes.System)))
|
||||
.Select(d => d.Name).ToImmutableList();
|
||||
.Select(d => new DirectoryDto()
|
||||
{
|
||||
Name = d.Name,
|
||||
FullPath = d.FullName,
|
||||
}).ToImmutableList();
|
||||
|
||||
return dirs;
|
||||
}
|
||||
|
@ -176,13 +176,23 @@ namespace API
|
||||
|
||||
app.UseMiddleware<ExceptionMiddleware>();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var allowSwaggerUi = (await unitOfWork.SettingsRepository.GetSettingsDtoAsync())
|
||||
.EnableSwaggerUi;
|
||||
|
||||
if (env.IsDevelopment() || allowSwaggerUi)
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Kavita API " + BuildInfo.Version);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Kavita API " + BuildInfo.Version);
|
||||
});
|
||||
app.UseHangfireDashboard();
|
||||
}
|
||||
|
||||
|
4
UI/Web/src/app/_models/system/directory-dto.ts
Normal file
4
UI/Web/src/app/_models/system/directory-dto.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface DirectoryDto {
|
||||
name: string;
|
||||
fullPath: string;
|
||||
}
|
@ -6,6 +6,7 @@ import { environment } from 'src/environments/environment';
|
||||
import { JumpKey } from '../_models/jumpbar/jump-key';
|
||||
import { Library, LibraryType } from '../_models/library';
|
||||
import { SearchResultGroup } from '../_models/search/search-result-group';
|
||||
import { DirectoryDto } from '../_models/system/directory-dto';
|
||||
|
||||
|
||||
@Injectable({
|
||||
@ -56,7 +57,7 @@ export class LibraryService {
|
||||
query = '?path=' + encodeURIComponent(rootPath);
|
||||
}
|
||||
|
||||
return this.httpClient.get<string[]>(this.baseUrl + 'library/list' + query);
|
||||
return this.httpClient.get<DirectoryDto[]>(this.baseUrl + 'library/list' + query);
|
||||
}
|
||||
|
||||
getJumpBar(libraryId: number) {
|
||||
|
@ -3,49 +3,69 @@
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<!-- <div class="mb-3">
|
||||
<label for="filter" class="form-label">Filter</label>
|
||||
<div class="input-group">
|
||||
<input id="filter" autocomplete="off" class="form-control" [(ngModel)]="filterQuery" type="text" aria-describedby="reset-input">
|
||||
<button class="btn btn-outline-secondary" type="button" id="reset-input" (click)="filterQuery = '';">Clear</button>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="filter" class="form-label">Path</label>
|
||||
<div class="input-group">
|
||||
<input id="typeahead-focus" type="text" class="form-control" [(ngModel)]="path" [ngbTypeahead]="search"
|
||||
(focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)"
|
||||
(ngModelChange)="updateTable()" #instance="ngbTypeahead" placeholder="Start typing or select path"
|
||||
[resultTemplate]="rt" />
|
||||
</div>
|
||||
<ng-template #rt let-r="result" let-t="term">
|
||||
<ngb-highlight [result]="r" [term]="t"></ngb-highlight>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<nav aria-label="directory breadcrumb">
|
||||
<ol class="breadcrumb" *ngIf="routeStack.peek() !== undefined; else noBreadcrumb">
|
||||
<li class="breadcrumb-item {{route === routeStack.peek() ? 'active' : ''}}" *ngFor="let route of routeStack.items; let index = index">
|
||||
<li class="breadcrumb-item {{route === routeStack.peek() ? 'active' : ''}}"
|
||||
*ngFor="let route of routeStack.items; let index = index">
|
||||
<ng-container *ngIf="route === routeStack.peek(); else nonActive">
|
||||
{{route}}
|
||||
</ng-container>
|
||||
<ng-template #nonActive>
|
||||
<a href="javascript:void(0);" (click)="navigateTo(index)">{{route}}</a>
|
||||
</ng-template>
|
||||
</li>
|
||||
</li>
|
||||
</ol>
|
||||
<ng-template #noBreadcrumb>
|
||||
<div class="breadcrumb">Select a folder to view breadcrumb. Don't see your directory, try checking / first.</div>
|
||||
<div class="breadcrumb">Select a folder to view breadcrumb. Don't see your directory, try checking / first.
|
||||
</div>
|
||||
</ng-template>
|
||||
</nav>
|
||||
<ul class="list-group">
|
||||
<div class="list-group-item list-group-item-action">
|
||||
<button (click)="goBack()" class="btn btn-secondary" [disabled]="routeStack.peek() === undefined">
|
||||
<i class="fa fa-arrow-left me-2" aria-hidden="true"></i>
|
||||
Back
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-primary float-end" [disabled]="routeStack.peek() === undefined" (click)="shareFolder('', $event)">Share</button>
|
||||
</div>
|
||||
</ul>
|
||||
<ul class="list-group scrollable">
|
||||
<button *ngFor="let folder of folders | filter: filterFolder" class="list-group-item list-group-item-action" (click)="selectNode(folder)">
|
||||
<span>{{getStem(folder)}}</span>
|
||||
<button type="button" class="btn btn-primary float-end" (click)="shareFolder(folder, $event)">Share</button>
|
||||
</button>
|
||||
<div class="list-group-item text-center" *ngIf="folders.length === 0">
|
||||
There are no folders here
|
||||
</div>
|
||||
</ul>
|
||||
<table class="table table-striped scrollable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr (click)="goBack()">
|
||||
<td><i class="fa-solid fa-arrow-turn-up" aria-hidden="true"></i></td>
|
||||
<td>...</td>
|
||||
</tr>
|
||||
<tr *ngFor="let folder of folders; let idx = index;" (click)="selectNode(folder)">
|
||||
<td><i class="fa-regular fa-folder" aria-hidden="true"></i></td>
|
||||
<td id="folder--{{idx}}">
|
||||
{{folder.name}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn btn-icon" *ngIf="helpUrl.length > 0" href="{{helpUrl}}" target="_blank">Help</a>
|
||||
<button type="button" class="btn btn-secondary" (click)="close()">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" (click)="share()">Share</button>
|
||||
</div>
|
@ -13,3 +13,7 @@ $breadcrumb-divider: quote(">");
|
||||
.btn-outline-secondary {
|
||||
border: 1px solid #ced4da;
|
||||
}
|
||||
|
||||
.table {
|
||||
background-color: lightgrey;
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { NgbActiveModal, NgbTypeahead } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { catchError, debounceTime, distinctUntilChanged, filter, map, merge, Observable, of, OperatorFunction, Subject, switchMap, tap } from 'rxjs';
|
||||
import { Stack } from 'src/app/shared/data-structures/stack';
|
||||
import { DirectoryDto } from 'src/app/_models/system/directory-dto';
|
||||
import { LibraryService } from '../../../_services/library.service';
|
||||
|
||||
|
||||
@ -10,6 +12,7 @@ export interface DirectoryPickerResult {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-directory-picker',
|
||||
templateUrl: './directory-picker.component.html',
|
||||
@ -24,9 +27,40 @@ export class DirectoryPickerComponent implements OnInit {
|
||||
@Input() helpUrl: string = 'https://wiki.kavitareader.com/en/guides/first-time-setup#adding-a-library-to-kavita';
|
||||
|
||||
currentRoot = '';
|
||||
folders: string[] = [];
|
||||
folders: DirectoryDto[] = [];
|
||||
routeStack: Stack<string> = new Stack<string>();
|
||||
filterQuery: string = '';
|
||||
|
||||
|
||||
path: string = '';
|
||||
@ViewChild('instance', {static: true}) instance!: NgbTypeahead;
|
||||
focus$ = new Subject<string>();
|
||||
click$ = new Subject<string>();
|
||||
searching: boolean = false;
|
||||
searchFailed: boolean = false;
|
||||
|
||||
|
||||
search: OperatorFunction<string, readonly string[]> = (text$: Observable<string>) => {
|
||||
const debouncedText$ = text$.pipe(debounceTime(200), distinctUntilChanged());
|
||||
const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen()));
|
||||
const inputFocus$ = this.focus$;
|
||||
|
||||
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$, text$).pipe(
|
||||
debounceTime(300),
|
||||
distinctUntilChanged(),
|
||||
tap(() => this.searching = true),
|
||||
switchMap(term =>
|
||||
this.libraryService.listDirectories(this.path).pipe(
|
||||
tap(() => this.searchFailed = false),
|
||||
tap((folders) => this.folders = folders),
|
||||
map(folders => folders.map(f => f.fullPath)),
|
||||
catchError(() => {
|
||||
this.searchFailed = true;
|
||||
return of([]);
|
||||
}))
|
||||
),
|
||||
tap(() => this.searching = false)
|
||||
)
|
||||
}
|
||||
|
||||
constructor(public modal: NgbActiveModal, private libraryService: LibraryService) {
|
||||
|
||||
@ -51,15 +85,16 @@ export class DirectoryPickerComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
filterFolder = (folder: string) => {
|
||||
return folder.toLowerCase().indexOf((this.filterQuery || '').toLowerCase()) >= 0;
|
||||
updateTable() {
|
||||
this.loadChildren(this.path);
|
||||
}
|
||||
|
||||
selectNode(folderName: string) {
|
||||
this.currentRoot = folderName;
|
||||
this.routeStack.push(folderName);
|
||||
const fullPath = this.routeStack.items.join('/');
|
||||
this.loadChildren(fullPath);
|
||||
|
||||
selectNode(folder: DirectoryDto) {
|
||||
this.currentRoot = folder.name;
|
||||
this.routeStack.push(folder.name);
|
||||
this.path = folder.fullPath;
|
||||
this.loadChildren(this.path);
|
||||
}
|
||||
|
||||
goBack() {
|
||||
@ -77,7 +112,6 @@ export class DirectoryPickerComponent implements OnInit {
|
||||
|
||||
loadChildren(path: string) {
|
||||
this.libraryService.listDirectories(path).subscribe(folders => {
|
||||
this.filterQuery = '';
|
||||
this.folders = folders;
|
||||
}, err => {
|
||||
// If there was an error, pop off last directory added to stack
|
||||
@ -85,19 +119,17 @@ export class DirectoryPickerComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
shareFolder(folderName: string, event: any) {
|
||||
shareFolder(fullPath: string, event: any) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
let fullPath = folderName;
|
||||
if (this.routeStack.items.length > 0) {
|
||||
const pathJoin = this.routeStack.items.join('/');
|
||||
fullPath = pathJoin + ((pathJoin.endsWith('/') || pathJoin.endsWith('\\')) ? '' : '/') + folderName;
|
||||
}
|
||||
|
||||
this.modal.close({success: true, folderPath: fullPath});
|
||||
}
|
||||
|
||||
share() {
|
||||
this.modal.close({success: true, folderPath: this.path});
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modal.close({success: false, folderPath: undefined});
|
||||
}
|
||||
@ -122,6 +154,9 @@ export class DirectoryPickerComponent implements OnInit {
|
||||
}
|
||||
|
||||
const fullPath = this.routeStack.items.join('/');
|
||||
this.path = fullPath;
|
||||
this.loadChildren(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,4 +10,5 @@ export interface ServerSettings {
|
||||
bookmarksDirectory: string;
|
||||
emailServiceUrl: string;
|
||||
convertBookmarkToWebP: boolean;
|
||||
enableSwaggerUi: boolean;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AdminRoutingModule } from './admin-routing.module';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { NgbDropdownModule, NgbNavModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NgbDropdownModule, NgbNavModule, NgbTooltipModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ManageLibraryComponent } from './manage-library/manage-library.component';
|
||||
import { ManageUsersComponent } from './manage-users/manage-users.component';
|
||||
import { LibraryEditorModalComponent } from './_modals/library-editor-modal/library-editor-modal.component';
|
||||
@ -53,11 +53,12 @@ import { ManageTasksSettingsComponent } from './manage-tasks-settings/manage-tas
|
||||
FormsModule,
|
||||
NgbNavModule,
|
||||
NgbTooltipModule,
|
||||
NgbTypeaheadModule, // Directory Picker
|
||||
NgbDropdownModule,
|
||||
SharedModule,
|
||||
PipeModule,
|
||||
SidenavModule,
|
||||
UserSettingsModule // API-key componet
|
||||
UserSettingsModule, // API-key componet
|
||||
],
|
||||
providers: []
|
||||
})
|
||||
|
@ -47,6 +47,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="swagger-ui" class="form-label" aria-describedby="swaggerui-info">Expose Swagger UI</label>
|
||||
<p class="accent" id="swaggerui-info">Allows Swagger UI to be exposed via swagger/ on your server. Authentication is not required, but a valid JWT token is. Requires a restart to take effect.</p>
|
||||
<div class="form-check form-switch">
|
||||
<input id="swagger-ui" type="checkbox" class="form-check-input" formControlName="enableSwaggerUi" role="switch">
|
||||
<label for="swagger-ui" class="form-check-label">Enable Swagger UI</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TODO: Move this to Plugins tab once we build out some basic tables -->
|
||||
<div class="mb-3">
|
||||
<label for="opds" aria-describedby="opds-info" class="form-label">OPDS</label>
|
||||
|
@ -3,8 +3,7 @@ import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { ConfirmService } from 'src/app/shared/confirm.service';
|
||||
import { EmailTestResult, SettingsService } from '../settings.service';
|
||||
import { SettingsService } from '../settings.service';
|
||||
import { DirectoryPickerComponent, DirectoryPickerResult } from '../_modals/directory-picker/directory-picker.component';
|
||||
import { ServerSettings } from '../_models/server-settings';
|
||||
|
||||
@ -21,7 +20,7 @@ export class ManageSettingsComponent implements OnInit {
|
||||
taskFrequencies: Array<string> = [];
|
||||
logLevels: Array<string> = [];
|
||||
|
||||
constructor(private settingsService: SettingsService, private toastr: ToastrService, private confirmService: ConfirmService,
|
||||
constructor(private settingsService: SettingsService, private toastr: ToastrService,
|
||||
private modalService: NgbModal) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -43,6 +42,7 @@ export class ManageSettingsComponent implements OnInit {
|
||||
this.settingsForm.addControl('enableOpds', new FormControl(this.serverSettings.enableOpds, [Validators.required]));
|
||||
this.settingsForm.addControl('baseUrl', new FormControl(this.serverSettings.baseUrl, [Validators.required]));
|
||||
this.settingsForm.addControl('emailServiceUrl', new FormControl(this.serverSettings.emailServiceUrl, [Validators.required]));
|
||||
this.settingsForm.addControl('enableSwaggerUi', new FormControl(this.serverSettings.enableSwaggerUi, [Validators.required]));
|
||||
});
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ export class ManageSettingsComponent implements OnInit {
|
||||
this.settingsForm.get('enableOpds')?.setValue(this.serverSettings.enableOpds);
|
||||
this.settingsForm.get('baseUrl')?.setValue(this.serverSettings.baseUrl);
|
||||
this.settingsForm.get('emailServiceUrl')?.setValue(this.serverSettings.emailServiceUrl);
|
||||
this.settingsForm.get('enableSwaggerUi')?.setValue(this.serverSettings.enableSwaggerUi);
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
@ -92,29 +93,4 @@ export class ManageSettingsComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// resetEmailServiceUrl() {
|
||||
// this.settingsService.resetEmailServerSettings().pipe(take(1)).subscribe(async (settings: ServerSettings) => {
|
||||
// this.serverSettings.emailServiceUrl = settings.emailServiceUrl;
|
||||
// this.resetForm();
|
||||
// this.toastr.success('Email Service Reset');
|
||||
// }, (err: any) => {
|
||||
// console.error('error: ', err);
|
||||
// });
|
||||
// }
|
||||
|
||||
// testEmailServiceUrl() {
|
||||
// this.settingsService.testEmailServerSettings(this.settingsForm.get('emailServiceUrl')?.value || '').pipe(take(1)).subscribe(async (result: EmailTestResult) => {
|
||||
// if (result.successful) {
|
||||
// this.toastr.success('Email Service Url validated');
|
||||
// } else {
|
||||
// this.toastr.error('Email Service Url did not respond. ' + result.errorMessage);
|
||||
// }
|
||||
|
||||
// }, (err: any) => {
|
||||
// console.error('error: ', err);
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user