diff --git a/docs/en/UI/Angular/Linked-List.md b/docs/en/UI/Angular/Linked-List.md index c3fb307806..388c5963cd 100644 --- a/docs/en/UI/Angular/Linked-List.md +++ b/docs/en/UI/Angular/Linked-List.md @@ -26,7 +26,7 @@ The constructor does not get any parameters. ### How to Add New Nodes -There are a few methods to create new nodes in a linked list and all of them are separately available as well as revealed from an `add` method. +There are several methods to create new nodes in a linked list and all of them are separately available as well as revealed by `add` and `addMany` methods. @@ -50,6 +50,22 @@ list.addHead('c'); +#### addManyHead(values: T\[\]): ListNode\\[\] + +Adds multiple nodes with given values as the first nodes in list: + +```js +list.addManyHead(['a', 'b', 'c']); + +// "a" <-> "b" <-> "c" + +list.addManyHead(['x', 'y', 'z']); + +// "x" <-> "y" <-> "z" <-> "a" <-> "b" <-> "c" +``` + + + #### addTail(value: T): ListNode\ Adds a node with given value as the last node in list: @@ -70,6 +86,22 @@ list.addTail('c'); +#### addManyTail(values: T\[\]): ListNode\\[\] + +Adds multiple nodes with given values as the last nodes in list: + +```js +list.addManyTail(['a', 'b', 'c']); + +// "a" <-> "b" <-> "c" + +list.addManyTail(['x', 'y', 'z']); + +// "a" <-> "b" <-> "c" <-> "x" <-> "y" <-> "z" +``` + + + #### addAfter(value: T, previousValue: T, compareFn = compare): ListNode\ Adds a node with given value after the first node that has the previous value: @@ -109,6 +141,40 @@ list.addAfter({ x: 0 }, { x: 2 }, (v1, v2) => v1.x === v2.x); +#### addManyAfter(values: T\[\], previousValue: T, compareFn = compare): ListNode\\[\] + +Adds multiple nodes with given values after the first node that has the previous value: + +```js +list.addManyTail(['a', 'b', 'b', 'c']); + +// "a" <-> "b" <-> "b" <-> "c" + +list.addManyAfter(['x', 'y'], 'b'); + +// "a" <-> "b" <-> "x" <-> "y" <-> "b" <-> "c" +``` + + + +You may pass a custom compare function to detect the searched value: + +```js +list.addManyTail([{ x: 1 },{ x: 2 },{ x: 3 }]); + +// {"x":1} <-> {"x":2} <-> {"x":3} + +list.addManyAfter([{ x: 4 }, { x: 5 }], { x: 2 }, (v1, v2) => v1.x === v2.x); + +// {"x":1} <-> {"x":2} <-> {"x":4} <-> {"x":5} <-> {"x":3} +``` + + + +> The default compare function checks deep equality, so you will rarely need to pass that parameter. + + + #### addBefore(value: T, nextValue: T, compareFn = compare): ListNode\ Adds a node with given value before the first node that has the next value: @@ -148,6 +214,40 @@ list.addBefore({ x: 0 }, { x: 2 }, (v1, v2) => v1.x === v2.x); +#### addManyBefore(values: T\[\], nextValue: T, compareFn = compare): ListNode\\[\] + +Adds multiple nodes with given values before the first node that has the next value: + +```js +list.addManyTail(['a', 'b', 'b', 'c']); + +// "a" <-> "b" <-> "b" <-> "c" + +list.addManyBefore(['x', 'y'], 'b'); + +// "a" <-> "x" <-> "y" <-> "b" <-> "b" <-> "c" +``` + + + +You may pass a custom compare function to detect the searched value: + +```js +list.addManyTail([{ x: 1 },{ x: 2 },{ x: 3 }]); + +// {"x":1} <-> {"x":2} <-> {"x":3} + +list.addManyBefore([{ x: 4 }, { x: 5 }], { x: 2 }, (v1, v2) => v1.x === v2.x); + +// {"x":1} <-> {"x":4} <-> {"x":5} <-> {"x":2} <-> {"x":3} +``` + + + +> The default compare function checks deep equality, so you will rarely need to pass that parameter. + + + #### addByIndex(value: T, position: number): ListNode\ Adds a node with given value at the specified position in the list: @@ -166,6 +266,52 @@ list.addByIndex('x', 2); +It works with negative index too: + +```js +list.addTail('a'); +list.addTail('b'); +list.addTail('c'); + +// "a" <-> "b" <-> "c" + +list.addByIndex('x', -1); + +// "a" <-> "b" <-> "x" <-> "c" +``` + + + +#### addManyByIndex(values: T\[\], position: number): ListNode\\[\] + +Adds multiple nodes with given values at the specified position in the list: + +```js +list.addManyTail(['a', 'b', 'c']); + +// "a" <-> "b" <-> "c" + +list.addManyByIndex(['x', 'y'], 2); + +// "a" <-> "b" <-> "x" <-> "y" <-> "c" +``` + + + +It works with negative index too: + +```js +list.addManyTail(['a', 'b', 'c']); + +// "a" <-> "b" <-> "c" + +list.addManyByIndex(['x', 'y'], -1); + +// "a" <-> "b" <-> "x" <-> "y" <-> "c" +``` + + + #### add(value: T).head(): ListNode\ Adds a node with given value as the first node in list: @@ -314,10 +460,172 @@ list.add('x').byIndex(2); +It works with negative index too: + +```js +list.add('a').tail(); +list.add('b').tail(); +list.add('c').tail(); + +// "a" <-> "b" <-> "c" + +list.add('x').byIndex(-1); + +// "a" <-> "b" <-> "x" <-> "c" +``` + + + > This is an alternative API for `addByIndex`. +#### addMany(values: T\[\]).head(): ListNode\\[\] + +Adds multiple nodes with given values as the first nodes in list: + +```js +list.addMany(['a', 'b', 'c']).head(); + +// "a" <-> "b" <-> "c" + +list.addMany(['x', 'y', 'z']).head(); + +// "x" <-> "y" <-> "z" <-> "a" <-> "b" <-> "c" +``` + + + +> This is an alternative API for `addManyHead`. + + + +#### addMany(values: T\[\]).tail(): ListNode\\[\] + +Adds multiple nodes with given values as the last nodes in list: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.addMany(['x', 'y', 'z']).tail(); + +// "a" <-> "b" <-> "c" <-> "x" <-> "y" <-> "z" +``` + + + +> This is an alternative API for `addManyTail`. + + + +#### addMany(values: T\[\]).after(previousValue: T, compareFn = compare): ListNode\\[\] + +Adds multiple nodes with given values after the first node that has the previous value: + +```js +list.addMany(['a', 'b', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "b" <-> "c" + +list.addMany(['x', 'y']).after('b'); + +// "a" <-> "b" <-> "x" <-> "y" <-> "b" <-> "c" +``` + + + +You may pass a custom compare function to detect the searched value: + +```js +list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }]).tail(); + +// {"x":1} <-> {"x":2} <-> {"x":3} + +list.addMany([{ x: 4 }, { x: 5 }]).after({ x: 2 }, (v1, v2) => v1.x === v2.x); + +// {"x":1} <-> {"x":2} <-> {"x":4} <-> {"x":5} <-> {"x":3} +``` + + + +> This is an alternative API for `addManyAfter`. +> +> The default compare function checks deep equality, so you will rarely need to pass that parameter. + + + +#### addMany(values: T\[\]).before(nextValue: T, compareFn = compare): ListNode\\[\] + +Adds multiple nodes with given values before the first node that has the next value: + +```js +list.addMany(['a', 'b', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "b" <-> "c" + +list.addMany(['x', 'y']).before('b'); + +// "a" <-> "x" <-> "y" <-> "b" <-> "b" <-> "c" +``` + + + +You may pass a custom compare function to detect the searched value: + +```js +list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }]).tail(); + +// {"x":1} <-> {"x":2} <-> {"x":3} + +list.addMany([{ x: 4 }, { x: 5 }]).before({ x: 2 }, (v1, v2) => v1.x === v2.x); + +// {"x":1} <-> {"x":4} <-> {"x":5} <-> {"x":2} <-> {"x":3} +``` + + + +> This is an alternative API for `addManyBefore`. +> +> The default compare function checks deep equality, so you will rarely need to pass that parameter. + + + +#### addMany(values: T\[\]).byIndex(position: number): ListNode\\[\] + +Adds multiple nodes with given values at the specified position in the list: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.addMany(['x', 'y']).byIndex(2); + +// "a" <-> "b" <-> "x" <-> "y" <-> "c" +``` + + + +It works with negative index too: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.addMany(['x', 'y']).byIndex(-1); + +// "a" <-> "b" <-> "x" <-> "y" <-> "c" +``` + + + +> This is an alternative API for `addManyByIndex`. + + + ### How to Remove Nodes There are a few methods to remove nodes from a linked list and all of them are separately available as well as revealed from a `drop` method. @@ -329,9 +637,7 @@ There are a few methods to remove nodes from a linked list and all of them are s Removes the first node from the list: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('c'); +list.addMany(['a', 'b', 'c']).tail(); // "a" <-> "b" <-> "c" @@ -342,14 +648,28 @@ list.dropHead(); +#### dropManyHead(count: number): ListNode\\[\] + +Removes the first nodes from the list based on given count: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.dropManyHead(2); + +// "c" +``` + + + #### dropTail(): ListNode\ | undefined Removes the last node from the list: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('c'); +list.addMany(['a', 'b', 'c']).tail(); // "a" <-> "b" <-> "c" @@ -360,14 +680,28 @@ list.dropTail(); +#### dropManyTail(count: number): ListNode\\[\] + +Removes the last nodes from the list based on given count: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.dropManyTail(2); + +// "a" +``` + + + #### dropByIndex(position: number): ListNode\ | undefined Removes the node with the specified position from the list: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('c'); +list.addMany(['a', 'b', 'c']).tail(); // "a" <-> "b" <-> "c" @@ -378,16 +712,56 @@ list.dropByIndex(1); +It works with negative index too: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.dropByIndex(-2); + +// "a" <-> "c" +``` + + + +#### dropManyByIndex(count: number, position: number): ListNode\\[\] + +Removes the nodes starting from the specified position from the list based on given count: + +```js +list.addMany(['a', 'b', 'c', 'd']).tail(); + +// "a" <-> "b" <-> "c" <-> "d + +list.dropManyByIndex(2, 1); + +// "a" <-> "d" +``` + + + +It works with negative index too: + +```js +list.addMany(['a', 'b', 'c', 'd']).tail(); + +// "a" <-> "b" <-> "c" <-> "d + +list.dropManyByIndex(2, -2); + +// "a" <-> "d" +``` + + + #### dropByValue(value: T, compareFn = compare): ListNode\ | undefined Removes the first node with given value from the list: ```js -list.addTail('a'); -list.addTail('x'); -list.addTail('b'); -list.addTail('x'); -list.addTail('c'); +list.addMany(['a', 'x', 'b', 'x', 'c']).tail(); // "a" <-> "x" <-> "b" <-> "x" <-> "c" @@ -401,11 +775,7 @@ list.dropByValue('x'); You may pass a custom compare function to detect the searched value: ```js -list.addTail({ x: 1 }); -list.addTail({ x: 0 }); -list.addTail({ x: 2 }); -list.addTail({ x: 0 }); -list.addTail({ x: 3 }); +list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail(); // {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3} @@ -425,11 +795,7 @@ list.dropByValue({ x: 0 }, (v1, v2) => v1.x === v2.x); Removes all nodes with given value from the list: ```js -list.addTail('a'); -list.addTail('x'); -list.addTail('b'); -list.addTail('x'); -list.addTail('c'); +list.addMany(['a', 'x', 'b', 'x', 'c']).tail(); // "a" <-> "x" <-> "b" <-> "x" <-> "c" @@ -443,11 +809,7 @@ list.dropByValueAll('x'); You may pass a custom compare function to detect the searched value: ```js -list.addTail({ x: 1 }); -list.addTail({ x: 0 }); -list.addTail({ x: 2 }); -list.addTail({ x: 0 }); -list.addTail({ x: 3 }); +list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail(); // {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3} @@ -467,9 +829,7 @@ list.dropByValue({ x: 0 }, (v1, v2) => v1.x === v2.x); Removes the first node in list: ```js -list.add('a').tail(); -list.add('b').tail(); -list.add('c').tail(); +list.addMany(['a', 'b', 'c']).tail(); // "a" <-> "b" <-> "c" @@ -489,9 +849,7 @@ list.drop().head(); Removes the last node in list: ```js -list.add('a').tail(); -list.add('b').tail(); -list.add('c').tail(); +list.addMany(['a', 'b', 'c']).tail(); // "a" <-> "b" <-> "c" @@ -511,9 +869,7 @@ list.drop().tail(); Removes the node with the specified position from the list: ```js -list.add('a').tail(); -list.add('b').tail(); -list.add('c').tail(); +list.addMany(['a', 'b', 'c']).tail(); // "a" <-> "b" <-> "c" @@ -524,6 +880,20 @@ list.drop().byIndex(1); +It works with negative index too: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.drop().byIndex(-2); + +// "a" <-> "c" +``` + + + > This is an alternative API for `dropByIndex`. @@ -533,11 +903,7 @@ list.drop().byIndex(1); Removes the first node with given value from the list: ```js -list.add('a').tail(); -list.add('x').tail(); -list.add('b').tail(); -list.add('x').tail(); -list.add('c').tail(); +list.addMany(['a', 'x', 'b', 'x', 'c']).tail(); // "a" <-> "x" <-> "b" <-> "x" <-> "c" @@ -551,11 +917,7 @@ list.drop().byValue('x'); You may pass a custom compare function to detect the searched value: ```js -list.add({ x: 1 }).tail(); -list.add({ x: 0 }).tail(); -list.add({ x: 2 }).tail(); -list.add({ x: 0 }).tail(); -list.add({ x: 3 }).tail(); +list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail(); // {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3} @@ -577,11 +939,7 @@ list.drop().byValue({ x: 0 }, (v1, v2) => v1.x === v2.x); Removes all nodes with given value from the list: ```js -list.add('a').tail(); -list.add('x').tail(); -list.add('b').tail(); -list.add('x').tail(); -list.add('c').tail(); +list.addMany(['a', 'x', 'b', 'x', 'c']).tail(); // "a" <-> "x" <-> "b" <-> "x" <-> "c" @@ -595,11 +953,7 @@ list.drop().byValueAll('x'); You may pass a custom compare function to detect the searched value: ```js -list.add({ x: 1 }).tail(); -list.add({ x: 0 }).tail(); -list.add({ x: 2 }).tail(); -list.add({ x: 0 }).tail(); -list.add({ x: 3 }).tail(); +list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail(); // {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3} @@ -616,6 +970,80 @@ list.drop().byValueAll({ x: 0 }, (v1, v2) => v1.x === v2.x); +#### dropMany(count: number).head(): ListNode\\[\] + +Removes the first nodes from the list based on given count: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.dropMany(2).head(); + +// "c" +``` + + + +> This is an alternative API for `dropManyHead`. + + + +#### dropMany(count: number).tail(): ListNode\\[\] + +Removes the last nodes from the list based on given count: + +```js +list.addMany(['a', 'b', 'c']).tail(); + +// "a" <-> "b" <-> "c" + +list.dropMany(2).tail(); + +// "a" +``` + + + +> This is an alternative API for `dropManyTail`. + + + +#### dropMany(count: number).byIndex(position: number): ListNode\\[\] + +Removes the nodes starting from the specified position from the list based on given count: + +```js +list.addMany(['a', 'b', 'c', 'd']).tail(); + +// "a" <-> "b" <-> "c" <-> "d + +list.dropMany(2).byIndex(1); + +// "a" <-> "d" +``` + + + +It works with negative index too: + +```js +list.addMany(['a', 'b', 'c', 'd']).tail(); + +// "a" <-> "b" <-> "c" <-> "d + +list.dropMany(2).byIndex(-2); + +// "a" <-> "d" +``` + + + +> This is an alternative API for `dropManyByIndex`. + + + ### How to Find Nodes There are a few methods to find specific nodes in a linked list. @@ -627,10 +1055,7 @@ There are a few methods to find specific nodes in a linked list. Finds the first node from the list that matches the given predicate: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('b'); -list.addTail('c'); +list.addTailMany(['a', 'b', 'b', 'c']); // "a" <-> "b" <-> "b" <-> "c" @@ -650,10 +1075,7 @@ found.next.value === "b" Finds the position of the first node from the list that matches the given predicate: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('b'); -list.addTail('c'); +list.addTailMany(['a', 'b', 'b', 'c']); // "a" <-> "b" <-> "b" <-> "c" @@ -677,9 +1099,7 @@ i3 === -1 Finds and returns the node with specific position in the list: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('c'); +list.addTailMany(['a', 'b', 'c']); // "a" <-> "b" <-> "c" @@ -699,10 +1119,7 @@ found.next.value === "c" Finds the position of the first node from the list that has the given value: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('b'); -list.addTail('c'); +list.addTailMany(['a', 'b', 'b', 'c']); // "a" <-> "b" <-> "b" <-> "c" @@ -724,11 +1141,7 @@ i3 === -1 You may pass a custom compare function to detect the searched value: ```js -list.addTail({ x: 1 }); -list.addTail({ x: 0 }); -list.addTail({ x: 2 }); -list.addTail({ x: 0 }); -list.addTail({ x: 3 }); +list.addTailMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]); // {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3} @@ -764,9 +1177,7 @@ There are a few ways to iterate over or display a linked list. Runs a callback function on all nodes in a linked list from head to tail: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('c'); +list.addTailMany(['a', 'b', 'c']); // "a" <-> "b" <-> "c" @@ -784,9 +1195,7 @@ list.forEach((node, index) => console.log(node.value + index)); A linked list is iterable. In other words, you may use methods like `for...of` on it. ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('c'); +list.addTailMany(['a', 'b', 'c']); // "a" <-> "b" <-> "c" @@ -801,14 +1210,12 @@ for(const node of list) { -#### toArray(): T[] +#### toArray(): T\[\] -Converts a linked list to an array: +Converts a linked list to an array of values: ```js -list.addTail('a'); -list.addTail('b'); -list.addTail('c'); +list.addTailMany(['a', 'b', 'c']); // "a" <-> "b" <-> "c" @@ -821,15 +1228,32 @@ arr === ['a', 'b', 'c'] +#### toNodeArray(): T\[\] + +Converts a linked list to an array of nodes: + +```js +list.addTailMany(['a', 'b', 'c']); + +// "a" <-> "b" <-> "c" + +const arr = list.toNodeArray(); + +/* +arr[0].value === 'a' +arr[1].value === 'a' +arr[2].value === 'a' +*/ +``` + + + #### toString(): string Converts a linked list to a string representation of nodes and their relations: ```js -list.addTail('a'); -list.addTail(2); -list.addTail('c'); -list.addTail({ k: 4, v: 'd' }); +list.addTailMany(['a', 2, 'c', { k: 4, v: 'd' }]); // "a" <-> 2 <-> "c" <-> {"k":4,"v":"d"} @@ -842,3 +1266,19 @@ str === '"a" <-> 2 <-> "c" <-> {"k":4,"v":"d"}' +You may pass a custom mapper function to map values before stringifying them: + +```js +list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }, { x: 5 }]).tail(); + +// {"x":1} <-> {"x":2} <-> {"x":3} <-> {"x":4} <-> {"x":5} + +const str = list.toString(value => value.x); + +/* +str === '1 <-> 2 <-> 3 <-> 4 <-> 5' +*/ +``` + + + diff --git a/docs/en/UI/Angular/Service-Proxies.md b/docs/en/UI/Angular/Service-Proxies.md index b1cd9ad500..97b43b7513 100644 --- a/docs/en/UI/Angular/Service-Proxies.md +++ b/docs/en/UI/Angular/Service-Proxies.md @@ -25,9 +25,9 @@ The files generated with the `--module all` option like below: ### Services -Each generated service matches a back-end controller. The services methods call back-end APIs via [RestService](./HTTP-Requests.md#restservice). +Each generated service matches a back-end controller. The services methods call back-end APIs via [RestService](./Http-Requests.md#restservice). -A variable named `apiName` (available as of v2.4) is defined in each service. `apiName` matches the module's RemoteServiceName. This variable passes to the `RestService` as a parameter at each request. If there is no microservice API defined in the environment, `RestService` uses the default. See [getting a specific API endpoint from application config](HTTP-Requests#how-to-get-a-specific-api-endpoint-from-application-config) +A variable named `apiName` (available as of v2.4) is defined in each service. `apiName` matches the module's RemoteServiceName. This variable passes to the `RestService` as a parameter at each request. If there is no microservice API defined in the environment, `RestService` uses the default. See [getting a specific API endpoint from application config](./Http-Requests.md#how-to-get-a-specific-api-endpoint-from-application-config) The `providedIn` property of the services is defined as `'root'`. Therefore no need to add a service as a provider to a module. You can use a service by injecting it into a constructor as shown below: @@ -64,4 +64,4 @@ Initial values ​​can optionally be passed to each class constructor. ## What's Next? -* [Http Requests](./Http-Requests.md) \ No newline at end of file +* [HTTP Requests](./Http-Requests.md) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 46cd056d29..d5b24f4404 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -5,7 +5,7 @@ "items": [ { "text": "From Startup Templates", - "path": "Getting-Started-With-Startup-Templates.md" + "path": "Getting-Started-With-Startup-Templates.md", "items": [ { "text": "Application with MVC (Razor Pages) UI", diff --git a/npm/ng-packs/packages/account/src/lib/services/account.service.ts b/npm/ng-packs/packages/account/src/lib/services/account.service.ts index 6c2571a518..ae9fc19d21 100644 --- a/npm/ng-packs/packages/account/src/lib/services/account.service.ts +++ b/npm/ng-packs/packages/account/src/lib/services/account.service.ts @@ -7,6 +7,8 @@ import { RegisterResponse, RegisterRequest, TenantIdResponse } from '../models'; providedIn: 'root', }) export class AccountService { + apiName = 'AbpAccount'; + constructor(private rest: RestService) {} findTenant(tenantName: string): Observable { @@ -15,7 +17,7 @@ export class AccountService { url: `/api/abp/multi-tenancy/tenants/by-name/${tenantName}`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } register(body: RegisterRequest): Observable { @@ -25,6 +27,9 @@ export class AccountService { body, }; - return this.rest.request(request, { skipHandleError: true }); + return this.rest.request(request, { + skipHandleError: true, + apiName: this.apiName, + }); } } diff --git a/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts b/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts index 5081f94068..39b893501c 100644 --- a/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts @@ -3,12 +3,18 @@ import { Observable } from 'rxjs'; import { Rest } from '../models/rest'; import { ApplicationConfiguration } from '../models/application-configuration'; import { RestService } from './rest.service'; +import { Store } from '@ngxs/store'; +import { ConfigState } from '../states/config.state'; @Injectable({ providedIn: 'root', }) export class ApplicationConfigurationService { - constructor(private rest: RestService) {} + get apiName(): string { + return this.store.selectSnapshot(ConfigState.getDeep('environment.application.name')); + } + + constructor(private rest: RestService, private store: Store) {} getConfiguration(): Observable { const request: Rest.Request = { @@ -16,6 +22,8 @@ export class ApplicationConfigurationService { url: '/api/abp/application-configuration', }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } } diff --git a/npm/ng-packs/packages/core/src/lib/services/profile.service.ts b/npm/ng-packs/packages/core/src/lib/services/profile.service.ts index 38d5fb3a7b..d80caf7e80 100644 --- a/npm/ng-packs/packages/core/src/lib/services/profile.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/profile.service.ts @@ -7,6 +7,8 @@ import { Profile, Rest } from '../models'; providedIn: 'root', }) export class ProfileService { + apiName = 'AbpIdentity'; + constructor(private rest: RestService) {} get(): Observable { @@ -15,7 +17,7 @@ export class ProfileService { url: '/api/identity/my-profile', }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } update(body: Profile.Response): Observable { @@ -25,16 +27,24 @@ export class ProfileService { body, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } - changePassword(body: Profile.ChangePasswordRequest, skipHandleError: boolean = false): Observable { + changePassword( + body: Profile.ChangePasswordRequest, + skipHandleError: boolean = false, + ): Observable { const request: Rest.Request = { method: 'POST', url: '/api/identity/my-profile/change-password', body, }; - return this.rest.request(request, { skipHandleError }); + return this.rest.request(request, { + skipHandleError, + apiName: this.apiName, + }); } } diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index 74e9ee8cd0..01a181229f 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -81,7 +81,7 @@ export class ConfigState { static getApiUrl(key?: string) { const selector = createSelector([ConfigState], (state: Config.State): string => { - return state.environment.apis[key || 'default'].url; + return (state.environment.apis[key || 'default'] || state.environment.apis.default).url; }); return selector; diff --git a/npm/ng-packs/packages/core/src/lib/tests/linked-list.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/linked-list.spec.ts index 518956deba..3ad9eeda63 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/linked-list.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/linked-list.spec.ts @@ -1,4 +1,4 @@ -import { LinkedList } from '../utils/linked-list'; +import { LinkedList, ListNode } from '../utils/linked-list'; describe('Linked List (Doubly)', () => { let list: LinkedList; @@ -44,9 +44,11 @@ describe('Linked List (Doubly)', () => { expect(list.length).toBe(3); expect(list.head.value).toBe('c'); expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('a'); expect(list.head.previous).toBeUndefined(); expect(list.tail.value).toBe('a'); expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('c'); expect(list.tail.next).toBeUndefined(); }); }); @@ -72,34 +74,49 @@ describe('Linked List (Doubly)', () => { expect(list.length).toBe(3); expect(list.head.value).toBe('a'); expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); expect(list.head.previous).toBeUndefined(); expect(list.tail.value).toBe('c'); expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); expect(list.tail.next).toBeUndefined(); }); }); describe('#after', () => { - it('should place a node after node with given value', () => { + it('should add a node after node with given value', () => { list.add('a').tail(); - list.add('b').tail(); - list.add('c').tail(); - // "a" <-> "b" <-> "c" + // "a" - list.add('x').after('b'); + list.add('b').after('a'); + list.add('c').after('b'); - // "a" <-> "b" <-> "x" <-> "c" + // "a" <-> "b" <-> "c" - expect(list.length).toBe(4); + expect(list.length).toBe(3); expect(list.head.value).toBe('a'); expect(list.head.next.value).toBe('b'); - expect(list.head.next.next.value).toBe('x'); - expect(list.head.next.next.next.value).toBe('c'); + expect(list.head.next.next.value).toBe('c'); expect(list.tail.value).toBe('c'); - expect(list.tail.previous.value).toBe('x'); - expect(list.tail.previous.previous.value).toBe('b'); - expect(list.tail.previous.previous.previous.value).toBe('a'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + }); + + it('should add a node to tail if given value is not found', () => { + list.add('a').tail(); + + // "a" + + list.add('b').after('x'); + + // "a" <-> "b" + + expect(list.length).toBe(2); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.tail.value).toBe('b'); + expect(list.tail.previous.value).toBe('a'); }); it('should be able to receive a custom compareFn', () => { @@ -126,79 +143,516 @@ describe('Linked List (Doubly)', () => { }); describe('#before', () => { - it('should place a node before node with given value', () => { + it('should add a node before node with given value', () => { + list.add('c').tail(); + + // "c" + + list.add('b').before('c'); + list.add('a').before('b'); + + // "a" <-> "b" <-> "c" + + expect(list.length).toBe(3); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + }); + + it('should add a node to head if given value is not found', () => { + list.add('b').tail(); + + // "a" + + list.add('a').before('x'); + + // "a" <-> "b" + + expect(list.length).toBe(2); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.tail.value).toBe('b'); + expect(list.tail.previous.value).toBe('a'); + }); + + it('should be able to receive a custom compareFn', () => { + list.add({ x: 1 }).tail(); + list.add({ x: 2 }).tail(); + list.add({ x: 3 }).tail(); + + // {"x":1} <-> {"x":2} <-> {"x":3} + + list.add({ x: 0 }).before({ x: 2 }, (v1: X, v2: X) => v1.x === v2.x); + + // {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":3} + + expect(list.length).toBe(4); + expect(list.head.value.x).toBe(1); + expect(list.head.next.value.x).toBe(0); + expect(list.head.next.next.value.x).toBe(2); + expect(list.head.next.next.next.value.x).toBe(3); + expect(list.tail.value.x).toBe(3); + expect(list.tail.previous.value.x).toBe(2); + expect(list.tail.previous.previous.value.x).toBe(0); + expect(list.tail.previous.previous.previous.value.x).toBe(1); + }); + }); + + describe('#byIndex', () => { + it('should add a node at given index', () => { list.add('a').tail(); list.add('b').tail(); list.add('c').tail(); // "a" <-> "b" <-> "c" - list.add('x').before('b'); + list.add('x').byIndex(1); // "a" <-> "x" <-> "b" <-> "c" - expect(list.length).toBe(4); + list.add('y').byIndex(3); + + // "a" <-> "x" <-> "b" <-> "y" <-> "c" + + expect(list.length).toBe(5); expect(list.head.value).toBe('a'); expect(list.head.next.value).toBe('x'); expect(list.head.next.next.value).toBe('b'); + expect(list.head.next.next.next.value).toBe('y'); + expect(list.head.next.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('y'); + expect(list.tail.previous.previous.value).toBe('b'); + expect(list.tail.previous.previous.previous.value).toBe('x'); + expect(list.tail.previous.previous.previous.previous.value).toBe('a'); + }); + + it('should add a node to head if given index is zero', () => { + list.add('a').tail(); + list.add('b').tail(); + list.add('c').tail(); + + // "a" <-> "b" <-> "c" + + list.add('x').byIndex(0); + + // "x" <-> "a" <-> "b" <-> "c" + + expect(list.length).toBe(4); + expect(list.head.value).toBe('x'); + expect(list.head.next.value).toBe('a'); + expect(list.head.next.next.value).toBe('b'); expect(list.head.next.next.next.value).toBe('c'); expect(list.tail.value).toBe('c'); expect(list.tail.previous.value).toBe('b'); - expect(list.tail.previous.previous.value).toBe('x'); - expect(list.tail.previous.previous.previous.value).toBe('a'); + expect(list.tail.previous.previous.value).toBe('a'); + expect(list.tail.previous.previous.previous.value).toBe('x'); + }); + + it('should add a node to tail if given index more than size', () => { + list.add('a').tail(); + list.add('b').tail(); + list.add('c').tail(); + + // "a" <-> "b" <-> "c" + + list.add('x').byIndex(4); + + // "a" <-> "b" <-> "c" <-> "x" + + expect(list.length).toBe(4); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.head.next.next.next.value).toBe('x'); + expect(list.tail.value).toBe('x'); + expect(list.tail.previous.value).toBe('c'); + expect(list.tail.previous.previous.value).toBe('b'); + expect(list.tail.previous.previous.previous.value).toBe('a'); + }); + + it('should be able to add a node at given index counting from right to left', () => { + list.add('a').tail(); + list.add('b').tail(); + list.add('c').tail(); + + // "a" <-> "b" <-> "c" + + list.add('x').byIndex(-1); + + // "a" <-> "b" <-> "x" <-> "c" + + expect(list.length).toBe(4); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('x'); + expect(list.head.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('x'); + expect(list.tail.previous.previous.value).toBe('b'); + expect(list.tail.previous.previous.previous.value).toBe('a'); + }); + + it('should add a node to head if given index is less than minus size', () => { + list.add('a').tail(); + list.add('b').tail(); + list.add('c').tail(); + + // "a" <-> "b" <-> "c" + + list.add('x').byIndex(-4); + + // "x" <-> "a" <-> "b" <-> "c" + + expect(list.length).toBe(4); + expect(list.head.value).toBe('x'); + expect(list.head.next.value).toBe('a'); + expect(list.head.next.next.value).toBe('b'); + expect(list.head.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + expect(list.tail.previous.previous.previous.value).toBe('x'); + }); + }); + }); + + describe('#addMany', () => { + describe('#head', () => { + it('should add multiple nodes to the head of the list', () => { + list.add('x').head(); + + // "x" + + list.addMany(['a', 'b', 'c']).head(); + + // "a" <-> "b" <-> "c" <-> "x" + + expect(list.length).toBe(4); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.head.next.next.next.value).toBe('x'); + expect(list.head.previous).toBeUndefined(); + expect(list.tail.value).toBe('x'); + expect(list.tail.previous.value).toBe('c'); + expect(list.tail.previous.previous.value).toBe('b'); + expect(list.tail.previous.previous.previous.value).toBe('a'); + expect(list.tail.next).toBeUndefined(); + }); + }); + + describe('#tail', () => { + it('should add multiple nodes to the tail of the list', () => { + list.add('x').tail(); + + // "x" + + list.addMany(['a', 'b', 'c']).tail(); + + // "x" <-> "a" <-> "b" <-> "c" + + expect(list.length).toBe(4); + expect(list.head.value).toBe('x'); + expect(list.head.next.value).toBe('a'); + expect(list.head.next.next.value).toBe('b'); + expect(list.head.next.next.next.value).toBe('c'); + expect(list.head.previous).toBeUndefined(); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + expect(list.tail.previous.previous.previous.value).toBe('x'); + expect(list.tail.next).toBeUndefined(); + }); + }); + + describe('#after', () => { + it('should add multiple nodes after node with given value', () => { + list.add('a').tail(); + + // "a" + + list.addMany(['b', 'c']).after('a'); + + // "a" <-> "b" <-> "c" + + list.addMany(['x', 'y', 'z']).after('b'); + + // "a" <-> "b" <-> "x" <-> "y" <-> "z" <-> "c" + + expect(list.length).toBe(6); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('x'); + expect(list.head.next.next.next.value).toBe('y'); + expect(list.head.next.next.next.next.value).toBe('z'); + expect(list.head.next.next.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('z'); + expect(list.tail.previous.previous.value).toBe('y'); + expect(list.tail.previous.previous.previous.value).toBe('x'); + expect(list.tail.previous.previous.previous.previous.value).toBe('b'); + expect(list.tail.previous.previous.previous.previous.previous.value).toBe('a'); + }); + + it('should add multiple nodes to tail if given value is not found', () => { + list.add('a').tail(); + + // "a" + + list.addMany(['b', 'c']).after('x'); + + // "a" <-> "b" <-> "c" + + expect(list.length).toBe(3); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + }); + + it('should be able to receive a custom compareFn', () => { + list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }]).tail(); + + // {"x":1} <-> {"x":2} <-> {"x":3} + + list.addMany([{ x: 4 }, { x: 5 }]).after({ x: 1 }, (v1: X, v2: X) => v1.x === v2.x); + + // {"x":1} <-> {"x":4} <-> {"x":5} <-> {"x":2} <-> {"x":3} + + expect(list.length).toBe(5); + expect(list.head.value.x).toBe(1); + expect(list.head.next.value.x).toBe(4); + expect(list.head.next.next.value.x).toBe(5); + expect(list.head.next.next.next.value.x).toBe(2); + expect(list.head.next.next.next.next.value.x).toBe(3); + expect(list.tail.value.x).toBe(3); + expect(list.tail.previous.value.x).toBe(2); + expect(list.tail.previous.previous.value.x).toBe(5); + expect(list.tail.previous.previous.previous.value.x).toBe(4); + expect(list.tail.previous.previous.previous.previous.value.x).toBe(1); + }); + + it('should not change the list when empty array given as value', () => { + list.add('a').tail(); + + // "a" + + list.addMany([]).after('a'); + + // "a" + + expect(list.length).toBe(1); + expect(list.head.value).toBe('a'); + expect(list.tail.value).toBe('a'); + }); + }); + + describe('#before', () => { + it('should add multiple nodes before node with given value', () => { + list.add('c').tail(); + + // "c" + + list.addMany(['a', 'b']).before('c'); + + // "a" <-> "b" <-> "c" + + list.addMany(['x', 'y', 'z']).before('b'); + + // "a" <-> "x" <-> "y" <-> "z" <-> "b" <-> "c" + + expect(list.length).toBe(6); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('x'); + expect(list.head.next.next.value).toBe('y'); + expect(list.head.next.next.next.value).toBe('z'); + expect(list.head.next.next.next.next.value).toBe('b'); + expect(list.head.next.next.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('z'); + expect(list.tail.previous.previous.previous.value).toBe('y'); + expect(list.tail.previous.previous.previous.previous.value).toBe('x'); + expect(list.tail.previous.previous.previous.previous.previous.value).toBe('a'); + }); + + it('should add multiple nodes to head if given value is not found', () => { + list.add('c').tail(); + + // "c" + + list.addMany(['a', 'b']).before('x'); + + // "a" <-> "b" <-> "c" + + expect(list.length).toBe(3); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + }); + + it('should be able to receive a custom compareFn', () => { + list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }]).tail(); + + // {"x":1} <-> {"x":2} <-> {"x":3} + + list.addMany([{ x: 4 }, { x: 5 }]).before({ x: 3 }, (v1: X, v2: X) => v1.x === v2.x); + + // {"x":1} <-> {"x":2} <-> {"x":4} <-> {"x":5} <-> {"x":3} + + expect(list.length).toBe(5); + expect(list.head.value.x).toBe(1); + expect(list.head.next.value.x).toBe(2); + expect(list.head.next.next.value.x).toBe(4); + expect(list.head.next.next.next.value.x).toBe(5); + expect(list.head.next.next.next.next.value.x).toBe(3); + expect(list.tail.value.x).toBe(3); + expect(list.tail.previous.value.x).toBe(5); + expect(list.tail.previous.previous.value.x).toBe(4); + expect(list.tail.previous.previous.previous.value.x).toBe(2); + expect(list.tail.previous.previous.previous.previous.value.x).toBe(1); + }); + + it('should not change the list when empty array given as value', () => { + list.add('a').tail(); + + // "a" + + list.addMany([]).before('a'); + + // "a" + + expect(list.length).toBe(1); + expect(list.head.value).toBe('a'); + expect(list.tail.value).toBe('a'); + }); + }); + + describe('#byIndex', () => { + it('should add multiple nodes starting from given index', () => { + list.addMany(['a', 'b', 'c']).tail(); + + // "a" <-> "b" <-> "c" + + list.addMany(['x', 'y']).byIndex(1); + + // "a" <-> "x" <-> "y" <-> "b" <-> "c" + + list.addMany(['z']).byIndex(4); + + // "a" <-> "x" <-> "y" <-> "b" <-> "z" <-> "c" + + expect(list.length).toBe(6); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('x'); + expect(list.head.next.next.value).toBe('y'); + expect(list.head.next.next.next.value).toBe('b'); + expect(list.head.next.next.next.next.value).toBe('z'); + expect(list.head.next.next.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('z'); + expect(list.tail.previous.previous.value).toBe('b'); + expect(list.tail.previous.previous.previous.value).toBe('y'); + expect(list.tail.previous.previous.previous.previous.value).toBe('x'); + expect(list.tail.previous.previous.previous.previous.previous.value).toBe('a'); + }); + + it('should add multiple nodes to head if given index is zero', () => { + list.addMany(['a', 'b', 'c']).tail(); + + // "a" <-> "b" <-> "c" + + list.addMany(['x', 'y']).byIndex(0); + + // "x" <-> "y" <-> "a" <-> "b" <-> "c" + + expect(list.length).toBe(5); + expect(list.head.value).toBe('x'); + expect(list.head.next.value).toBe('y'); + expect(list.head.next.next.value).toBe('a'); + expect(list.head.next.next.next.value).toBe('b'); + expect(list.head.next.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + expect(list.tail.previous.previous.previous.value).toBe('y'); + expect(list.tail.previous.previous.previous.previous.value).toBe('x'); }); - it('should be able to receive a custom compareFn', () => { - list.add({ x: 1 }).tail(); - list.add({ x: 2 }).tail(); - list.add({ x: 3 }).tail(); + it('should add multiple nodes to tail if given index more than size', () => { + list.addMany(['a', 'b', 'c']).tail(); - // {"x":1} <-> {"x":2} <-> {"x":3} + // "a" <-> "b" <-> "c" - list.add({ x: 0 }).before({ x: 2 }, (v1: X, v2: X) => v1.x === v2.x); + list.addMany(['x', 'y']).byIndex(4); - // {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":3} + // "a" <-> "b" <-> "c" <-> "x" <-> "y" - expect(list.length).toBe(4); - expect(list.head.value.x).toBe(1); - expect(list.head.next.value.x).toBe(0); - expect(list.head.next.next.value.x).toBe(2); - expect(list.head.next.next.next.value.x).toBe(3); - expect(list.tail.value.x).toBe(3); - expect(list.tail.previous.value.x).toBe(2); - expect(list.tail.previous.previous.value.x).toBe(0); - expect(list.tail.previous.previous.previous.value.x).toBe(1); + expect(list.length).toBe(5); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.head.next.next.next.value).toBe('x'); + expect(list.head.next.next.next.next.value).toBe('y'); + expect(list.tail.value).toBe('y'); + expect(list.tail.previous.value).toBe('x'); + expect(list.tail.previous.previous.value).toBe('c'); + expect(list.tail.previous.previous.previous.value).toBe('b'); + expect(list.tail.previous.previous.previous.previous.value).toBe('a'); }); - }); - describe('#byIndex', () => { - it('should place a node at given index', () => { - list.add('a').tail(); - list.add('b').tail(); - list.add('c').tail(); + it('should be able to add multiple nodes at given index counting from right to left', () => { + list.addMany(['a', 'b', 'c']).tail(); // "a" <-> "b" <-> "c" - list.add('x').byIndex(1); - - // "a" <-> "x" <-> "b" <-> "c" - - list.add('y').byIndex(3); + list.addMany(['x', 'y']).byIndex(-1); - // "a" <-> "x" <-> "b" <-> "y" <-> "c" + // "a" <-> "b" <-> "x" <-> "y" <-> "c" expect(list.length).toBe(5); expect(list.head.value).toBe('a'); - expect(list.head.next.value).toBe('x'); - expect(list.head.next.next.value).toBe('b'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('x'); expect(list.head.next.next.next.value).toBe('y'); expect(list.head.next.next.next.next.value).toBe('c'); expect(list.tail.value).toBe('c'); expect(list.tail.previous.value).toBe('y'); - expect(list.tail.previous.previous.value).toBe('b'); - expect(list.tail.previous.previous.previous.value).toBe('x'); + expect(list.tail.previous.previous.value).toBe('x'); + expect(list.tail.previous.previous.previous.value).toBe('b'); expect(list.tail.previous.previous.previous.previous.value).toBe('a'); }); + + it('should add a node to head if given index is less than minus size', () => { + list.addMany(['a', 'b', 'c']).tail(); + + // "a" <-> "b" <-> "c" + + list.addMany(['x', 'y']).byIndex(-4); + + // "x" <-> "y" <-> "a" <-> "b" <-> "c" + + expect(list.length).toBe(5); + expect(list.head.value).toBe('x'); + expect(list.head.next.value).toBe('y'); + expect(list.head.next.next.value).toBe('a'); + expect(list.head.next.next.next.value).toBe('b'); + expect(list.head.next.next.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + expect(list.tail.previous.previous.previous.value).toBe('y'); + expect(list.tail.previous.previous.previous.previous.value).toBe('x'); + }); }); }); @@ -212,19 +666,19 @@ describe('Linked List (Doubly)', () => { // "a" <-> "x" <-> "b" <-> "x" <-> "c" - const node1 = list.find(node => node.previous && node.previous.value === 'a'); + const found1 = list.find(node => node.previous && node.previous.value === 'a'); - expect(node1.value).toBe('x'); - expect(node1.previous.value).toBe('a'); - expect(node1.next.value).toBe('b'); + expect(found1.value).toBe('x'); + expect(found1.previous.value).toBe('a'); + expect(found1.next.value).toBe('b'); // "a" <-> "x" <-> "b" <-> "x" <-> "c" - const node2 = list.find(node => node.next && node.next.value === 'c'); + const found2 = list.find(node => node.next && node.next.value === 'c'); - expect(node2.value).toBe('x'); - expect(node2.previous.value).toBe('b'); - expect(node2.next.value).toBe('c'); + expect(found2.value).toBe('x'); + expect(found2.previous.value).toBe('b'); + expect(found2.next.value).toBe('c'); }); it('should return undefined when list is empty', () => { @@ -329,7 +783,8 @@ describe('Linked List (Doubly)', () => { describe('#drop', () => { describe('#head', () => { it('should return undefined when there is no head', () => { - expect(list.drop().head()).toBeUndefined(); + const dropped = list.drop().head(); + expect(dropped).toBeUndefined(); }); it('should remove the node from the head of the list', () => { @@ -350,12 +805,22 @@ describe('Linked List (Doubly)', () => { expect(list.tail.value).toBe('c'); expect(list.tail.previous.value).toBe('b'); expect(list.tail.next).toBeUndefined(); + + // "b" <-> "c" + + list.drop().head(); + list.drop().head(); + + expect(list.length).toBe(0); + expect(list.head).toBeUndefined(); + expect(list.tail).toBeUndefined(); }); }); - describe('#head', () => { + describe('#tail', () => { it('should return undefined when there is no tail', () => { - expect(list.drop().tail()).toBeUndefined(); + const dropped = list.drop().tail(); + expect(dropped).toBeUndefined(); }); it('should remove the node from the tail of the list', () => { @@ -376,6 +841,15 @@ describe('Linked List (Doubly)', () => { expect(list.tail.value).toBe('b'); expect(list.tail.previous.value).toBe('a'); expect(list.tail.next).toBeUndefined(); + + // "a" <-> "b" + + list.drop().tail(); + list.drop().tail(); + + expect(list.length).toBe(0); + expect(list.head).toBeUndefined(); + expect(list.tail).toBeUndefined(); }); }); @@ -393,7 +867,7 @@ describe('Linked List (Doubly)', () => { // "a" <-> "c" <-> "d" <-> "e" - list.drop().byIndex(2); + list.drop().byIndex(-2); // "a" <-> "c" <-> "e" @@ -404,11 +878,21 @@ describe('Linked List (Doubly)', () => { expect(list.tail.value).toBe('e'); expect(list.tail.previous.value).toBe('c'); expect(list.tail.previous.previous.value).toBe('a'); + + // "a" <-> "c" <-> "e" + + list.drop().byIndex(2); + list.drop().byIndex(1); + list.drop().byIndex(0); + + expect(list.length).toBe(0); + expect(list.head).toBeUndefined(); + expect(list.tail).toBeUndefined(); }); it('should return undefined when list is empty', () => { - const node = list.drop().byIndex(0); - expect(node).toBeUndefined(); + const dropped = list.drop().byIndex(0); + expect(dropped).toBeUndefined(); }); it('should return undefined when given index does not exist', () => { @@ -418,11 +902,11 @@ describe('Linked List (Doubly)', () => { // "a" <-> "b" <-> "c" - const node1 = list.drop().byIndex(4); + const dropped1 = list.drop().byIndex(4); // "a" <-> "b" <-> "c" - expect(node1).toBeUndefined(); + expect(dropped1).toBeUndefined(); expect(list.length).toBe(3); expect(list.head.value).toBe('a'); expect(list.head.next.value).toBe('b'); @@ -433,11 +917,11 @@ describe('Linked List (Doubly)', () => { // "a" <-> "b" <-> "c" - const node2 = list.drop().byIndex(-1); + const dropped2 = list.drop().byIndex(-4); // "a" <-> "b" <-> "c" - expect(node2).toBeUndefined(); + expect(dropped2).toBeUndefined(); expect(list.length).toBe(3); expect(list.head.value).toBe('a'); expect(list.head.next.value).toBe('b'); @@ -506,8 +990,8 @@ describe('Linked List (Doubly)', () => { }); it('should return undefined when list is empty', () => { - const node = list.drop().byValue('x'); - expect(node).toBeUndefined(); + const dropped = list.drop().byValue('x'); + expect(dropped).toBeUndefined(); }); it('should return undefined when given value is not found', () => { @@ -622,6 +1106,214 @@ describe('Linked List (Doubly)', () => { }); }); + describe('#dropMany', () => { + describe('#head', () => { + it('should return empty array when there is no head', () => { + const dropped = list.dropMany(1).head(); + expect(dropped).toEqual([]); + }); + + it('should remove multiple nodes from the head of the list', () => { + list.addMany(['a', 'b', 'c', 'd', 'e']).tail(); + + // "a" <-> "b" <-> "c" <-> "d" <-> "e" + + list.dropMany(3).head(); + + // "d" <-> "e" + + expect(list.length).toBe(2); + expect(list.head.value).toBe('d'); + expect(list.head.next.value).toBe('e'); + expect(list.head.previous).toBeUndefined(); + expect(list.tail.value).toBe('e'); + expect(list.tail.previous.value).toBe('d'); + expect(list.tail.next).toBeUndefined(); + }); + + it('should not change the list when count is less than or equal to zero', () => { + list.add('a').tail(); + + // "a" + + list.dropMany(0).head(); + + // "a" + + list.dropMany(-1).head(); + + // "a" + + expect(list.length).toBe(1); + expect(list.head.value).toBe('a'); + expect(list.tail.value).toBe('a'); + }); + }); + + describe('#tail', () => { + it('should return empty array when there is no tail', () => { + const dropped = list.dropMany(1).tail(); + expect(dropped).toEqual([]); + }); + + it('should remove multiple nodes from the tail of the list', () => { + list.addMany(['a', 'b', 'c', 'd', 'e']).tail(); + + // "a" <-> "b" <-> "c" <-> "d" <-> "e" + + list.dropMany(3).tail(); + + // "a" <-> "b" + + expect(list.length).toBe(2); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.previous).toBeUndefined(); + expect(list.tail.value).toBe('b'); + expect(list.tail.previous.value).toBe('a'); + expect(list.tail.next).toBeUndefined(); + }); + + it('should not change the list when count is less than or equal to zero', () => { + list.add('a').tail(); + + // "a" + + list.dropMany(0).tail(); + + // "a" + + list.dropMany(-1).tail(); + + // "a" + + expect(list.length).toBe(1); + expect(list.head.value).toBe('a'); + expect(list.tail.value).toBe('a'); + }); + }); + + describe('#byIndex', () => { + it('should remove multiple nodes starting from given index', () => { + list.addMany(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']).tail(); + + // "a" <-> "b" <-> "c" <-> "d" <-> "e" <-> "f" <-> "g" <-> "h" + + list.dropMany(2).byIndex(1); + + // "a" <-> "d" <-> "e" <-> "f" <-> "g" <-> "h" + + list.dropMany(2).byIndex(-3); + + // "a" <-> "d" <-> "e" <-> "h" + + expect(list.length).toBe(4); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('d'); + expect(list.head.next.next.value).toBe('e'); + expect(list.head.next.next.next.value).toBe('h'); + expect(list.tail.value).toBe('h'); + expect(list.tail.previous.value).toBe('e'); + expect(list.tail.previous.previous.value).toBe('d'); + expect(list.tail.previous.previous.previous.value).toBe('a'); + + list.dropMany(4).byIndex(0); + + expect(list.length).toBe(0); + expect(list.head).toBeUndefined(); + expect(list.tail).toBeUndefined(); + }); + + it('should return empty array when list is empty', () => { + const dropped = list.dropMany(1).byIndex(0); + expect(dropped).toEqual([]); + }); + + it('should return empty array when given index does not exist', () => { + list.addMany(['a', 'b', 'c']).tail(); + + // "a" <-> "b" <-> "c" + + const dropped = list.dropMany(3).byIndex(4); + + // "a" <-> "b" <-> "c" + + expect(dropped).toEqual([]); + expect(list.length).toBe(3); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + }); + + it('should remove from start when given index is less than minus size', () => { + list.addMany(['a', 'b', 'c', 'd', 'e']).tail(); + + // "a" <-> "b" <-> "c" <-> "d" <-> "e" + + list.dropMany(2).byIndex(-9); + + // "c" <-> "d" <-> "e" + + expect(list.length).toBe(3); + expect(list.head.value).toBe('c'); + expect(list.head.next.value).toBe('d'); + expect(list.head.next.next.value).toBe('e'); + expect(list.tail.value).toBe('e'); + expect(list.tail.previous.value).toBe('d'); + expect(list.tail.previous.previous.value).toBe('c'); + }); + + it('should remove from end when given index + count is larger than or equal to size', () => { + list.addMany(['a', 'b', 'c', 'd', 'e']).tail(); + + // "a" <-> "b" <-> "c" <-> "d" <-> "e" + + list.dropMany(2).byIndex(3); + + // "a" <-> "b" <-> "c" + + expect(list.length).toBe(3); + expect(list.head.value).toBe('a'); + expect(list.head.next.value).toBe('b'); + expect(list.head.next.next.value).toBe('c'); + expect(list.tail.value).toBe('c'); + expect(list.tail.previous.value).toBe('b'); + expect(list.tail.previous.previous.value).toBe('a'); + + // "a" <-> "b" <-> "c" + + list.dropMany(9).byIndex(1); + + // "a" + + expect(list.length).toBe(1); + expect(list.head.value).toBe('a'); + expect(list.tail.value).toBe('a'); + }); + + it('should not change the list when count is less than or equal to zero', () => { + list.add('a').tail(); + + // "a" + + list.dropMany(0).byIndex(0); + + // "a" + + list.dropMany(-1).byIndex(0); + + // "a" + + expect(list.length).toBe(1); + expect(list.head.value).toBe('a'); + expect(list.tail.value).toBe('a'); + }); + }); + }); + describe('#get', () => { it('should return node at given index', () => { list.add('a').tail(); @@ -761,6 +1453,27 @@ describe('Linked List (Doubly)', () => { }); }); + describe('#toNodeArray', () => { + it('should return array of nodes', () => { + list.addTail('a'); + list.addTail(2); + list.addTail('c'); + list.addTail({ k: 4, v: 'd' }); + + // "a" <-> 2 <-> "c" <-> {"k":4,"v":"d"} + + const arr = list.toNodeArray(); + + expect(arr.every(node => node instanceof ListNode)).toBe(true); + expect(arr.map(node => node.value)).toEqual(['a', 2, 'c', { k: 4, v: 'd' }]); + }); + + it('should return empty array when list is empty', () => { + const arr = list.toNodeArray(); + expect(arr).toEqual([]); + }); + }); + describe('#toString', () => { it('should return string representation', () => { list.addTail('a'); @@ -778,6 +1491,23 @@ describe('Linked List (Doubly)', () => { const str = list.toString(); expect(str).toBe(''); }); + + it('should be coercible', () => { + list.addMany(['a', 'b', 'c']).tail(); + + // "a" <-> "b" <-> "c" + + expect('' + list).toBe('"a" <-> "b" <-> "c"'); + }); + + it('should be able to receive a custom mapperFn', () => { + list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }]).tail(); + + // {"x":1} <-> {"x":2} <-> {"x":3} + + const str = list.toString(value => value.x); + expect(str).toBe('1 <-> 2 <-> 3'); + }); }); it('should be iterable', () => { diff --git a/npm/ng-packs/packages/core/src/lib/utils/linked-list.ts b/npm/ng-packs/packages/core/src/lib/utils/linked-list.ts index 42cc5bc941..9bd3e21941 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/linked-list.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/linked-list.ts @@ -27,65 +27,107 @@ export class LinkedList { return this.size; } - private linkWith( + private attach( value: T, previousNode: ListNode | undefined, nextNode: ListNode | undefined, ): ListNode { - const node = new ListNode(value); - if (!previousNode) return this.addHead(value); + if (!nextNode) return this.addTail(value); + const node = new ListNode(value); node.previous = previousNode; previousNode.next = node; node.next = nextNode; nextNode.previous = node; - this.size += 1; + this.size++; + + return node; + } + + private attachMany( + values: T[], + previousNode: ListNode | undefined, + nextNode: ListNode | undefined, + ): ListNode[] { + if (!values.length) return []; + + if (!previousNode) return this.addManyHead(values); + + if (!nextNode) return this.addManyTail(values); + + const list = new LinkedList(); + list.addManyTail(values); + list.first!.previous = previousNode; + previousNode.next = list.first; + list.last!.next = nextNode; + nextNode.previous = list.last; + + this.size += values.length; + + return list.toNodeArray(); + } + + private detach(node: ListNode) { + if (!node.previous) return this.dropHead(); + + if (!node.next) return this.dropTail(); + + node.previous.next = node.next; + node.next.previous = node.previous; + + this.size--; return node; } add(value: T) { return { - after: (previousValue: T, compareFn = compare) => { - return this.addAfter(value, previousValue, compareFn); - }, - before: (nextValue: T, compareFn = compare) => { - return this.addBefore(value, nextValue, compareFn); - }, - byIndex: (position: number): ListNode => { - return this.addByIndex(value, position); - }, - head: (): ListNode => { - return this.addHead(value); - }, - tail: (): ListNode => { - return this.addTail(value); - }, + after: (previousValue: T, compareFn: ListComparisonFn = compare) => + this.addAfter(value, previousValue, compareFn), + before: (nextValue: T, compareFn: ListComparisonFn = compare) => + this.addBefore(value, nextValue, compareFn), + byIndex: (position: number) => this.addByIndex(value, position), + head: () => this.addHead(value), + tail: () => this.addTail(value), + }; + } + + addMany(values: T[]) { + return { + after: (previousValue: T, compareFn: ListComparisonFn = compare) => + this.addManyAfter(values, previousValue, compareFn), + before: (nextValue: T, compareFn: ListComparisonFn = compare) => + this.addManyBefore(values, nextValue, compareFn), + byIndex: (position: number) => this.addManyByIndex(values, position), + head: () => this.addManyHead(values), + tail: () => this.addManyTail(values), }; } - addAfter(value: T, previousValue: T, compareFn = compare): ListNode { + addAfter(value: T, previousValue: T, compareFn: ListComparisonFn = compare): ListNode { const previous = this.find(node => compareFn(node.value, previousValue)); - return previous ? this.linkWith(value, previous, previous.next) : this.addTail(value); + return previous ? this.attach(value, previous, previous.next) : this.addTail(value); } - addBefore(value: T, nextValue: T, compareFn = compare): ListNode { + addBefore(value: T, nextValue: T, compareFn: ListComparisonFn = compare): ListNode { const next = this.find(node => compareFn(node.value, nextValue)); - return next ? this.linkWith(value, next.previous, next) : this.addHead(value); + return next ? this.attach(value, next.previous, next) : this.addHead(value); } addByIndex(value: T, position: number): ListNode { + if (position < 0) position += this.size; + else if (position >= this.size) return this.addTail(value); + if (position <= 0) return this.addHead(value); - if (position >= this.size) return this.addTail(value); const next = this.get(position)!; - return this.linkWith(value, next.previous, next); + return this.attach(value, next.previous, next); } addHead(value: T): ListNode { @@ -97,7 +139,7 @@ export class LinkedList { else this.last = node; this.first = node; - this.size += 1; + this.size++; return node; } @@ -114,51 +156,92 @@ export class LinkedList { this.last = node; } - this.size += 1; + this.size++; return node; } + addManyAfter( + values: T[], + previousValue: T, + compareFn: ListComparisonFn = compare, + ): ListNode[] { + const previous = this.find(node => compareFn(node.value, previousValue)); + + return previous ? this.attachMany(values, previous, previous.next) : this.addManyTail(values); + } + + addManyBefore( + values: T[], + nextValue: T, + compareFn: ListComparisonFn = compare, + ): ListNode[] { + const next = this.find(node => compareFn(node.value, nextValue)); + + return next ? this.attachMany(values, next.previous, next) : this.addManyHead(values); + } + + addManyByIndex(values: T[], position: number): ListNode[] { + if (position < 0) position += this.size; + + if (position <= 0) return this.addManyHead(values); + + if (position >= this.size) return this.addManyTail(values); + + const next = this.get(position)!; + + return this.attachMany(values, next.previous, next); + } + + addManyHead(values: T[]): ListNode[] { + return values.reduceRight[]>((nodes, value) => { + nodes.unshift(this.addHead(value)); + return nodes; + }, []); + } + + addManyTail(values: T[]): ListNode[] { + return values.map(value => this.addTail(value)); + } + drop() { return { byIndex: (position: number) => this.dropByIndex(position), - byValue: (value: T, compareFn = compare) => this.dropByValue(value, compareFn), - byValueAll: (value: T, compareFn = compare) => this.dropByValueAll(value, compareFn), + byValue: (value: T, compareFn: ListComparisonFn = compare) => + this.dropByValue(value, compareFn), + byValueAll: (value: T, compareFn: ListComparisonFn = compare) => + this.dropByValueAll(value, compareFn), head: () => this.dropHead(), tail: () => this.dropTail(), }; } + dropMany(count: number) { + return { + byIndex: (position: number) => this.dropManyByIndex(count, position), + head: () => this.dropManyHead(count), + tail: () => this.dropManyTail(count), + }; + } + dropByIndex(position: number): ListNode | undefined { - if (position === 0) return this.dropHead(); - else if (position === this.size - 1) return this.dropTail(); + if (position < 0) position += this.size; const current = this.get(position); - if (current) { - current.previous!.next = current.next; - current.next!.previous = current.previous; - - this.size -= 1; - - return current; - } - - return undefined; + return current ? this.detach(current) : undefined; } - dropByValue(value: T, compareFn = compare): ListNode | undefined { + dropByValue(value: T, compareFn: ListComparisonFn = compare): ListNode | undefined { const position = this.findIndex(node => compareFn(node.value, value)); - if (position < 0) return undefined; - - return this.dropByIndex(position); + return position < 0 ? undefined : this.dropByIndex(position); } - dropByValueAll(value: T, compareFn = compare): ListNode[] { + dropByValueAll(value: T, compareFn: ListComparisonFn = compare): ListNode[] { const dropped: ListNode[] = []; - for (let current = this.first, position = 0; current; position += 1, current = current.next) { + for (let current = this.first, position = 0; current; position++, current = current.next) { if (compareFn(current.value, value)) { dropped.push(this.dropByIndex(position - dropped.length)!); } @@ -176,7 +259,7 @@ export class LinkedList { if (this.first) this.first.previous = undefined; else this.last = undefined; - this.size -= 1; + this.size--; return head; } @@ -193,7 +276,7 @@ export class LinkedList { if (this.last) this.last.next = undefined; else this.first = undefined; - this.size -= 1; + this.size--; return tail; } @@ -201,24 +284,66 @@ export class LinkedList { return undefined; } - find(predicate: ListIteratorFunction): ListNode | undefined { - for (let current = this.first, position = 0; current; position += 1, current = current.next) { + dropManyByIndex(count: number, position: number): ListNode[] { + if (count <= 0) return []; + + if (position < 0) position = Math.max(position + this.size, 0); + else if (position >= this.size) return []; + + count = Math.min(count, this.size - position); + + const dropped: ListNode[] = []; + + while (count--) { + const current = this.get(position); + dropped.push(this.detach(current!)!); + } + + return dropped; + } + + dropManyHead(count: Exclude): ListNode[] { + if (count <= 0) return []; + + count = Math.min(count, this.size); + + const dropped: ListNode[] = []; + + while (count--) dropped.unshift(this.dropHead()!); + + return dropped; + } + + dropManyTail(count: Exclude): ListNode[] { + if (count <= 0) return []; + + count = Math.min(count, this.size); + + const dropped: ListNode[] = []; + + while (count--) dropped.push(this.dropTail()!); + + return dropped; + } + + find(predicate: ListIteratorFn): ListNode | undefined { + for (let current = this.first, position = 0; current; position++, current = current.next) { if (predicate(current, position, this)) return current; } return undefined; } - findIndex(predicate: ListIteratorFunction): number { - for (let current = this.first, position = 0; current; position += 1, current = current.next) { + findIndex(predicate: ListIteratorFn): number { + for (let current = this.first, position = 0; current; position++, current = current.next) { if (predicate(current, position, this)) return position; } return -1; } - forEach(callback: ListIteratorFunction) { - for (let node = this.first, position = 0; node; position += 1, node = node.next) { + forEach(callback: ListIteratorFn) { + for (let node = this.first, position = 0; node; position++, node = node.next) { callback(node, position, this); } } @@ -227,7 +352,7 @@ export class LinkedList { return this.find((_, index) => position === index); } - indexOf(value: T, compareFn = compare): number { + indexOf(value: T, compareFn: ListComparisonFn = compare): number { return this.findIndex(node => compareFn(node.value, value)); } @@ -239,20 +364,32 @@ export class LinkedList { return array; } - toString(): string { + toNodeArray(): ListNode[] { + const array = new Array(this.size); + + this.forEach((node, index) => (array[index!] = node)); + + return array; + } + + toString(mapperFn: ListMapperFn = JSON.stringify): string { return this.toArray() - .map(value => JSON.stringify(value)) + .map(value => mapperFn(value)) .join(' <-> '); } *[Symbol.iterator]() { - for (let node = this.first, position = 0; node; position += 1, node = node.next) { + for (let node = this.first, position = 0; node; position++, node = node.next) { yield node.value; } } } -export type ListIteratorFunction = ( +export type ListMapperFn = (value: T) => any; + +export type ListComparisonFn = (value1: T, value2: T) => boolean; + +export type ListIteratorFn = ( node: ListNode, index?: number, list?: LinkedList, diff --git a/npm/ng-packs/packages/feature-management/src/lib/services/feature-management.service.ts b/npm/ng-packs/packages/feature-management/src/lib/services/feature-management.service.ts index 5f6c0eed6e..1020e60d4e 100644 --- a/npm/ng-packs/packages/feature-management/src/lib/services/feature-management.service.ts +++ b/npm/ng-packs/packages/feature-management/src/lib/services/feature-management.service.ts @@ -8,6 +8,8 @@ import { FeatureManagement } from '../models'; providedIn: 'root', }) export class FeatureManagementService { + apiName = 'FeatureManagement'; + constructor(private rest: RestService, private store: Store) {} getFeatures(params: FeatureManagement.Provider): Observable { @@ -16,7 +18,9 @@ export class FeatureManagementService { url: '/api/abp/features', params, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } updateFeatures({ @@ -30,6 +34,6 @@ export class FeatureManagementService { body: { features }, params: { providerKey, providerName }, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } } diff --git a/npm/ng-packs/packages/identity/src/lib/services/identity.service.ts b/npm/ng-packs/packages/identity/src/lib/services/identity.service.ts index ae9ca3a921..51e88557fe 100644 --- a/npm/ng-packs/packages/identity/src/lib/services/identity.service.ts +++ b/npm/ng-packs/packages/identity/src/lib/services/identity.service.ts @@ -7,6 +7,8 @@ import { Identity } from '../models/identity'; providedIn: 'root', }) export class IdentityService { + apiName = 'AbpIdentity'; + constructor(private rest: RestService) {} getRoles(params = {} as ABP.PageQueryParams): Observable { @@ -16,7 +18,7 @@ export class IdentityService { params, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } getAllRoles(): Observable { @@ -25,7 +27,7 @@ export class IdentityService { url: '/api/identity/roles/all', }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } getRoleById(id: string): Observable { @@ -34,7 +36,7 @@ export class IdentityService { url: `/api/identity/roles/${id}`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } deleteRole(id: string): Observable { @@ -43,7 +45,7 @@ export class IdentityService { url: `/api/identity/roles/${id}`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } createRole(body: Identity.RoleSaveRequest): Observable { @@ -53,7 +55,9 @@ export class IdentityService { body, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } updateRole(body: Identity.RoleItem): Observable { @@ -66,7 +70,9 @@ export class IdentityService { body, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } getUsers(params = {} as ABP.PageQueryParams): Observable { @@ -76,7 +82,7 @@ export class IdentityService { params, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } getUserById(id: string): Observable { @@ -85,7 +91,7 @@ export class IdentityService { url: `/api/identity/users/${id}`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } getUserRoles(id: string): Observable { @@ -94,7 +100,7 @@ export class IdentityService { url: `/api/identity/users/${id}/roles`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } deleteUser(id: string): Observable { @@ -103,7 +109,7 @@ export class IdentityService { url: `/api/identity/users/${id}`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } createUser(body: Identity.UserSaveRequest): Observable { @@ -113,7 +119,9 @@ export class IdentityService { body, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } updateUser(body: Identity.UserItem): Observable { @@ -126,6 +134,8 @@ export class IdentityService { body, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } } diff --git a/npm/ng-packs/packages/permission-management/src/lib/services/permission-management.service.ts b/npm/ng-packs/packages/permission-management/src/lib/services/permission-management.service.ts index e7fdd98ce3..fa6433e952 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/services/permission-management.service.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/services/permission-management.service.ts @@ -7,16 +7,23 @@ import { PermissionManagement } from '../models/permission-management'; providedIn: 'root', }) export class PermissionManagementService { + apiName = 'AbpPermissionManagement'; + constructor(private rest: RestService) {} - getPermissions(params: PermissionManagement.GrantedProvider): Observable { + getPermissions( + params: PermissionManagement.GrantedProvider, + ): Observable { const request: Rest.Request = { method: 'GET', url: '/api/abp/permissions', params, }; - return this.rest.request(request); + return this.rest.request( + request, + { apiName: this.apiName }, + ); } updatePermissions({ @@ -31,6 +38,8 @@ export class PermissionManagementService { params: { providerKey, providerName }, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } } diff --git a/npm/ng-packs/packages/tenant-management/src/lib/services/tenant-management.service.ts b/npm/ng-packs/packages/tenant-management/src/lib/services/tenant-management.service.ts index 27ee26b7ed..8678da1332 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/services/tenant-management.service.ts +++ b/npm/ng-packs/packages/tenant-management/src/lib/services/tenant-management.service.ts @@ -7,6 +7,8 @@ import { TenantManagement } from '../models/tenant-management'; providedIn: 'root', }) export class TenantManagementService { + apiName = 'AbpTenantManagement'; + constructor(private rest: RestService) {} getTenant(params = {} as ABP.PageQueryParams): Observable { @@ -16,7 +18,7 @@ export class TenantManagementService { params, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } getTenantById(id: string): Observable { @@ -25,7 +27,7 @@ export class TenantManagementService { url: `/api/multi-tenancy/tenants/${id}`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } deleteTenant(id: string): Observable { @@ -34,7 +36,7 @@ export class TenantManagementService { url: `/api/multi-tenancy/tenants/${id}`, }; - return this.rest.request(request); + return this.rest.request(request, { apiName: this.apiName }); } createTenant(body: TenantManagement.AddRequest): Observable { @@ -44,7 +46,9 @@ export class TenantManagementService { body, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } updateTenant(body: TenantManagement.UpdateRequest): Observable { @@ -57,7 +61,9 @@ export class TenantManagementService { body, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } getDefaultConnectionString(id: string): Observable { @@ -68,7 +74,9 @@ export class TenantManagementService { responseType: Rest.ResponseType.Text, url, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } updateDefaultConnectionString( @@ -81,7 +89,9 @@ export class TenantManagementService { url, params: { defaultConnectionString: payload.defaultConnectionString }, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } deleteDefaultConnectionString(id: string): Observable { @@ -91,6 +101,8 @@ export class TenantManagementService { method: 'DELETE', url, }; - return this.rest.request(request); + return this.rest.request(request, { + apiName: this.apiName, + }); } }