Skip to content

Commit 1c51d2c

Browse files
authored
Merge branch '20.1.x' into didimmova/align-daterange-label
2 parents fde9f02 + 91bed5d commit 1c51d2c

File tree

84 files changed

+1256
-381
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1256
-381
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
"@types/source-map": "0.5.2",
7676
"express": "^5.1.0",
7777
"fflate": "^0.8.1",
78-
"igniteui-theming": "^22.0.0",
78+
"igniteui-theming": "^23.0.0",
7979
"igniteui-trial-watermark": "^3.1.0",
8080
"lodash-es": "^4.17.21",
8181
"rxjs": "^7.8.2",

projects/igniteui-angular-elements/src/app/custom-strategy.spec.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
IgcPaginatorComponent,
1313
IgcGridStateComponent,
1414
IgcColumnLayoutComponent,
15+
IgcActionStripComponent,
16+
IgcGridEditingActionsComponent,
1517
} from './components';
1618
import { defineComponents } from '../utils/register';
1719

@@ -27,6 +29,8 @@ describe('Elements: ', () => {
2729
IgcColumnLayoutComponent,
2830
IgcPaginatorComponent,
2931
IgcGridStateComponent,
32+
IgcActionStripComponent,
33+
IgcGridEditingActionsComponent
3034
);
3135
});
3236

