mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 21:33:15 -07:00
commit
cf4d0acc6a
12 changed files with 129 additions and 32 deletions
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -1,5 +1,26 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## (unreleased)
|
||||||
|
|
||||||
|
### **New Features**
|
||||||
|
|
||||||
|
- Added a default set of root folders and qualities for Anime in Sonarr. [Jamie Rees]
|
||||||
|
|
||||||
|
### **Fixes**
|
||||||
|
|
||||||
|
- Fixed #2243 The refresh metadata was being run everytime we launched Ombi... [Jamie]
|
||||||
|
|
||||||
|
- Fixed a issue where the Plex Content Sync wouldn't pick up new shows #2276 #2244 #2261. [Jamie]
|
||||||
|
|
||||||
|
- Sort TvRequests by latest request. [Joe Harvey]
|
||||||
|
|
||||||
|
- Fixed build. [Jamie Rees]
|
||||||
|
|
||||||
|
- Fix newsletter card background overflow when only one item is available. [Anojh]
|
||||||
|
|
||||||
|
- Fix #1745. [Anojh]
|
||||||
|
|
||||||
|
|
||||||
## v3.0.3330 (2018-05-17)
|
## v3.0.3330 (2018-05-17)
|
||||||
|
|
||||||
### **New Features**
|
### **New Features**
|
||||||
|
|
|
@ -142,7 +142,8 @@ namespace Ombi.Core.Engine
|
||||||
.Include(x => x.ChildRequests)
|
.Include(x => x.ChildRequests)
|
||||||
.ThenInclude(x => x.SeasonRequests)
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
|
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||||
|
.Skip(position).Take(count).ToListAsync();
|
||||||
|
|
||||||
// Filter out children
|
// Filter out children
|
||||||
|
|
||||||
|
@ -154,7 +155,8 @@ namespace Ombi.Core.Engine
|
||||||
.Include(x => x.ChildRequests)
|
.Include(x => x.ChildRequests)
|
||||||
.ThenInclude(x => x.SeasonRequests)
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
|
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||||
|
.Skip(position).Take(count).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||||
|
@ -172,6 +174,7 @@ namespace Ombi.Core.Engine
|
||||||
.Include(x => x.ChildRequests)
|
.Include(x => x.ChildRequests)
|
||||||
.ThenInclude(x => x.SeasonRequests)
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
|
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||||
.Skip(position).Take(count).ToListAsync();
|
.Skip(position).Take(count).ToListAsync();
|
||||||
|
|
||||||
FilterChildren(allRequests, shouldHide);
|
FilterChildren(allRequests, shouldHide);
|
||||||
|
@ -182,6 +185,7 @@ namespace Ombi.Core.Engine
|
||||||
.Include(x => x.ChildRequests)
|
.Include(x => x.ChildRequests)
|
||||||
.ThenInclude(x => x.SeasonRequests)
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
|
.OrderByDescending(x => x.ChildRequests.Max(y => y.RequestedDate))
|
||||||
.Skip(position).Take(count).ToListAsync();
|
.Skip(position).Take(count).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,17 +118,31 @@ namespace Ombi.Core.Senders
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int.TryParse(s.QualityProfile, out var qualityToUse);
|
int qualityToUse;
|
||||||
|
string rootFolderPath;
|
||||||
|
|
||||||
|
if (model.SeriesType == SeriesType.Anime)
|
||||||
|
{
|
||||||
|
// Get the root path from the rootfolder selected.
|
||||||
|
// For some reason, if we haven't got one use the first root folder in Sonarr
|
||||||
|
// TODO make this overrideable via the UI
|
||||||
|
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPathAnime), s);
|
||||||
|
int.TryParse(s.QualityProfileAnime, out qualityToUse);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int.TryParse(s.QualityProfile, out qualityToUse);
|
||||||
|
// Get the root path from the rootfolder selected.
|
||||||
|
// For some reason, if we haven't got one use the first root folder in Sonarr
|
||||||
|
// TODO make this overrideable via the UI
|
||||||
|
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
|
||||||
|
}
|
||||||
|
|
||||||
if (model.ParentRequest.QualityOverride.HasValue)
|
if (model.ParentRequest.QualityOverride.HasValue)
|
||||||
{
|
{
|
||||||
qualityToUse = model.ParentRequest.QualityOverride.Value;
|
qualityToUse = model.ParentRequest.QualityOverride.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the root path from the rootfolder selected.
|
|
||||||
// For some reason, if we haven't got one use the first root folder in Sonarr
|
|
||||||
// TODO make this overrideable via the UI
|
|
||||||
var rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Does the series actually exist?
|
// Does the series actually exist?
|
||||||
|
@ -160,13 +174,13 @@ namespace Ombi.Core.Senders
|
||||||
// Montitor the correct seasons,
|
// Montitor the correct seasons,
|
||||||
// If we have that season in the model then it's monitored!
|
// If we have that season in the model then it's monitored!
|
||||||
var seasonsToAdd = new List<Season>();
|
var seasonsToAdd = new List<Season>();
|
||||||
for (var i = 1; i < model.ParentRequest.TotalSeasons + 1; i++)
|
for (var i = 0; i < model.ParentRequest.TotalSeasons + 1; i++)
|
||||||
{
|
{
|
||||||
var index = i;
|
var index = i;
|
||||||
var season = new Season
|
var season = new Season
|
||||||
{
|
{
|
||||||
seasonNumber = i,
|
seasonNumber = i,
|
||||||
monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index)
|
monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index && x.SeasonNumber != 0)
|
||||||
};
|
};
|
||||||
seasonsToAdd.Add(season);
|
seasonsToAdd.Add(season);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,8 +68,6 @@ namespace Ombi.Schedule
|
||||||
RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||||
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||||
|
|
||||||
BackgroundJob.Enqueue(() => _refreshMetadata.Start());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
protected virtual void AddBackgroundInsideTable(StringBuilder sb, string url)
|
protected virtual void AddBackgroundInsideTable(StringBuilder sb, string url)
|
||||||
{
|
{
|
||||||
sb.Append("<td align=\"center\" valign=\"top\" class=\"media-card\" style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 12px; vertical-align: top; padding: 3px; width: 502px; min-width: 500px; max-width: 500px; height: 235px; \">");
|
sb.Append("<td align=\"center\" valign=\"top\" class=\"media-card\" style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 12px; vertical-align: top; padding: 3px; width: 502px; min-width: 500px; max-width: 500px; height: 235px; \">");
|
||||||
sb.AppendFormat("<table class=\"card-bg\" style=\"background-image: url({0}); border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #1f1f1f; background-position: center; background-size: cover; background-repeat: no-repeat; background-clip: padding-box; border: 2px solid rgba(255,118,27,.4); height: 248px; max-height: 500px; \">", url);
|
sb.AppendFormat("<table class=\"card-bg\" style=\"background-image: url({0}); border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 500px; background-color: #1f1f1f; background-position: center; background-size: cover; background-repeat: no-repeat; background-clip: padding-box; border: 2px solid rgba(255,118,27,.4); height: 248px; max-height: 500px; \">", url);
|
||||||
sb.Append("<tr>");
|
sb.Append("<tr>");
|
||||||
sb.Append("<td>");
|
sb.Append("<td>");
|
||||||
sb.Append("<table class=\"bg-tint\" style=\"background-color: rgba(0, 0, 0, .6); position: absolute; width: 490px; height: 239px; \">");
|
sb.Append("<table class=\"bg-tint\" style=\"background-color: rgba(0, 0, 0, .6); position: absolute; width: 490px; height: 239px; \">");
|
||||||
|
|
|
@ -162,8 +162,10 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
Logger.LogInformation("Found some episodes, this must be a recently added sync");
|
Logger.LogInformation("Found some episodes, this must be a recently added sync");
|
||||||
|
var count = 0;
|
||||||
foreach (var epInfo in content.Metadata)
|
foreach (var epInfo in content.Metadata)
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
var grandParentKey = epInfo.grandparentRatingKey;
|
var grandParentKey = epInfo.grandparentRatingKey;
|
||||||
// Lookup the rating key
|
// Lookup the rating key
|
||||||
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, grandParentKey);
|
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, grandParentKey);
|
||||||
|
@ -174,7 +176,27 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
}
|
}
|
||||||
|
|
||||||
await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch, processedContent);
|
await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch, processedContent);
|
||||||
|
if (contentToAdd.Any())
|
||||||
|
{
|
||||||
|
await Repo.AddRange(contentToAdd, false);
|
||||||
|
if (recentlyAddedSearch)
|
||||||
|
{
|
||||||
|
foreach (var plexServerContent in contentToAdd)
|
||||||
|
{
|
||||||
|
processedContent.Add(plexServerContent.Id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
contentToAdd.Clear();
|
||||||
|
}
|
||||||
|
if (count > 200)
|
||||||
|
{
|
||||||
|
await Repo.SaveChangesAsync();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save just to make sure we don't leave anything hanging
|
||||||
|
await Repo.SaveChangesAsync();
|
||||||
|
|
||||||
await EpisodeSync.ProcessEpsiodes(content.Metadata, allEps);
|
await EpisodeSync.ProcessEpsiodes(content.Metadata, allEps);
|
||||||
}
|
}
|
||||||
|
@ -182,11 +204,32 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
// Process Shows
|
// Process Shows
|
||||||
Logger.LogInformation("Processing TV Shows");
|
Logger.LogInformation("Processing TV Shows");
|
||||||
|
var count = 0;
|
||||||
foreach (var show in content.Metadata ?? new Metadata[] { })
|
foreach (var show in content.Metadata ?? new Metadata[] { })
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch, processedContent);
|
await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch, processedContent);
|
||||||
|
|
||||||
|
if (contentToAdd.Any())
|
||||||
|
{
|
||||||
|
await Repo.AddRange(contentToAdd, false);
|
||||||
|
if (recentlyAddedSearch)
|
||||||
|
{
|
||||||
|
foreach (var plexServerContent in contentToAdd)
|
||||||
|
{
|
||||||
|
processedContent.Add(plexServerContent.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
contentToAdd.Clear();
|
||||||
|
}
|
||||||
|
if (count > 200)
|
||||||
|
{
|
||||||
|
await Repo.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Repo.SaveChangesAsync();
|
||||||
|
}
|
||||||
if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
Logger.LogInformation("Processing Movies");
|
Logger.LogInformation("Processing Movies");
|
||||||
|
@ -464,21 +507,6 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
show.title);
|
show.title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentToAdd.Count > 500 || recentlyAdded)
|
|
||||||
{
|
|
||||||
await Repo.AddRange(contentToAdd);
|
|
||||||
foreach (var plexServerContent in contentToAdd)
|
|
||||||
{
|
|
||||||
contentProcessed.Add(plexServerContent.Id);
|
|
||||||
}
|
|
||||||
contentToAdd.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentToAdd.Any())
|
|
||||||
{
|
|
||||||
await Repo.AddRange(contentToAdd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
/// The root path.
|
/// The root path.
|
||||||
/// </value>
|
/// </value>
|
||||||
public string RootPath { get; set; }
|
public string RootPath { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public string QualityProfileAnime { get; set; }
|
||||||
|
public string RootPathAnime { get; set; }
|
||||||
public bool AddOnly { get; set; }
|
public bool AddOnly { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@ namespace Ombi.Store.Repository
|
||||||
Task<T> Find(object key);
|
Task<T> Find(object key);
|
||||||
IQueryable<T> GetAll();
|
IQueryable<T> GetAll();
|
||||||
Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate);
|
Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate);
|
||||||
Task AddRange(IEnumerable<T> content);
|
Task AddRange(IEnumerable<T> content, bool save = true);
|
||||||
Task<T> Add(T content);
|
Task<T> Add(T content);
|
||||||
Task DeleteRange(IEnumerable<T> req);
|
Task DeleteRange(IEnumerable<T> req);
|
||||||
Task Delete(T request);
|
Task Delete(T request);
|
||||||
|
|
|
@ -35,11 +35,14 @@ namespace Ombi.Store.Repository
|
||||||
return await _db.FirstOrDefaultAsync(predicate);
|
return await _db.FirstOrDefaultAsync(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddRange(IEnumerable<T> content)
|
public async Task AddRange(IEnumerable<T> content, bool save = true)
|
||||||
{
|
{
|
||||||
_db.AddRange(content);
|
_db.AddRange(content);
|
||||||
|
if (save)
|
||||||
|
{
|
||||||
await _ctx.SaveChangesAsync();
|
await _ctx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<T> Add(T content)
|
public async Task<T> Add(T content)
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,8 +65,10 @@ export interface ISonarrSettings extends IExternalSettings {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
qualityProfile: string;
|
qualityProfile: string;
|
||||||
|
qualityProfileAnime: string;
|
||||||
seasonFolders: boolean;
|
seasonFolders: boolean;
|
||||||
rootPath: string;
|
rootPath: string;
|
||||||
|
rootPathAnime: string;
|
||||||
fullRootPath: string;
|
fullRootPath: string;
|
||||||
addOnly: boolean;
|
addOnly: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,14 @@
|
||||||
<small *ngIf="form.get('qualityProfile').hasError('required')" class="error-text">A Default Quality Profile is required</small>
|
<small *ngIf="form.get('qualityProfile').hasError('required')" class="error-text">A Default Quality Profile is required</small>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="select" class="control-label">Quality Profiles (Anime)</label>
|
||||||
|
<div id="qualityProfileAnime">
|
||||||
|
<select class="form-control form-control-custom" id="qualityProfileAnime" formControlName="qualityProfileAnime">
|
||||||
|
<option *ngFor="let quality of qualities" value="{{quality.id}}" >{{quality.name}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div>
|
<div>
|
||||||
|
@ -85,6 +93,15 @@
|
||||||
<small *ngIf="form.get('rootPath').hasError('required')" class="error-text">A Default Root Path is required</small>
|
<small *ngIf="form.get('rootPath').hasError('required')" class="error-text">A Default Root Path is required</small>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="rootFoldersAnime" class="control-label">Default Root Folders (Anime)</label>
|
||||||
|
<div id="rootFoldersAnime">
|
||||||
|
<select class="form-control form-control-custom" formControlName="rootPathAnime">
|
||||||
|
<option *ngFor="let folder of rootFoldersAnime" value="{{folder.id}}">{{folder.path}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -15,7 +15,9 @@ import { SettingsService } from "../../services";
|
||||||
export class SonarrComponent implements OnInit {
|
export class SonarrComponent implements OnInit {
|
||||||
|
|
||||||
public qualities: ISonarrProfile[];
|
public qualities: ISonarrProfile[];
|
||||||
|
public qualitiesAnime: ISonarrProfile[];
|
||||||
public rootFolders: ISonarrRootFolder[];
|
public rootFolders: ISonarrRootFolder[];
|
||||||
|
public rootFoldersAnime: ISonarrRootFolder[];
|
||||||
public selectedRootFolder: ISonarrRootFolder;
|
public selectedRootFolder: ISonarrRootFolder;
|
||||||
public selectedQuality: ISonarrProfile;
|
public selectedQuality: ISonarrProfile;
|
||||||
public profilesRunning: boolean;
|
public profilesRunning: boolean;
|
||||||
|
@ -37,6 +39,8 @@ export class SonarrComponent implements OnInit {
|
||||||
apiKey: [x.apiKey, [Validators.required]],
|
apiKey: [x.apiKey, [Validators.required]],
|
||||||
qualityProfile: [x.qualityProfile, [Validators.required]],
|
qualityProfile: [x.qualityProfile, [Validators.required]],
|
||||||
rootPath: [x.rootPath, [Validators.required]],
|
rootPath: [x.rootPath, [Validators.required]],
|
||||||
|
qualityProfileAnime: [x.qualityProfileAnime],
|
||||||
|
rootPathAnime: [x.rootPathAnime],
|
||||||
ssl: [x.ssl],
|
ssl: [x.ssl],
|
||||||
subDir: [x.subDir],
|
subDir: [x.subDir],
|
||||||
ip: [x.ip, [Validators.required]],
|
ip: [x.ip, [Validators.required]],
|
||||||
|
@ -64,6 +68,7 @@ export class SonarrComponent implements OnInit {
|
||||||
.subscribe(x => {
|
.subscribe(x => {
|
||||||
this.qualities = x;
|
this.qualities = x;
|
||||||
this.qualities.unshift({ name: "Please Select", id: -1 });
|
this.qualities.unshift({ name: "Please Select", id: -1 });
|
||||||
|
this.qualitiesAnime = x;
|
||||||
|
|
||||||
this.profilesRunning = false;
|
this.profilesRunning = false;
|
||||||
this.notificationService.success("Successfully retrieved the Quality Profiles");
|
this.notificationService.success("Successfully retrieved the Quality Profiles");
|
||||||
|
@ -76,6 +81,7 @@ export class SonarrComponent implements OnInit {
|
||||||
.subscribe(x => {
|
.subscribe(x => {
|
||||||
this.rootFolders = x;
|
this.rootFolders = x;
|
||||||
this.rootFolders.unshift({ path: "Please Select", id: -1 });
|
this.rootFolders.unshift({ path: "Please Select", id: -1 });
|
||||||
|
this.rootFoldersAnime = x;
|
||||||
|
|
||||||
this.rootFoldersRunning = false;
|
this.rootFoldersRunning = false;
|
||||||
this.notificationService.success("Successfully retrieved the Root Folders");
|
this.notificationService.success("Successfully retrieved the Root Folders");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue