diff --git a/backend/src/Migrations/Migrations/MongoDb/ConvertDocumentIds.cs b/backend/src/Migrations/Migrations/MongoDb/ConvertDocumentIds.cs index 37799a14d..7465af658 100644 --- a/backend/src/Migrations/Migrations/MongoDb/ConvertDocumentIds.cs +++ b/backend/src/Migrations/Migrations/MongoDb/ConvertDocumentIds.cs @@ -13,6 +13,7 @@ using MongoDB.Bson; using MongoDB.Driver; using Squidex.Infrastructure; using Squidex.Infrastructure.Migrations; +using Squidex.Infrastructure.MongoDb; namespace Migrations.Migrations.MongoDb { @@ -82,6 +83,11 @@ namespace Migrations.Migrations.MongoDb var collectionOld = database.GetCollection(collectionNameOld); var collectionNew = database.GetCollection(collectionNameNew); + if (!await collectionOld.AnyAsync()) + { + return; + } + await collectionNew.DeleteManyAsync(new BsonDocument()); var batchBlock = new BatchBlock(SizeOfBatch, new GroupingDataflowBlockOptions diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs index 4c829a29f..0da0dd8e8 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs @@ -35,6 +35,13 @@ namespace Squidex.Infrastructure.MongoDb return await collections.AnyAsync(); } + public static Task AnyAsync(this IMongoCollection collection) + { + var find = collection.Find(new BsonDocument()).Limit(1); + + return find.AnyAsync(); + } + public static async Task InsertOneIfNotExistsAsync(this IMongoCollection collection, T document, CancellationToken ct = default) { try diff --git a/frontend/app/features/assets/pages/assets-page.component.ts b/frontend/app/features/assets/pages/assets-page.component.ts index 4527eda35..3cf4f5b76 100644 --- a/frontend/app/features/assets/pages/assets-page.component.ts +++ b/frontend/app/features/assets/pages/assets-page.component.ts @@ -6,7 +6,7 @@ */ import { Component, OnInit } from '@angular/core'; -import { AssetsState, DialogModel, LocalStoreService, Queries, Query, QueryFullTextSynchronizer, ResourceOwner, Router2State, UIState } from '@app/shared'; +import { AssetsState, DialogModel, LocalStoreService, MathHelper, Queries, Query, QueryFullTextSynchronizer, ResourceOwner, Router2State, UIState } from '@app/shared'; import { Settings } from '@app/shared/state/settings'; @Component({ @@ -39,7 +39,7 @@ export class AssetsPageComponent extends ResourceOwner implements OnInit { const initial = this.assetsRoute.mapTo(this.assetsState) .withPaging('assets', 30) - .withString('parentId') + .withStringOr('parentId', MathHelper.EMPTY_GUID) .withStrings('tagsSelected') .withSynchronizer(QueryFullTextSynchronizer.INSTANCE) .getInitial(); diff --git a/frontend/app/framework/angular/routers/router-2-state.spec.ts b/frontend/app/framework/angular/routers/router-2-state.spec.ts index 00b8c0b5d..8a3d3feb6 100644 --- a/frontend/app/framework/angular/routers/router-2-state.spec.ts +++ b/frontend/app/framework/angular/routers/router-2-state.spec.ts @@ -13,7 +13,7 @@ import { PagingSynchronizer, QueryParams, Router2State, StringKeysSynchronizer, describe('Router2State', () => { describe('Strings', () => { - const synchronizer = new StringSynchronizer('key'); + const synchronizer = new StringSynchronizer('key', 'fallback'); it('should parse from state', () => { const value = 'my-string'; @@ -38,6 +38,22 @@ describe('Router2State', () => { expect(value).toEqual({ key: 'my-string' }); }); + + it('should not get fallback from route if empty', () => { + const params: QueryParams = { key: '' }; + + const value = synchronizer.parseFromRoute(params); + + expect(value).toEqual({ key: '' }); + }); + + it('should get fallback from route if not found', () => { + const params: QueryParams = { other: 'my-string' }; + + const value = synchronizer.parseFromRoute(params); + + expect(value).toEqual({ key: 'fallback' }); + }); }); describe('StringKeys', () => { diff --git a/frontend/app/framework/angular/routers/router-2-state.ts b/frontend/app/framework/angular/routers/router-2-state.ts index c4d7f862c..29faf3af4 100644 --- a/frontend/app/framework/angular/routers/router-2-state.ts +++ b/frontend/app/framework/angular/routers/router-2-state.ts @@ -81,11 +81,16 @@ export class StringSynchronizer implements RouteSynchronizer { } constructor( - private readonly key: string + private readonly key: string, + private readonly fallback?: string ) { } public parseFromRoute(params: QueryParams) { + if (!params.hasOwnProperty(this.key)) { + return { [this.key]: this.fallback }; + } + const value = params[this.key]; return { [this.key]: value }; @@ -257,6 +262,10 @@ export class Router2StateMap implements StateSynchronizerMap { private loadInternal(isReload: boolean): Observable { this.next({ isLoading: true }); - const { page, pageSize, query, tagsSelected } = this.snapshot; - - const q: any = { take: pageSize, skip: pageSize * page }; - - const hasQuery = !!query?.fullText || Object.keys(tagsSelected).length > 0; - - if (hasQuery) { - if (query) { - q.query = query; - } - - const searchTags = Object.keys(this.snapshot.tagsSelected); - - if (searchTags.length > 0) { - q.tags = searchTags; - } - } else { - q.parentId = this.snapshot.parentId; - } + const query = createQuery(this.snapshot); const assets$ = - this.assetsService.getAssets(this.appName, q); + this.assetsService.getAssets(this.appName, query); const assetFolders$ = - !hasQuery ? + query.parentId ? this.assetsService.getAssetFolders(this.appName, this.snapshot.parentId) : of(EMPTY_FOLDERS); const tags$ = - !hasQuery || !this.snapshot.isLoadedOnce ? + query.parentId || !this.snapshot.isLoadedOnce ? this.assetsService.getTags(this.appName) : of(this.snapshot.tagsAvailable); @@ -449,6 +431,35 @@ function updateTags(snapshot: Snapshot, newAsset?: AssetDto, oldAsset?: AssetDto return { tagsAvailable, tagsSelected }; } +function createQuery(snapshot: Snapshot) { + const { + page, + pageSize, + query, + tagsSelected + } = snapshot; + + const result: any = { take: pageSize, skip: pageSize * page }; + + const hasQuery = !!query?.fullText || Object.keys(tagsSelected).length > 0; + + if (hasQuery) { + if (query) { + result.query = query; + } + + const searchTags = Object.keys(snapshot.tagsSelected); + + if (searchTags.length > 0) { + result.tags = searchTags; + } + } else { + result.parentId = snapshot.parentId; + } + + return result; +} + function getParent(path: ReadonlyArray) { if (path.length > 1) { return { folderName: 'i18n:assets.specialFolder.parent', id: path[path.length - 2].id };