@@ -230,5 +234,66 @@ describe('Elements: ', () => {
230234
expect(grid.columns.length).toEqual(6);
231235
expect(grid.getColumnByVisibleIndex(1).field).toEqual('ProductName');
232236
});
237+
238+
it('should not destroy action strip when row it is shown in is destroyed or cached.', async() => {
239+
const innerHtml = `
240+
<igc-grid id="testGrid" auto-generate>
241+
<igc-action-strip id="testStrip">
242+
<igc-grid-editing-actions add-row="true"></igc-grid-editing-actions>
243+
</igc-action-strip>
244+
</igc-grid>`;
245+
testContainer.innerHTML = innerHtml;
246+
247+
// TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
248+
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3));
249+
250+
const grid = document.querySelector<IgcNgElement & InstanceType<typeof IgcGridComponent>>('#testGrid');
251+
const actionStrip = document.querySelector<IgcNgElement & InstanceType<typeof IgcActionStripComponent>>('#testStrip');
252+
grid.data = SampleTestData.foodProductData();
253+
254+
// TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
255+
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3));
256+
257+
let row = grid.dataRowList.toArray()[0];
258+
actionStrip.show(row);
259+
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3));
260+
261+
expect(actionStrip.hidden).toBeFalse();
262+
263+
grid.data = [];
264+
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3));
265+
266+
// row destroyed
267+
expect((row.cdr as any).destroyed).toBeTrue();
268+
// action strip still in DOM, only hidden.
269+
expect(actionStrip.hidden).toBeTrue();
270+
expect(actionStrip.isConnected).toBeTrue();
271+
272+
grid.data = SampleTestData.foodProductData();
273+
grid.groupBy({ fieldName: 'InStock', dir: 1, ignoreCase: false });
274+
275+
// TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
276+
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3));
277+
278+
row = grid.dataRowList.toArray()[0];
279+
actionStrip.show(row);
280+
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3));
281+
282+
expect(actionStrip.hidden).toBeFalse();
283+
284+
// collapse all data rows, leave only groups
285+
grid.toggleAllGroupRows();
286+
287+
// TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
288+
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3));
289+
290+
// row not destroyed, but also not in dom anymore
291+
expect((row.cdr as any).destroyed).toBeFalse();
292+
expect(row.element.nativeElement.isConnected).toBe(false);
293+
294+
// action strip still in DOM, only hidden.
295+
expect(actionStrip.hidden).toBeTrue();
296+
expect(actionStrip.isConnected).toBeTrue();
297+
});
233298
});
234299
});
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Ignite UI performance project
2+
3+
This project contains sample applications for the grid, tree grid, and pivot grid, with predefined data source sizes of 1,000, 100,000, and 1,000,000 records. These samples are used to measure the performance of different grid features using an internal `PerformanceService`, which is a wrapper around the browser's Performance API.
4+
5+
To run the application:
6+
7+
```sh
8+
npm run start:performance
9+
```
10+
11+
## Using the performance service
12+
13+
The performance service is intended to be used as an injectable service inside a component that would be measured. In order to inject it add a private property in the component:
14+
15+
```ts
16+
private performanceService = inject(PerformanceService);
17+
```
18+
19+
This will initialize the service and also create a global `$$igcPerformance` variable that can be used for convenience.
20+
21+
### API
22+
23+
```ts
24+
performanceService.setLogEnabled(true);
25+
```
26+
27+
- Set whether the service should use `console.debug` to print the performance entries. Defaults to `false`.
28+
29+
```ts
30+
const end = performanceService.start(name);
31+
data.sort();
32+
end();
33+
```
34+
35+
- Starts a performance measuring. The method returns a function that should be invoked after the code you want to measure has finished executing. This creates a `PerformanceMeasure` entry in the browser's performance timeline.
36+
37+
```ts
38+
const performanceMeasures: PerformanceEntryList = performanceService.getMeasures(name?);
39+
```
40+
41+
- Gets list of `PerformanceMeasure` entries. If a name is provided, it returns only the measures with that name.
42+
43+
```ts
44+
performanceService.clearMeasures(name?);
45+
```
46+
47+
- Clears all performed measures. If a `name` is provided, it clears only the measures with that name.
48+
49+
> **Note:** The `$$igcPerformance` global object could be used as an alternative to the injected `performanceService` instance.
50+
51+
### Reading results
52+
53+
Let's say that we want to measure the time that the grid's sorting pipeline takes to sort the data. We first go to the `IgxGridSortingPipe` and modify the code to look like this:
54+
55+
```ts
56+
@Pipe({
57+
name: 'gridSort',
58+
standalone: true,
59+
})
60+
export class IgxGridSortingPipe implements PipeTransform {
61+
private performance = inject(PerformanceService);
62+
63+
constructor(@Inject(IGX_GRID_BASE) private grid: GridType) {}
64+
65+
public transform(
66+
collection: any[],
67+
sortExpressions: ISortingExpression[],
68+
groupExpressions: IGroupingExpression[],
69+
sorting: IGridSortingStrategy,
70+
id: string,
71+
pipeTrigger: number,
72+
pinned?
73+
): any[] {
74+
// This is important!
75+
this.performance.setLogEnabled(true);
76+
const endSorting = this.performance.start('Sorting pipe');
77+
78+
let result: any[];
79+
const expressions = groupExpressions.concat(sortExpressions);
80+
if (!expressions.length) {
81+
result = collection;
82+
} else {
83+
result = DataUtil.sort(
84+
cloneArray(collection),
85+
expressions,
86+
sorting,
87+
this.grid
88+
);
89+
}
90+
this.grid.setFilteredSortedData(result, pinned);
91+
92+
// This is important!
93+
endSorting();
94+
95+
return result;
96+
}
97+
}
98+
```
99+
100+
If you run a sample and sort a column, the performance service will measure the execution time of the sorting pipe. There are two ways to see the results:
101+
102+
1. If `setLogEnabled` is called with `true` then the service will print the measurement result in the console using `console.debug`.
103+
<img width="1720" height="863" alt="performance-console" src="https://github.com/user-attachments/assets/000d0bfd-a180-447d-ac27-2f82904e1150" />
104+
105+
2. The browser's DevTools Performance tab can be used for a more detailed analysis. Before triggering the action (e.g., sorting), start a new performance recording in DevTools.
106+
107+
108+
https://github.com/user-attachments/assets/8aa80ead-82d0-48a4-a6d2-1c17b3d099b1
109+
110+
111+
You should look at the timings tab in the performance window in dev-tools.

