From 48380126923e64756ba65cb654ec13b2f9143b9a Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Fri, 10 Mar 2023 18:54:32 +0300 Subject: [PATCH 01/20] tasks done #15935 --- npm/ng-packs/packages/core/src/lib/models/common.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index 12318357dd..59c1595195 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -66,10 +66,16 @@ export namespace ABP { invisible?: boolean; } + export interface GroupedRoute { + key: string; + text: string; + } + export interface Route extends Nav { path?: string; layout?: eLayoutType; iconClass?: string; + group?: GroupedRoute; } export interface Tab extends Nav { From 6952da5d79b33d0f86c83189b53fdf140f79a6e1 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Fri, 10 Mar 2023 19:12:28 +0300 Subject: [PATCH 02/20] model name updated --- npm/ng-packs/packages/core/src/lib/models/common.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index 59c1595195..e239be2092 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -66,7 +66,7 @@ export namespace ABP { invisible?: boolean; } - export interface GroupedRoute { + export interface Group { key: string; text: string; } @@ -75,7 +75,7 @@ export namespace ABP { path?: string; layout?: eLayoutType; iconClass?: string; - group?: GroupedRoute; + group?: Group; } export interface Tab extends Nav { From 22e0a3d78bcbb4cfc49008031f99dd7865e8d652 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Fri, 10 Mar 2023 19:52:52 +0300 Subject: [PATCH 03/20] ABP.Group model modified --- npm/ng-packs/packages/core/src/lib/models/common.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index e239be2092..f7aa504c3d 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -66,8 +66,8 @@ export namespace ABP { invisible?: boolean; } - export interface Group { - key: string; + export interface Group { + key: TKey; text: string; } @@ -75,7 +75,7 @@ export namespace ABP { path?: string; layout?: eLayoutType; iconClass?: string; - group?: Group; + group?: Group; } export interface Tab extends Nav { From 9d6ccd0557b5812001cbcae05ea19e92f20408a7 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Mon, 13 Mar 2023 10:50:47 +0300 Subject: [PATCH 04/20] document task done #15938 --- docs/en/UI/Angular/Modifying-the-Menu.md | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index b0a3b760fa..8278f38722 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -88,6 +88,41 @@ function configureRoutes(routes: RoutesService) { } ``` +Also we can define group for navigation elements. It's an optional property + +```js +// route.provider.ts +import { ABP } from '@abp/ng.core'; + +type GroupType = ABP.Group; + +function configureRoutes(routes: RoutesService) { + const myGroup: GroupType = { key:'groupKey', text:'GroupName' }; + + return () => { + routes.add([ + { + path: '/your-path', + name: 'Your navigation', + requiredPolicy: 'permission key here', + order: 101, + iconClass: 'fas fa-question-circle', + layout: eLayoutType.application, + group: myGroup + }, + { + path: '/your-path/child', + name: 'Your child navigation', + parentName: 'Your navigation', + requiredPolicy: 'permission key here', + order: 1, + }, + ]); + }; +} +``` + + ...and then in app.module.ts... ```js @@ -111,6 +146,9 @@ Here is what every property works as: - `iconClass` is the class of the `i` tag, which is placed to the left of the navigation label. - `layout` defines in which layout the route will be loaded. (default: `eLayoutType.empty`) - `invisible` makes the item invisible in the menu. (default: `false`) +- `group` is an optional property that is used to group together related routes in an application. It's an object and it have 2 property + - `key` is a generic type property that we use for gather items in same group. (default type: `string`) + - `text` is the display name on menu ### Via `routes` Property in `AppRoutingModule` From 81adbaddd9ce06896f19e026b8831ffa98e40d42 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Mon, 13 Mar 2023 14:53:17 +0300 Subject: [PATCH 05/20] Test done #15938 --- .../core/src/lib/tests/routes.service.spec.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts index 51c81a5b3c..1f3bb79362 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts @@ -1,11 +1,14 @@ import { Subject } from 'rxjs'; import { take } from 'rxjs/operators'; +import { ABP } from '../models'; import { RoutesService } from '../services/routes.service'; import { DummyInjector } from './utils/common.utils'; import { mockPermissionService } from './utils/permission-service.spec.utils'; const updateStream$ = new Subject(); +type GroupType = ABP.Group; + export const mockRoutesService = (injectorPayload = {} as { [key: string]: any }) => { const injector = new DummyInjector({ PermissionService: mockPermissionService(), @@ -17,6 +20,10 @@ export const mockRoutesService = (injectorPayload = {} as { [key: string]: any } describe('Routes Service', () => { let service: RoutesService; + + const fooGroup: GroupType = { key: 'foo', text: '::FooGroup' }; + const barGroup: GroupType = { key: 'bar', text: '::BarGroup' }; + const routes = [ { path: '/foo', name: 'foo' }, { path: '/foo/bar', name: 'bar', parentName: 'foo', invisible: true, order: 2 }, @@ -25,6 +32,13 @@ describe('Routes Service', () => { { path: '/foo/x', name: 'x', parentName: 'foo', order: 1 }, ]; + const groupedRoutes = [ + { path: '/foo', name: 'foo', group: fooGroup }, + { path: '/foo/bar', name: 'bar', group: barGroup }, + { path: '/foo/bar/baz', name: 'baz', group: barGroup }, + { path: '/foo/y', name: 'y', parentName: 'foo' }, + ]; + beforeEach(() => { service = mockRoutesService(); }); @@ -59,6 +73,18 @@ describe('Routes Service', () => { }); }); + describe('#addGroup', () => { + it('should have routes with and without group', async () => { + service.add(groupedRoutes); + + const grouped = await service.flat.filter(f => f.group); + const unGrouped = await service.flat.filter(f => !f.group); + + expect(grouped.length).toBe(3); + expect(unGrouped.length).toBe(1); + }); + }); + describe('#find', () => { it('should return node found based on query', () => { service.add(routes); From 41c75fa199f7efbf1d9965ce664f008781335149 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Thu, 16 Mar 2023 12:36:17 +0300 Subject: [PATCH 06/20] created injection token for others group, model updated, created "groupedTree" getter to routes.service --- .../packages/core/src/lib/models/common.ts | 6 ++++ .../core/src/lib/services/routes.service.ts | 35 +++++++++++++++++-- .../packages/core/src/lib/tokens/index.ts | 1 + .../core/src/lib/tokens/others-group.token.ts | 4 +++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index f7aa504c3d..bf366b9cd4 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -2,6 +2,7 @@ import { EventEmitter, Type } from '@angular/core'; import { Routes } from '@angular/router'; import { Subject } from 'rxjs'; import { eLayoutType } from '../enums/common'; +import { TreeNode } from '../utils'; import { Environment } from './environment'; export namespace ABP { @@ -78,6 +79,11 @@ export namespace ABP { group?: Group; } + export interface RouteGroup { + group: Group; + items: TreeNode[]; + } + export interface Tab extends Nav { component: Type; } diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 32f8b473d0..1fcaea5371 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -1,13 +1,14 @@ -import { Injectable, Injector, OnDestroy } from '@angular/core'; +import { Injectable, Injector, inject, OnDestroy } from '@angular/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { ABP } from '../models/common'; +import { OTHERS_GROUP } from '../tokens'; import { pushValueTo } from '../utils/array-utils'; import { BaseTreeNode, createTreeFromList, TreeNode } from '../utils/tree-utils'; import { ConfigStateService } from './config-state.service'; import { PermissionService } from './permission.service'; // eslint-disable-next-line @typescript-eslint/ban-types -export abstract class AbstractTreeService { +export abstract class AbstractTreeService { abstract id: string; abstract parentId: string; abstract hide: (item: T) => boolean; @@ -180,4 +181,32 @@ export abstract class AbstractNavTreeService } @Injectable({ providedIn: 'root' }) -export class RoutesService extends AbstractNavTreeService {} +export class RoutesService extends AbstractNavTreeService { + private readonly othersGroup: ABP.Group = inject(OTHERS_GROUP, { + optional: true, + }); + + get groupedTree(): ABP.RouteGroup[] { + const groupTree = this.visible.filter(node => node.group); + if (groupTree.length < 1) return; + + const map = new Map[]>(groupTree?.map(node => [node.group, []])); + const otherGroup = this.othersGroup || { key: 'others', text: '::Others' }; + map.set(otherGroup, []); + + for (const node of this.visible) { + const { path, children, group } = node; + + if (!group && (children?.length > 0 || path)) { + map.get(otherGroup)?.push(node); + } else if (group) { + map.get(group)?.push(node); + } + } + + return Array.from(map.entries()).map(([group, nodes]) => ({ + group, + items: nodes, + })); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/tokens/index.ts b/npm/ng-packs/packages/core/src/lib/tokens/index.ts index f0e724259a..d01f652b98 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/index.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/index.ts @@ -12,3 +12,4 @@ export * from './pipe-to-login.token'; export * from './set-token-response-to-storage.token'; export * from './check-authentication-state'; export * from './http-context.token'; +export * from './others-group.token' \ No newline at end of file diff --git a/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts new file mode 100644 index 0000000000..396bb3db13 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts @@ -0,0 +1,4 @@ +import { InjectionToken } from '@angular/core'; +import { ABP } from '../models'; + +export const OTHERS_GROUP = new InjectionToken('OTHERS_GROUP'); From e4b962901c7bb986cd56572c524193e0e1246bed Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Thu, 16 Mar 2023 14:09:02 +0300 Subject: [PATCH 07/20] routes service & test updated --- .../core/src/lib/services/routes.service.ts | 13 ++++--- .../core/src/lib/tests/routes.service.spec.ts | 35 +++++++++++++++---- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 1fcaea5371..2f2381a3d5 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Injector, inject, OnDestroy } from '@angular/core'; +import { Injectable, Injector, Inject, Optional, OnDestroy } from '@angular/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { ABP } from '../models/common'; import { OTHERS_GROUP } from '../tokens'; @@ -182,11 +182,14 @@ export abstract class AbstractNavTreeService @Injectable({ providedIn: 'root' }) export class RoutesService extends AbstractNavTreeService { - private readonly othersGroup: ABP.Group = inject(OTHERS_GROUP, { - optional: true, - }); + constructor( + injector: Injector, + @Optional() @Inject(OTHERS_GROUP) private readonly othersGroup: ABP.Group, + ) { + super(injector); + } - get groupedTree(): ABP.RouteGroup[] { + get groupedVisible(): ABP.RouteGroup[] { const groupTree = this.visible.filter(node => node.group); if (groupTree.length < 1) return; diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts index 1f3bb79362..b07aa05544 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts @@ -15,14 +15,15 @@ export const mockRoutesService = (injectorPayload = {} as { [key: string]: any } ConfigStateService: { createOnUpdateStream: () => updateStream$ }, ...injectorPayload, }); - return new RoutesService(injector); + const othersGroup: ABP.Group = { key: 1, text: 'Others' }; + return new RoutesService(injector, othersGroup); }; describe('Routes Service', () => { let service: RoutesService; - const fooGroup: GroupType = { key: 'foo', text: '::FooGroup' }; - const barGroup: GroupType = { key: 'bar', text: '::BarGroup' }; + const fooGroup: GroupType = { key: 'foo', text: 'FooGroup' }; + const barGroup: GroupType = { key: 'bar', text: 'BarGroup' }; const routes = [ { path: '/foo', name: 'foo' }, @@ -34,9 +35,10 @@ describe('Routes Service', () => { const groupedRoutes = [ { path: '/foo', name: 'foo', group: fooGroup }, + { path: '/foo/y', name: 'y', parentName: 'foo' }, { path: '/foo/bar', name: 'bar', group: barGroup }, { path: '/foo/bar/baz', name: 'baz', group: barGroup }, - { path: '/foo/y', name: 'y', parentName: 'foo' }, + { path: '/foo/z', name: 'z' }, ]; beforeEach(() => { @@ -77,14 +79,35 @@ describe('Routes Service', () => { it('should have routes with and without group', async () => { service.add(groupedRoutes); - const grouped = await service.flat.filter(f => f.group); - const unGrouped = await service.flat.filter(f => !f.group); + const grouped = service.visible.filter(f => f.group); + const unGrouped = service.visible.filter(f => !f.group); expect(grouped.length).toBe(3); expect(unGrouped.length).toBe(1); }); }); + describe('#groupedVisible', () => { + it('should have groups and items', async () => { + service.add(groupedRoutes); + + const tree = service.groupedVisible; + + expect(tree.length).toBe(3); + + expect(tree[0].group.key).toBe('foo'); + expect(tree[0].group.text).toBe('FooGroup'); + expect(tree[0].items[0].children[0].name).toBe('y'); + + expect(tree[1].group.key).toBe('bar'); + expect(tree[1].group.text).toBe('BarGroup'); + + expect(tree[2].group.key).toBe(1); + expect(tree[2].group.text).toBe('Others'); + expect(tree[2].items[0].name).toBe('z'); + }); + }); + describe('#find', () => { it('should return node found based on query', () => { service.add(routes); From 7b625e1d237497028b395cc342efbdb5de7b7a7a Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Thu, 16 Mar 2023 15:29:46 +0300 Subject: [PATCH 08/20] routes service & test updated, model updated, added docs for routes service --- docs/en/UI/Angular/Modifying-the-Menu.md | 24 ++++++++++++++++++- .../packages/core/src/lib/core.module.ts | 5 ++++ .../packages/core/src/lib/models/common.ts | 1 + .../core/src/lib/services/routes.service.ts | 4 ++-- .../core/src/lib/tests/routes.service.spec.ts | 7 ++++-- 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index 8278f38722..b3ab040910 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -122,15 +122,37 @@ function configureRoutes(routes: RoutesService) { } ``` +To get route items as grouped we can use `groupedVisible` getter method + - It will return `RouteGroup[]` if there is any group in route tree otherwise it'll return undefined + +```js +import { ABP, RoutesService } from "@abp/ng.core"; +import { Component } from "@angular/core"; + +@Component(/* component metadata */) +export class AppComponent { + visible: ABP.RouteGroup[] | undefined = routes.groupedVisible; + + constructor(routes: RoutesService) {} +} +``` ...and then in app.module.ts... + - `groupedVisible` method will return `Others` group for ungrouped items, we can define `key` and `text` via `OTHERS_GROUP` injection token for this group ```js import { NgModule } from '@angular/core'; +import { ABP, OTHERS_GROUP } from '@abp/ng.core'; import { APP_ROUTE_PROVIDER } from './route.provider'; @NgModule({ - providers: [APP_ROUTE_PROVIDER], + providers: [ + APP_ROUTE_PROVIDER, + { + provide: OTHERS_GROUP, + useValue: { key: 1, text: 'MyOthersGroup' } as ABP.Group, + }, + ], // imports, declarations, and bootstrap }) export class AppModule {} diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index e3cd895022..0b3747455a 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -24,6 +24,7 @@ import { ToInjectorPipe } from './pipes/to-injector.pipe'; import { CookieLanguageProvider } from './providers/cookie-language.provider'; import { LocaleProvider } from './providers/locale.provider'; import { LocalizationService } from './services/localization.service'; +import { OTHERS_GROUP } from './tokens'; import { localizationContributor, LOCALIZATIONS } from './tokens/localization.token'; import { CORE_OPTIONS, coreOptionsFactory } from './tokens/options.token'; import { TENANT_KEY } from './tokens/tenant-key.token'; @@ -176,6 +177,10 @@ export class CoreModule { provide: QUEUE_MANAGER, useClass: DefaultQueueManager, }, + { + provide: OTHERS_GROUP, + useValue: options.othersGroup || { key: 'others', text: '::Others' } as ABP.Group, + }, IncludeLocalizationResourcesProvider, ], }; diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index bf366b9cd4..13d7d8bdc2 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -13,6 +13,7 @@ export namespace ABP { sendNullsAsQueryParam?: boolean; tenantKey?: string; localizations?: Localization[]; + othersGroup?: Group; } export interface Child { diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 2f2381a3d5..d36228891e 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -189,12 +189,12 @@ export class RoutesService extends AbstractNavTreeService { super(injector); } - get groupedVisible(): ABP.RouteGroup[] { + get groupedVisible(): ABP.RouteGroup[] | undefined { const groupTree = this.visible.filter(node => node.group); if (groupTree.length < 1) return; const map = new Map[]>(groupTree?.map(node => [node.group, []])); - const otherGroup = this.othersGroup || { key: 'others', text: '::Others' }; + const otherGroup = this.othersGroup; map.set(otherGroup, []); for (const node of this.visible) { diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts index b07aa05544..a45b4d6d36 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts @@ -15,8 +15,8 @@ export const mockRoutesService = (injectorPayload = {} as { [key: string]: any } ConfigStateService: { createOnUpdateStream: () => updateStream$ }, ...injectorPayload, }); - const othersGroup: ABP.Group = { key: 1, text: 'Others' }; - return new RoutesService(injector, othersGroup); + const othersGroupToken: ABP.Group = { key: 1, text: 'Others' }; + return new RoutesService(injector, othersGroupToken); }; describe('Routes Service', () => { @@ -97,10 +97,13 @@ describe('Routes Service', () => { expect(tree[0].group.key).toBe('foo'); expect(tree[0].group.text).toBe('FooGroup'); + expect(tree[0].items[0].name).toBe('foo'); expect(tree[0].items[0].children[0].name).toBe('y'); expect(tree[1].group.key).toBe('bar'); expect(tree[1].group.text).toBe('BarGroup'); + expect(tree[1].items[0].name).toBe('bar'); + expect(tree[1].items[1].name).toBe('baz'); expect(tree[2].group.key).toBe(1); expect(tree[2].group.text).toBe('Others'); From 309eeada03b8a0eaa0768fbcfa910d644f56c3ff Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Fri, 24 Mar 2023 15:43:43 +0300 Subject: [PATCH 09/20] grouped menu feature refactored document updated test updated --- docs/en/UI/Angular/Modifying-the-Menu.md | 23 ++++------- .../packages/core/src/lib/core.module.ts | 2 +- .../packages/core/src/lib/models/common.ts | 13 ++---- .../core/src/lib/services/routes.service.ts | 40 ++++++------------- .../core/src/lib/tests/routes.service.spec.ts | 32 ++++----------- .../core/src/lib/tokens/others-group.token.ts | 3 +- 6 files changed, 33 insertions(+), 80 deletions(-) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index b3ab040910..b084f75781 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -96,19 +96,12 @@ import { ABP } from '@abp/ng.core'; type GroupType = ABP.Group; -function configureRoutes(routes: RoutesService) { - const myGroup: GroupType = { key:'groupKey', text:'GroupName' }; - +function configureRoutes(routes: RoutesService) { return () => { routes.add([ { - path: '/your-path', - name: 'Your navigation', - requiredPolicy: 'permission key here', - order: 101, - iconClass: 'fas fa-question-circle', - layout: eLayoutType.application, - group: myGroup + //etc.. + group: 'ModuleName::GroupName' }, { path: '/your-path/child', @@ -138,11 +131,11 @@ export class AppComponent { ``` ...and then in app.module.ts... - - `groupedVisible` method will return `Others` group for ungrouped items, we can define `key` and `text` via `OTHERS_GROUP` injection token for this group + - `groupedVisible` method will return `Others` group for ungrouped items, Default key is `AbpUi::OthersGroup` we can change this `key` via `OTHERS_GROUP` injection token ```js import { NgModule } from '@angular/core'; -import { ABP, OTHERS_GROUP } from '@abp/ng.core'; +import { OTHERS_GROUP } from '@abp/ng.core'; import { APP_ROUTE_PROVIDER } from './route.provider'; @NgModule({ @@ -150,7 +143,7 @@ import { APP_ROUTE_PROVIDER } from './route.provider'; APP_ROUTE_PROVIDER, { provide: OTHERS_GROUP, - useValue: { key: 1, text: 'MyOthersGroup' } as ABP.Group, + useValue: 'ModuleName::MyOthersGroupKey', }, ], // imports, declarations, and bootstrap @@ -168,9 +161,7 @@ Here is what every property works as: - `iconClass` is the class of the `i` tag, which is placed to the left of the navigation label. - `layout` defines in which layout the route will be loaded. (default: `eLayoutType.empty`) - `invisible` makes the item invisible in the menu. (default: `false`) -- `group` is an optional property that is used to group together related routes in an application. It's an object and it have 2 property - - `key` is a generic type property that we use for gather items in same group. (default type: `string`) - - `text` is the display name on menu +- `group` is an optional property that is used to group together related routes in an application. (type: `string`, default: `AbpUi::OthersGroup`) ### Via `routes` Property in `AppRoutingModule` diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index 0b3747455a..818a464124 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -179,7 +179,7 @@ export class CoreModule { }, { provide: OTHERS_GROUP, - useValue: options.othersGroup || { key: 'others', text: '::Others' } as ABP.Group, + useValue: options.othersGroup || 'AbpUi::OthersGroup', }, IncludeLocalizationResourcesProvider, ], diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index 13d7d8bdc2..c20c6849ed 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -13,7 +13,7 @@ export namespace ABP { sendNullsAsQueryParam?: boolean; tenantKey?: string; localizations?: Localization[]; - othersGroup?: Group; + othersGroup?: string; } export interface Child { @@ -68,20 +68,15 @@ export namespace ABP { invisible?: boolean; } - export interface Group { - key: TKey; - text: string; - } - export interface Route extends Nav { path?: string; layout?: eLayoutType; iconClass?: string; - group?: Group; + group?: string; } - export interface RouteGroup { - group: Group; + export interface RouteGroup { + group: string; items: TreeNode[]; } diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index d36228891e..74b76bb40d 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Injector, Inject, Optional, OnDestroy } from '@angular/core'; +import { Injectable, Injector, Inject, OnDestroy} from '@angular/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { ABP } from '../models/common'; import { OTHERS_GROUP } from '../tokens'; @@ -182,34 +182,20 @@ export abstract class AbstractNavTreeService @Injectable({ providedIn: 'root' }) export class RoutesService extends AbstractNavTreeService { - constructor( - injector: Injector, - @Optional() @Inject(OTHERS_GROUP) private readonly othersGroup: ABP.Group, - ) { + constructor(injector: Injector, @Inject(OTHERS_GROUP) private readonly othersGroup: string) { super(injector); } - get groupedVisible(): ABP.RouteGroup[] | undefined { - const groupTree = this.visible.filter(node => node.group); - if (groupTree.length < 1) return; - - const map = new Map[]>(groupTree?.map(node => [node.group, []])); - const otherGroup = this.othersGroup; - map.set(otherGroup, []); - - for (const node of this.visible) { - const { path, children, group } = node; - - if (!group && (children?.length > 0 || path)) { - map.get(otherGroup)?.push(node); - } else if (group) { - map.get(group)?.push(node); - } - } - - return Array.from(map.entries()).map(([group, nodes]) => ({ - group, - items: nodes, - })); + const hasGroup = this.visible.some(node => !!node.group); + if (!hasGroup) return; + + const groups = this.visible.reduce((acc, node) => { + const groupName = node.group ?? this.othersGroup; + acc[groupName] ||= []; + acc[groupName].push(node); + return acc; + }, {} as Record[]>); + + return Object.entries(groups).map(([group, items]) => ({ group, items })); } } diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts index a45b4d6d36..d4871108a3 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts @@ -1,29 +1,26 @@ import { Subject } from 'rxjs'; import { take } from 'rxjs/operators'; -import { ABP } from '../models'; import { RoutesService } from '../services/routes.service'; import { DummyInjector } from './utils/common.utils'; import { mockPermissionService } from './utils/permission-service.spec.utils'; const updateStream$ = new Subject(); -type GroupType = ABP.Group; - export const mockRoutesService = (injectorPayload = {} as { [key: string]: any }) => { const injector = new DummyInjector({ PermissionService: mockPermissionService(), ConfigStateService: { createOnUpdateStream: () => updateStream$ }, ...injectorPayload, }); - const othersGroupToken: ABP.Group = { key: 1, text: 'Others' }; - return new RoutesService(injector, othersGroupToken); + return new RoutesService(injector, 'OthersGroup'); }; describe('Routes Service', () => { let service: RoutesService; - const fooGroup: GroupType = { key: 'foo', text: 'FooGroup' }; - const barGroup: GroupType = { key: 'bar', text: 'BarGroup' }; + const fooGroup = 'FooGroup'; + const barGroup = 'BarGroup'; + const othersGroup = 'OthersGroup'; const routes = [ { path: '/foo', name: 'foo' }, @@ -75,18 +72,6 @@ describe('Routes Service', () => { }); }); - describe('#addGroup', () => { - it('should have routes with and without group', async () => { - service.add(groupedRoutes); - - const grouped = service.visible.filter(f => f.group); - const unGrouped = service.visible.filter(f => !f.group); - - expect(grouped.length).toBe(3); - expect(unGrouped.length).toBe(1); - }); - }); - describe('#groupedVisible', () => { it('should have groups and items', async () => { service.add(groupedRoutes); @@ -95,18 +80,15 @@ describe('Routes Service', () => { expect(tree.length).toBe(3); - expect(tree[0].group.key).toBe('foo'); - expect(tree[0].group.text).toBe('FooGroup'); + expect(tree[0].group).toBe('FooGroup'); expect(tree[0].items[0].name).toBe('foo'); expect(tree[0].items[0].children[0].name).toBe('y'); - expect(tree[1].group.key).toBe('bar'); - expect(tree[1].group.text).toBe('BarGroup'); + expect(tree[1].group).toBe('BarGroup'); expect(tree[1].items[0].name).toBe('bar'); expect(tree[1].items[1].name).toBe('baz'); - expect(tree[2].group.key).toBe(1); - expect(tree[2].group.text).toBe('Others'); + expect(tree[2].group).toBe(othersGroup); expect(tree[2].items[0].name).toBe('z'); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts index 396bb3db13..23d7d65b92 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts @@ -1,4 +1,3 @@ import { InjectionToken } from '@angular/core'; -import { ABP } from '../models'; -export const OTHERS_GROUP = new InjectionToken('OTHERS_GROUP'); +export const OTHERS_GROUP = new InjectionToken('OTHERS_GROUP'); From bfb3b0ccd9dbf674f4e79cadbb2cd9acacc447c3 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Fri, 24 Mar 2023 17:20:02 +0300 Subject: [PATCH 10/20] test refactored --- .../packages/core/src/lib/services/routes.service.ts | 8 ++++++-- .../packages/core/src/lib/tests/routes.service.spec.ts | 6 +++--- .../packages/core/src/lib/tests/utils/common.utils.ts | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 74b76bb40d..20dc13ddfe 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Injector, Inject, OnDestroy} from '@angular/core'; +import { Injectable, Injector, OnDestroy } from '@angular/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { ABP } from '../models/common'; import { OTHERS_GROUP } from '../tokens'; @@ -182,9 +182,13 @@ export abstract class AbstractNavTreeService @Injectable({ providedIn: 'root' }) export class RoutesService extends AbstractNavTreeService { - constructor(injector: Injector, @Inject(OTHERS_GROUP) private readonly othersGroup: string) { + private readonly othersGroup: string; + + constructor(injector: Injector) { super(injector); + this.othersGroup = injector.get(OTHERS_GROUP); } + get groupedVisible(): ABP.RouteGroup[] | undefined { const hasGroup = this.visible.some(node => !!node.group); if (!hasGroup) return; diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts index d4871108a3..ac79c193ac 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts @@ -10,9 +10,10 @@ export const mockRoutesService = (injectorPayload = {} as { [key: string]: any } const injector = new DummyInjector({ PermissionService: mockPermissionService(), ConfigStateService: { createOnUpdateStream: () => updateStream$ }, + OTHERS_GROUP: 'OthersGroup', ...injectorPayload, }); - return new RoutesService(injector, 'OthersGroup'); + return new RoutesService(injector); }; describe('Routes Service', () => { @@ -71,9 +72,8 @@ describe('Routes Service', () => { expect(visible[0].children[0].name).toBe('x'); }); }); - describe('#groupedVisible', () => { - it('should have groups and items', async () => { + it('should return grouped route list', () => { service.add(groupedRoutes); const tree = service.groupedVisible; diff --git a/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts b/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts index e568b63a17..01612a987e 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts @@ -14,6 +14,6 @@ export class DummyInjector extends Injector { ): T; get(token: any, notFoundValue?: any): any; get(token, notFoundValue?, flags?: InjectFlags): any { - return this.payload[token.name || token]; + return this.payload[token.name || token._desc || token]; } } From 8ab24be0ef842c0bfd8aa59b473db8ba96401cd6 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Fri, 24 Mar 2023 17:59:52 +0300 Subject: [PATCH 11/20] Node added for modifying the menu doc. --- docs/en/UI/Angular/Modifying-the-Menu.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index b084f75781..c0ab458549 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -89,6 +89,7 @@ function configureRoutes(routes: RoutesService) { ``` Also we can define group for navigation elements. It's an optional property + - **Note:** It'll also include groups that included from modules ```js // route.provider.ts From a1b94fed05aa67e1583033e70a89473c289a4c24 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Sun, 26 Mar 2023 19:26:42 +0300 Subject: [PATCH 12/20] createGroupMap moved to tree-utils code refactored --- .../packages/core/src/lib/models/common.ts | 6 --- .../core/src/lib/services/routes.service.ts | 39 ++++++++++--------- .../core/src/lib/tests/routes.service.spec.ts | 38 +++++++++++++++--- .../packages/core/src/lib/utils/tree-utils.ts | 27 +++++++++++++ 4 files changed, 79 insertions(+), 31 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index c20c6849ed..7a285b4461 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -2,7 +2,6 @@ import { EventEmitter, Type } from '@angular/core'; import { Routes } from '@angular/router'; import { Subject } from 'rxjs'; import { eLayoutType } from '../enums/common'; -import { TreeNode } from '../utils'; import { Environment } from './environment'; export namespace ABP { @@ -75,11 +74,6 @@ export namespace ABP { group?: string; } - export interface RouteGroup { - group: string; - items: TreeNode[]; - } - export interface Tab extends Nav { component: Type; } diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 20dc13ddfe..c7acce3aee 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -1,9 +1,15 @@ import { Injectable, Injector, OnDestroy } from '@angular/core'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { BehaviorSubject, Observable, Subscription, map } from 'rxjs'; import { ABP } from '../models/common'; import { OTHERS_GROUP } from '../tokens'; import { pushValueTo } from '../utils/array-utils'; -import { BaseTreeNode, createTreeFromList, TreeNode } from '../utils/tree-utils'; +import { + BaseTreeNode, + createTreeFromList, + TreeNode, + RouteGroup, + createGroupMap, +} from '../utils/tree-utils'; import { ConfigStateService } from './config-state.service'; import { PermissionService } from './permission.service'; @@ -18,6 +24,8 @@ export abstract class AbstractTreeService[]>([]); private _visible$ = new BehaviorSubject[]>([]); + protected othersGroup: string; + get flat(): T[] { return this._flat$.value; } @@ -51,6 +59,11 @@ export abstract class AbstractTreeService[]): RouteGroup[] | undefined { + const map = createGroupMap(list, this.othersGroup); + return !map ? undefined : Array.from(map, ([key, items]) => ({ group: key, items })); + } + private filterWith(setOrMap: Set | Map): T[] { return this._flat$.value.filter(item => !setOrMap.has(item[this.id])); } @@ -158,6 +171,7 @@ export abstract class AbstractNavTreeService .createOnUpdateStream(state => state) .subscribe(() => this.refresh()); this.permissionService = injector.get(PermissionService); + this.othersGroup = injector.get(OTHERS_GROUP); } protected isGranted({ requiredPolicy }: T): boolean { @@ -182,24 +196,11 @@ export abstract class AbstractNavTreeService @Injectable({ providedIn: 'root' }) export class RoutesService extends AbstractNavTreeService { - private readonly othersGroup: string; - - constructor(injector: Injector) { - super(injector); - this.othersGroup = injector.get(OTHERS_GROUP); + get groupedVisible(): RouteGroup[] | undefined { + return this.createGroupedTree(this.visible); } - get groupedVisible(): ABP.RouteGroup[] | undefined { - const hasGroup = this.visible.some(node => !!node.group); - if (!hasGroup) return; - - const groups = this.visible.reduce((acc, node) => { - const groupName = node.group ?? this.othersGroup; - acc[groupName] ||= []; - acc[groupName].push(node); - return acc; - }, {} as Record[]>); - - return Object.entries(groups).map(([group, items]) => ({ group, items })); + get groupedVisible$(): Observable[] | undefined> { + return this.visible$.pipe(map(visible => this.createGroupedTree(visible))); } } diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts index ac79c193ac..ab9c6a76ae 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts @@ -1,4 +1,4 @@ -import { Subject } from 'rxjs'; +import { Subject, lastValueFrom } from 'rxjs'; import { take } from 'rxjs/operators'; import { RoutesService } from '../services/routes.service'; import { DummyInjector } from './utils/common.utils'; @@ -47,9 +47,9 @@ describe('Routes Service', () => { it('should add given routes as flat$, tree$, and visible$', async () => { service.add(routes); - const flat = await service.flat$.pipe(take(1)).toPromise(); - const tree = await service.tree$.pipe(take(1)).toPromise(); - const visible = await service.visible$.pipe(take(1)).toPromise(); + const flat = await lastValueFrom(service.flat$.pipe(take(1))); + const tree = await lastValueFrom(service.tree$.pipe(take(1))); + const visible = await lastValueFrom(service.visible$.pipe(take(1))); expect(flat.length).toBe(5); expect(flat[0].name).toBe('baz'); @@ -72,11 +72,37 @@ describe('Routes Service', () => { expect(visible[0].children[0].name).toBe('x'); }); }); + describe('#groupedVisible', () => { - it('should return grouped route list', () => { + it('should return undefined when there are no visible routes', async () => { + service.add(routes); + const result = await lastValueFrom(service.groupedVisible$.pipe(take(1))); + expect(result).toBeUndefined(); + }); + + it( + 'should group visible routes under "' + othersGroup + '" when no group is specified', + async () => { + service.add([ + { path: '/foo', name: 'foo' }, + { path: '/foo/bar', name: 'bar', group: '' }, + { path: '/foo/bar/baz', name: 'baz', group: undefined }, + { path: '/x', name: 'y', group: 'z' }, + ]); + + const result = await lastValueFrom(service.groupedVisible$.pipe(take(1))); + + expect(result[0].group).toBe(othersGroup); + expect(result[0].items[0].name).toBe('foo'); + expect(result[0].items[1].name).toBe('bar'); + expect(result[0].items[2].name).toBe('baz'); + }, + ); + + it('should return grouped route list', async () => { service.add(groupedRoutes); - const tree = service.groupedVisible; + const tree = await lastValueFrom(service.groupedVisible$.pipe(take(1))); expect(tree.length).toBe(3); diff --git a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts index bfc938c158..6e1261d823 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts @@ -74,6 +74,28 @@ export function createTreeNodeFilterCreator( }; } +export function createGroupMap( + list: TreeNode[], + othersGroupKey: string, +): Map[]> | undefined { + if (!list || !Array.isArray(list) || !list.some(node => Boolean(node.group))) return undefined; + + const mapGroup = new Map[]>(); + + for (const node of list) { + const group = node?.group || othersGroupKey; + if (typeof group !== 'string') { + throw new Error(`Invalid group: ${group}`); + } + + const items = mapGroup.get(group) || []; + items.push(node); + mapGroup.set(group, items); + } + + return mapGroup; +} + export type TreeNode = { [K in keyof T]: T[K]; } & { @@ -82,6 +104,11 @@ export type TreeNode = { parent?: TreeNode; }; +export type RouteGroup = { + readonly group: string; + readonly items: TreeNode[]; +}; + export type NodeKey = number | string | symbol | undefined | null; export type NodeValue any> = F extends undefined From e21e8686fce1a05f77b135d2e0bd95c96faac096 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Sun, 26 Mar 2023 20:41:16 +0300 Subject: [PATCH 13/20] Document updated --- docs/en/UI/Angular/Modifying-the-Menu.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index c0ab458549..2aec9f37e4 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -89,13 +89,11 @@ function configureRoutes(routes: RoutesService) { ``` Also we can define group for navigation elements. It's an optional property - - **Note:** It'll also include groups that included from modules + - **Note:** It'll also include groups that defined at modules ```js // route.provider.ts -import { ABP } from '@abp/ng.core'; - -type GroupType = ABP.Group; +import { RoutesService } from '@abp/ng.core'; function configureRoutes(routes: RoutesService) { return () => { @@ -116,16 +114,18 @@ function configureRoutes(routes: RoutesService) { } ``` -To get route items as grouped we can use `groupedVisible` getter method - - It will return `RouteGroup[]` if there is any group in route tree otherwise it'll return undefined +To get route items as grouped we can use `groupedVisible` (or Observable one `groupedVisible$`) getter methods + - It will return `RouteGroup[]` if there is any group in route tree otherwise it'll return `undefined` ```js -import { ABP, RoutesService } from "@abp/ng.core"; +import { ABP, RoutesService, RouteGroup } from "@abp/ng.core"; import { Component } from "@angular/core"; @Component(/* component metadata */) export class AppComponent { - visible: ABP.RouteGroup[] | undefined = routes.groupedVisible; + visible: RouteGroup[] | undefined = this.routes.groupedVisible; + //Or + visible$:Observable[] | undefined> = this.routes.groupedVisible$; constructor(routes: RoutesService) {} } From a398e302c73d9d2a9904829cb40a582aa51d462d Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Mon, 27 Mar 2023 21:53:31 +0300 Subject: [PATCH 14/20] visible list filtered & tree-utils updated --- .../packages/core/src/lib/services/routes.service.ts | 2 +- npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index c7acce3aee..27a01beecf 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -197,7 +197,7 @@ export abstract class AbstractNavTreeService @Injectable({ providedIn: 'root' }) export class RoutesService extends AbstractNavTreeService { get groupedVisible(): RouteGroup[] | undefined { - return this.createGroupedTree(this.visible); + return this.createGroupedTree(this.visible.filter(f => f.path || f.children?.length > 0)); } get groupedVisible$(): Observable[] | undefined> { diff --git a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts index 6e1261d823..0195a81112 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts @@ -1,3 +1,5 @@ +import { isArray } from './common-utils'; + /* eslint-disable @typescript-eslint/ban-types */ export class BaseTreeNode { children: TreeNode[] = []; @@ -77,8 +79,8 @@ export function createTreeNodeFilterCreator( export function createGroupMap( list: TreeNode[], othersGroupKey: string, -): Map[]> | undefined { - if (!list || !Array.isArray(list) || !list.some(node => Boolean(node.group))) return undefined; +) { + if (!isArray(list) || !list.some(node => Boolean(node.group))) return undefined; const mapGroup = new Map[]>(); From 990a211110ef4f305f6def55637a7fbd3eb30954 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Tue, 28 Mar 2023 14:08:55 +0300 Subject: [PATCH 15/20] tree-util & routes.service updated --- .../core/src/lib/services/routes.service.ts | 13 ++++++++++--- .../packages/core/src/lib/utils/tree-utils.ts | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 27a01beecf..80ee56765e 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -61,7 +61,7 @@ export abstract class AbstractTreeService[]): RouteGroup[] | undefined { const map = createGroupMap(list, this.othersGroup); - return !map ? undefined : Array.from(map, ([key, items]) => ({ group: key, items })); + return Boolean(map) ? Array.from(map, ([key, items]) => ({ group: key, items })) : undefined; } private filterWith(setOrMap: Set | Map): T[] { @@ -196,11 +196,18 @@ export abstract class AbstractNavTreeService @Injectable({ providedIn: 'root' }) export class RoutesService extends AbstractNavTreeService { + private hasPathOrChild(item: TreeNode): boolean { + return Boolean(item.path) || Boolean(item.children?.length); + } + get groupedVisible(): RouteGroup[] | undefined { - return this.createGroupedTree(this.visible.filter(f => f.path || f.children?.length > 0)); + return this.createGroupedTree(this.visible.filter(item => this.hasPathOrChild(item))); } get groupedVisible$(): Observable[] | undefined> { - return this.visible$.pipe(map(visible => this.createGroupedTree(visible))); + return this.visible$.pipe( + map(items => items.filter(item => this.hasPathOrChild(item))), + map(visible => this.createGroupedTree(visible)), + ); } } diff --git a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts index 0195a81112..8ea8cc504c 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts @@ -76,7 +76,7 @@ export function createTreeNodeFilterCreator( }; } -export function createGroupMap( +export function createGroupMap( list: TreeNode[], othersGroupKey: string, ) { From 79662c203bc4fa8900c5c48b6fd66c07bccc7ef6 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Tue, 28 Mar 2023 16:26:36 +0300 Subject: [PATCH 16/20] Document updated --- docs/en/UI/Angular/Modifying-the-Menu.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index 2aec9f37e4..2ef4d83bab 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -115,7 +115,7 @@ function configureRoutes(routes: RoutesService) { ``` To get route items as grouped we can use `groupedVisible` (or Observable one `groupedVisible$`) getter methods - - It will return `RouteGroup[]` if there is any group in route tree otherwise it'll return `undefined` + - It will return `RouteGroup[]` if there is any group in route tree otherwise it'll return `undefined` ```js import { ABP, RoutesService, RouteGroup } from "@abp/ng.core"; From 178158c0a22cdf53231299719dc64b02e2249329 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Tue, 28 Mar 2023 17:00:17 +0300 Subject: [PATCH 17/20] early pattern applied --- .../packages/core/src/lib/services/routes.service.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 80ee56765e..960ddc5266 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -61,7 +61,11 @@ export abstract class AbstractTreeService[]): RouteGroup[] | undefined { const map = createGroupMap(list, this.othersGroup); - return Boolean(map) ? Array.from(map, ([key, items]) => ({ group: key, items })) : undefined; + if (!map) { + return undefined; + } + + return Array.from(map, ([key, items]) => ({ group: key, items })); } private filterWith(setOrMap: Set | Map): T[] { From c785a560399f33f1a5acda9d30c76d42cd88f6e1 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Tue, 28 Mar 2023 17:20:28 +0300 Subject: [PATCH 18/20] minor changes --- docs/en/UI/Angular/Modifying-the-Menu.md | 2 +- npm/ng-packs/packages/core/src/lib/services/routes.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index 2ef4d83bab..12cf88efd0 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -127,7 +127,7 @@ export class AppComponent { //Or visible$:Observable[] | undefined> = this.routes.groupedVisible$; - constructor(routes: RoutesService) {} + constructor(private routes: RoutesService) {} } ``` diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 960ddc5266..329d2a370c 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -201,7 +201,7 @@ export abstract class AbstractNavTreeService @Injectable({ providedIn: 'root' }) export class RoutesService extends AbstractNavTreeService { private hasPathOrChild(item: TreeNode): boolean { - return Boolean(item.path) || Boolean(item.children?.length); + return Boolean(item.path) || this.hasChildren(item.name); } get groupedVisible(): RouteGroup[] | undefined { From a5ddbeb69f7b5315e682d1eb6275e4266464fd33 Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Tue, 28 Mar 2023 19:01:02 +0300 Subject: [PATCH 19/20] Quick Doc Fix --- docs/en/UI/Angular/Modifying-the-Menu.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index 12cf88efd0..c59ce0d650 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -88,8 +88,8 @@ function configureRoutes(routes: RoutesService) { } ``` -Also we can define group for navigation elements. It's an optional property - - **Note:** It'll also include groups that defined at modules +We can also define a group for navigation elements. It's an optional property + - **Note:** It'll also include groups that were defined at the modules ```js // route.provider.ts @@ -114,8 +114,8 @@ function configureRoutes(routes: RoutesService) { } ``` -To get route items as grouped we can use `groupedVisible` (or Observable one `groupedVisible$`) getter methods - - It will return `RouteGroup[]` if there is any group in route tree otherwise it'll return `undefined` +To get the route items as grouped we can use the `groupedVisible` (or Observable one `groupedVisible$`) getter methods + - It returns `RouteGroup[]` if there is any group in the route tree, otherwise it returns `undefined` ```js import { ABP, RoutesService, RouteGroup } from "@abp/ng.core"; @@ -132,7 +132,7 @@ export class AppComponent { ``` ...and then in app.module.ts... - - `groupedVisible` method will return `Others` group for ungrouped items, Default key is `AbpUi::OthersGroup` we can change this `key` via `OTHERS_GROUP` injection token + - The `groupedVisible` method will return the `Others` group for ungrouped items, the default key is `AbpUi::OthersGroup`, we can change this `key` via the `OTHERS_GROUP` injection token ```js import { NgModule } from '@angular/core'; @@ -160,7 +160,7 @@ Here is what every property works as: - `requiredPolicy` is the permission key to access the page. See the [Permission Management document](./Permission-Management.md) - `order` is the order of the navigation element. "Administration" has an order of `100`, so keep that in mind when ordering top level menu items. - `iconClass` is the class of the `i` tag, which is placed to the left of the navigation label. -- `layout` defines in which layout the route will be loaded. (default: `eLayoutType.empty`) +- `layout` defines in which layout the route is loaded. (default: `eLayoutType.empty`) - `invisible` makes the item invisible in the menu. (default: `false`) - `group` is an optional property that is used to group together related routes in an application. (type: `string`, default: `AbpUi::OthersGroup`) From 24b890a1790632b5be42e3e57594b939f2de32bb Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Thu, 30 Mar 2023 16:58:22 +0300 Subject: [PATCH 20/20] localization resource added for 'AbpUi::OthersGroup' key --- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json | 5 +++-- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json | 3 ++- .../src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json | 5 +++-- .../Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json | 3 ++- .../Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json | 3 ++- 26 files changed, 66 insertions(+), 40 deletions(-) diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json index 4717b1fe9b..bcbab76211 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json @@ -48,6 +48,7 @@ "Search": "بحث", "ItemWillBeDeletedMessageWithFormat": "سيتم حذف {0}!", "ItemWillBeDeletedMessage": "سوف يتم حذف هذا البند!", - "ManageYourAccount": "إدارة حسابك" + "ManageYourAccount": "إدارة حسابك", + "OthersGroup": "آخرون" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json index 1fe7ea6a23..5dc41952a6 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json @@ -48,6 +48,7 @@ "Search": "Vyhledávání", "ItemWillBeDeletedMessageWithFormat": "{0} bude smazáno!", "ItemWillBeDeletedMessage": "Tato položka bude smazána!", - "ManageYourAccount": "Spravujte svůj účet" + "ManageYourAccount": "Spravujte svůj účet", + "OthersGroup": "Jiný" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json index edb4f7563a..dc99f75586 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json @@ -48,6 +48,7 @@ "Search": "Suche", "ItemWillBeDeletedMessageWithFormat": "{0} wird gelöscht!", "ItemWillBeDeletedMessage": "Dieses Element wird gelöscht!", - "ManageYourAccount": "Verwalten Sie Ihr Benutzerkonto" + "ManageYourAccount": "Verwalten Sie Ihr Benutzerkonto", + "OthersGroup":"Andere" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json index 6bba8ee140..24a7642eb0 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json @@ -48,6 +48,7 @@ "Search": "Αναζήτηση", "ItemWillBeDeletedMessageWithFormat": "Το {0} θα διαγραφεί", "ItemWillBeDeletedMessage": "Αυτό το στοιχείο θα διαγραφεί!", - "ManageYourAccount": "Διαχείριση Λογαριασμού" + "ManageYourAccount": "Διαχείριση Λογαριασμού", + "OthersGroup":"άλλος" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json index a26c5ddf9e..4b88af7d26 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json @@ -48,6 +48,7 @@ "Search": "Search", "ItemWillBeDeletedMessageWithFormat": "{0} will be deleted!", "ItemWillBeDeletedMessage": "This item will be deleted!", - "ManageYourAccount": "Manage your account" + "ManageYourAccount": "Manage your account", + "OthersGroup": "Other" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json index 2a22849731..0f2b2f4423 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json @@ -48,6 +48,7 @@ "Search": "Search", "ItemWillBeDeletedMessageWithFormat": "{0} will be deleted!", "ItemWillBeDeletedMessage": "This item will be deleted!", - "ManageYourAccount": "Manage your account" + "ManageYourAccount": "Manage your account", + "OthersGroup": "Other" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json index f2b40a785b..c28e8049bc 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json @@ -48,6 +48,7 @@ "Search": "Buscar", "ItemWillBeDeletedMessageWithFormat": "{0} serán borrados!", "ItemWillBeDeletedMessage": "Este elemento será borrado", - "ManageYourAccount": "Administrar cuenta" + "ManageYourAccount": "Administrar cuenta", + "OthersGroup": "Otra" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json index c2f81b9c52..4fd179573b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json @@ -48,6 +48,7 @@ "Search": "جستجو", "ItemWillBeDeletedMessageWithFormat": "{0} حذف خواهد شد!", "ItemWillBeDeletedMessage": "این مورد حذف خواهد شد!", - "ManageYourAccount": "حساب خود را مدیریت کنید" + "ManageYourAccount": "حساب خود را مدیریت کنید", + "OthersGroup": "دیگر" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json index 1f5c6b7724..f5c5ee9d09 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json @@ -48,6 +48,7 @@ "Search": "Hae", "ItemWillBeDeletedMessageWithFormat": "{0} poistetaan!", "ItemWillBeDeletedMessage": "Tämä kohde poistetaan!", - "ManageYourAccount": "Hallitse tiliäsi" + "ManageYourAccount": "Hallitse tiliäsi", + "OthersGroup": "Muut" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json index 0fc43162b2..b850315dfe 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json @@ -48,6 +48,7 @@ "Search": "Recherche", "ItemWillBeDeletedMessageWithFormat": "{0} sera supprimé!", "ItemWillBeDeletedMessage": "Cet objet va être supprimé!", - "ManageYourAccount": "Gérer votre compte" + "ManageYourAccount": "Gérer votre compte", + "OthersGroup": "Autre" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json index 2c451bc797..0a20f1dcbb 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json @@ -48,6 +48,7 @@ "Search": "खोज", "ItemWillBeDeletedMessageWithFormat": "{0} हटा दिया जाएगा!", "ItemWillBeDeletedMessage": "यह आइटम हटा दिया जाएगा!", - "ManageYourAccount": "अपने खाते का प्रबंधन" + "ManageYourAccount": "अपने खाते का प्रबंधन", + "OthersGroup": "अन्य" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json index 9cbef79b12..a6285a4cee 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json @@ -48,6 +48,7 @@ "Search": "Pretraga", "ItemWillBeDeletedMessageWithFormat": "{0} zapis će biti obrisan!", "ItemWillBeDeletedMessage": "Ovaj zapis će biti obrisan!", - "ManageYourAccount": "Upravljaj korisničkim računom" + "ManageYourAccount": "Upravljaj korisničkim računom", + "OthersGroup": "Drugi" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json index 595e2f8b62..98c0c46f54 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json @@ -48,6 +48,7 @@ "Search": "Keresés", "ItemWillBeDeletedMessageWithFormat": "{0} törlésre kerül!", "ItemWillBeDeletedMessage": "Ez az elem törlődik!", - "ManageYourAccount": "Kezelje fiókját" + "ManageYourAccount": "Kezelje fiókját", + "OthersGroup": "Egyéb" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json index a931570496..12b1565c2e 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json @@ -48,6 +48,7 @@ "Search": "Leita", "ItemWillBeDeletedMessageWithFormat": "{0} verður eytt!", "ItemWillBeDeletedMessage": "Þessum lið verður eytt!", - "ManageYourAccount": "Stillingar notandaaðgangs" + "ManageYourAccount": "Stillingar notandaaðgangs", + "OthersGroup": "Annað" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json index 3c4328619e..f07bf67e2d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json @@ -48,6 +48,7 @@ "Search": "Ricerca", "ItemWillBeDeletedMessageWithFormat": "{0} sarà eliminato!", "ItemWillBeDeletedMessage": "Questo elemento sarà eliminato!", - "ManageYourAccount": "Gestisci il tuo account" + "ManageYourAccount": "Gestisci il tuo account", + "OthersGroup": "Altra" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json index d23d2356b4..5875fe07b9 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json @@ -48,6 +48,7 @@ "Search": "Zoeken", "ItemWillBeDeletedMessageWithFormat": "{0} wordt verwijderd!", "ItemWillBeDeletedMessage": "Dit item wordt verwijderd!", - "ManageYourAccount": "Beheer uw account" + "ManageYourAccount": "Beheer uw account", + "OthersGroup": "Ander" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json index e7cd503b4f..f2b8227137 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json @@ -48,6 +48,7 @@ "Search": "Szukaj", "ItemWillBeDeletedMessageWithFormat": "{0} zostanie usunięty!", "ItemWillBeDeletedMessage": "Ten element zostanie usunięty!", - "ManageYourAccount": "Zarządzaj kontem" + "ManageYourAccount": "Zarządzaj kontem", + "OthersGroup": "Inny" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json index 03855ec698..928c9299fb 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json @@ -48,6 +48,7 @@ "Search": "Procurar", "ItemWillBeDeletedMessageWithFormat": "{0} será excluído!", "ItemWillBeDeletedMessage": "Este item será excluído!", - "ManageYourAccount": "Gerenciar sua conta" + "ManageYourAccount": "Gerenciar sua conta", + "OthersGroup": "Outra" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json index 7064064671..544b893c39 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json @@ -48,6 +48,7 @@ "Search": "Caută", "ItemWillBeDeletedMessageWithFormat": "{0} va fi şters!", "ItemWillBeDeletedMessage": "Acest articol va fi şters!", - "ManageYourAccount": "Administraţi-vă contul" + "ManageYourAccount": "Administraţi-vă contul", + "OthersGroup": "Alte" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json index dc648a2138..66f24ca65d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json @@ -48,6 +48,7 @@ "Search": "поиск", "ItemWillBeDeletedMessageWithFormat": "{0} будет удален!", "ItemWillBeDeletedMessage": "Этот предмет будет удален!", - "ManageYourAccount": "Настройте свой аккаунт" + "ManageYourAccount": "Настройте свой аккаунт", + "OthersGroup": "Другой" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json index 59b2628310..28278f04f2 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json @@ -48,6 +48,7 @@ "Search": "Hľadať", "ItemWillBeDeletedMessageWithFormat": "{0} sa vymaže!", "ItemWillBeDeletedMessage": "Táto položka bude vymazaná!", - "ManageYourAccount": "Spravovať svoje konto" + "ManageYourAccount": "Spravovať svoje konto", + "OthersGroup": "Iné" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json index 7a50fbaf25..c05c1dc202 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json @@ -48,6 +48,7 @@ "Search": "Iskanje", "ItemWillBeDeletedMessageWithFormat": "{0} bo izbrisan!", "ItemWillBeDeletedMessage": "Ta element bo izbrisan!", - "ManageYourAccount": "Upravljajte svoj račun" + "ManageYourAccount": "Upravljajte svoj račun", + "OthersGroup": "Ostalo" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json index 67ae56793a..fa2f3561f2 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json @@ -48,6 +48,7 @@ "Search": "Arama", "ItemWillBeDeletedMessageWithFormat": "{0} silinecektir!", "ItemWillBeDeletedMessage": "Bu nesne silinecektir!", - "ManageYourAccount": "Hesap yönetimi" + "ManageYourAccount": "Hesap yönetimi", + "OthersGroup": "Diğer" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json index 4062990743..1b8bc5fb5b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json @@ -48,6 +48,7 @@ "Search": "Tìm kiếm", "ItemWillBeDeletedMessageWithFormat": "{0} sẽ bị xóa!", "ItemWillBeDeletedMessage": "Vật phẩm này sẽ bị xoá!", - "ManageYourAccount": "Quản lý tài khoản của bạn" + "ManageYourAccount": "Quản lý tài khoản của bạn", + "OthersGroup": "Khác" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json index 7c9d2798ff..133faa7386 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json @@ -48,6 +48,7 @@ "Search": "搜索", "ItemWillBeDeletedMessageWithFormat": "{0} 将被删除!", "ItemWillBeDeletedMessage": "此项将被删除!", - "ManageYourAccount": "管理你的账户" + "ManageYourAccount": "管理你的账户", + "OthersGroup": "其他" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json index 449dd67480..7bac7da3b8 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json @@ -48,6 +48,7 @@ "Search": "查詢", "ItemWillBeDeletedMessageWithFormat": "{0} 將被刪除!", "ItemWillBeDeletedMessage": "此項目將被刪除!", - "ManageYourAccount": "管理個人帳號" + "ManageYourAccount": "管理個人帳號", + "OthersGroup": "其他" } }