projects/igniteui-angular/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
"tslib": "^2.3.0",
7474
"igniteui-trial-watermark": "^3.1.0",
7575
"lodash-es": "^4.17.21",
76-
"igniteui-theming": "^22.0.0",
76+
"igniteui-theming": "^23.0.0",
7777
"@igniteui/material-icons-extended": "^3.1.0"
7878
},
7979
"peerDependencies": {

projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { IgxGridPinningActionsComponent } from './grid-pinning-actions.component
1515
import { IgxActionStripComponent } from '../action-strip.component';
1616
import { IRowDataCancelableEventArgs, IgxColumnComponent } from '../../grids/public_api';
1717
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
18+
import { SortingDirection } from '../../data-operations/sorting-strategy';
1819

1920
describe('igxGridEditingActions #grid ', () => {
2021
let fixture;
@@ -274,6 +275,59 @@ describe('igxGridEditingActions #grid ', () => {
274275

275276
expect(actionStrip.hidden).toBeTrue();
276277
});
278+
279+
it('should auto-hide on delete action click.', () => {
280+
const row = grid.rowList.toArray()[0];
281+
actionStrip.show(row);
282+
fixture.detectChanges();
283+
284+
expect(actionStrip.hidden).toBeFalse();
285+
286+
const deleteIcon = fixture.debugElement.queryAll(By.css(`igx-grid-editing-actions igx-icon`))[1];
287+
expect(deleteIcon.nativeElement.innerText).toBe('delete');
288+
deleteIcon.parent.triggerEventHandler('click', new Event('click'));
289+
fixture.detectChanges();
290+
291+
expect(actionStrip.hidden).toBeTrue();
292+
293+
});
294+
295+
it('should auto-hide if context row is destroyed.', () => {
296+
const row = grid.rowList.toArray()[0];
297+
actionStrip.show(row);
298+
fixture.detectChanges();
299+
300+
expect(actionStrip.hidden).toBeFalse();
301+
302+
// bind to no data, which removes all rows.
303+
grid.data = [];
304+
grid.cdr.detectChanges();
305+
306+
expect((row.cdr as any).destroyed).toBeTrue();
307+
expect(actionStrip.hidden).toBeTrue();
308+
});
309+
310+
it('should auto-hide if context row is cached.', () => {
311+
// create group rows
312+
grid.groupBy({ fieldName: 'ContactTitle', dir: SortingDirection.Desc, ignoreCase: false });
313+
fixture.detectChanges();
314+
315+
// show for first data row
316+
const row = grid.dataRowList.toArray()[0];
317+
actionStrip.show(row);
318+
fixture.detectChanges();
319+
320+
// collapse all groups to cache data rows
321+
grid.toggleAllGroupRows();
322+
fixture.detectChanges();
323+
324+
// not destroyed, but not in DOM anymore
325+
expect((row.cdr as any).destroyed).toBeFalse();
326+
expect(row.element.nativeElement.isConnected).toBe(false);
327+
328+
// action strip should be hidden
329+
expect(actionStrip.hidden).toBeTrue();
330+
});
277331
});
278332

279333
describe('auto show/hide in HierarchicalGrid', () => {

projects/igniteui-angular/src/lib/badge/README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# igx-badge
22

33
The **igx-badge** component is an absolutely positioned element that can be used in tandem with other components such as avatars, navigation menus, or anywhere else in an app where some active indication is required.
4-
With the igx-badge you can display active count or an icon in several different predefined styles.
4+
With the igx-badge you can display active count or an icon in several different predefined styles and sizes.
55
A walkthrough of how to get started can be found [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/badge.html)
66

77
# Usage
@@ -14,9 +14,12 @@ A walkthrough of how to get started can be found [here](https://www.infragistics
1414
|:----------|:-------------:|:------|
1515
| `id` | string | Unique identifier of the component. If not provided it will be automatically generated.|
1616
| `type` | string | Set the type of the badge to either `primary`, `info`, `success`, `warning`, or `error`. This will change the background color of the badge according to the values set in the default theme. |
17+
| `dot` | boolean | Set whether the badge is displayed as a minimal dot indicator without any content. Default is `false`. |
1718
| `position` | string | Set the position of the badge relative to its parent container to either `top-right`, `top-left`, `bottom-right`, or `bottom-left`. |
1819
| `value` | string | Set the value to be displayed inside the badge. |
1920
| `icon` | string | Set an icon for the badge from the material icons set. Will not be displayed if `value` for the badge is already set. |
21+
| `outlined` | boolean | Set whether the badge should have an outline. Default is `false`. |
22+
| `shape` | string | Set the shape of the badge to either `rounded` or `square`. Default is `rounded`. |
2023

2124
# Examples
2225

@@ -26,3 +29,18 @@ Using `igx-badge` with the `igx-avatar` component to show active status.
2629
<igx-badge type="info" value="8"></igx-badge>
2730
</igx-avatar>
2831
```
32+
33+
Using `igx-badge` as a dot indicator for notifications.
34+
```html
35+
<igx-badge dot type="success"></igx-badge>
36+
<igx-badge dot outlined type="error"></igx-badge>
37+
```
38+
39+
Using different badge types.
40+
```html
41+
<igx-badge type="primary" value="1"></igx-badge>
42+
<igx-badge type="info" value="2"></igx-badge>
43+
<igx-badge type="success" value="3"></igx-badge>
44+
<igx-badge type="warning" value="4"></igx-badge>
45+
<igx-badge type="error" value="5"></igx-badge>
46+
```

projects/igniteui-angular/src/lib/badge/badge.component.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ describe('Badge', () => {
1111
InitBadgeWithDefaultsComponent,
1212
InitBadgeWithIconComponent,
1313
IgxBadgeComponent,
14-
InitBadgeWithIconARIAComponent
14+
InitBadgeWithIconARIAComponent,
15+
InitBadgeWithDotComponent
1516
]
1617
}).compileComponents();
1718
}));
@@ -87,6 +88,26 @@ describe('Badge', () => {
8788
const container = fixture.nativeElement.querySelectorAll('.igx-badge')[0];
8889
expect(container.getAttribute('aria-roledescription')).toMatch(expectedDescription);
8990
});
91+
92+
it('Initializes badge with dot property', () => {
93+
const fixture = TestBed.createComponent(InitBadgeWithDotComponent);
94+
fixture.detectChanges();
95+
const badge = fixture.componentInstance.badge;
96+
97+
expect(badge.dot).toBeTruthy();
98+
expect(fixture.debugElement.query(By.css('.igx-badge--dot'))).toBeTruthy();
99+
});
100+
101+
it('Initializes success badge as dot', () => {
102+
const fixture = TestBed.createComponent(InitBadgeWithDotComponent);
103+
fixture.detectChanges();
104+
const badge = fixture.componentInstance.badge;
105+
106+
expect(badge.type).toBe(IgxBadgeType.SUCCESS);
107+
expect(badge.dot).toBeTruthy();
108+
expect(fixture.debugElement.query(By.css('.igx-badge--dot'))).toBeTruthy();
109+
expect(fixture.debugElement.query(By.css('.igx-badge--success'))).toBeTruthy();
110+
});
90111
});
91112

92113
@Component({
@@ -120,3 +141,11 @@ class InitBadgeWithIconComponent {
120141
class InitBadgeWithIconARIAComponent {
121142
@ViewChild(IgxBadgeComponent, { static: true }) public badge: IgxBadgeComponent;
122143
}
144+
145+
@Component({
146+
template: `<igx-badge dot type="success"></igx-badge>`,
147+
imports: [IgxBadgeComponent]
148+
})
149+
class InitBadgeWithDotComponent {
150+
@ViewChild(IgxBadgeComponent, { static: true }) public badge: IgxBadgeComponent;
151+
}

0 commit comments

Comments
 (0)