Skip to content

Commit 2b59031

Browse files
mvdluitkirjs
authored andcommitted
docs(docs-infra): add status filter to api reference overview (angular#57614)
add a status filter on the api reference overview page to filter on status (all|stable|deprecated|developer-preview|experimental) PR Close angular#57614
1 parent 11d441f commit 2b59031

14 files changed

+275
-117
lines changed

adev/shared-docs/styles/_colors.scss

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,24 +263,36 @@
263263
}
264264
}
265265

266-
@mixin mdc-definitions() {
267-
@include mat.snack-bar-overrides(
268-
(
269-
container-shape: 0.25rem,
270-
container-color: var(--page-background),
271-
supporting-text-color: var(--primary-contrast),
272-
)
273-
);
274-
}
266+
@include mat.snack-bar-overrides(
267+
(
268+
container-shape: 0.25rem,
269+
container-color: var(--page-background),
270+
supporting-text-color: var(--primary-contrast),
271+
)
272+
);
273+
274+
@include mat.chips-overrides(
275+
(
276+
outline-color: var(--quinary-contrast),
277+
disabled-outline-color: var(--quinary-contrast),
278+
flat-selected-outline-width: 1px,
279+
label-text-color: var(--tertiary-contrast),
280+
label-text-size: 14px,
281+
label-text-line-height: 20px,
282+
283+
with-icon-icon-color: var(--french-violet),
284+
with-icon-selected-icon-color: var(--french-violet),
285+
selected-label-text-color: var(--french-violet),
286+
focus-outline-color: var(--french-violet),
287+
)
288+
);
275289

276290
// LIGHT MODE (Explicit)
277291
.docs-light-mode {
278292
background-color: #ffffff;
279293
@include root-definitions();
280-
@include mdc-definitions();
281294
.docs-invert-mode {
282295
@include dark-mode-definitions();
283-
@include mdc-definitions();
284296
}
285297
}
286298

@@ -289,9 +301,7 @@
289301
background-color: oklch(16.93% 0.004 285.95);
290302
@include root-definitions();
291303
@include dark-mode-definitions();
292-
@include mdc-definitions();
293304
.docs-invert-mode {
294305
@include root-definitions();
295-
@include mdc-definitions();
296306
}
297307
}

adev/src/app/features/references/api-items-section/api-items-section.component.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ <h3 [id]="group().id">
2929
<span class="adev-item-title" [attr.title]="apiItem.title">{{ apiItem.title }}</span>
3030
</a>
3131
@if (apiItem.isDeprecated) {
32-
<span class="adev-deprecated"> &lt;!&gt; </span>
32+
<span class="adev-item-attribute" matTooltip="Deprecated"> &lt;!&gt; </span>
33+
}
34+
@if(apiItem.isExperimental) {
35+
<span class="adev-item-attribute" matTooltip="Experimental"> 🧪 </span>
36+
}
37+
@if(apiItem.isDeveloperPreview) {
38+
<span class="adev-item-attribute" matTooltip="Developer Preview"> 🚧 </span>
3339
}
3440
</li>
3541
}

adev/src/app/features/references/api-items-section/api-items-section.component.scss

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,12 @@
7979
gap: 1em;
8080
}
8181

82-
.adev-deprecated {
82+
.adev-item-attribute {
83+
width: 24px;
84+
text-align: center;
8385
font-family: var(--code-font);
8486
background-color: var(--senary-contrast);
8587
color: var(--tertiary-contrast);
86-
width: max-content;
8788
border-radius: 0.25rem;
8889
padding: 0.001rem 0.2rem 0.005rem;
8990
margin-inline-start: 0.5rem;

adev/src/app/features/references/api-items-section/api-items-section.component.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ describe('ApiItemsSection', () => {
5959
fixture.detectChanges();
6060

6161
const deprecatedApiIcons = fixture.debugElement.queryAll(
62-
By.css('.adev-api-items-section-grid li .adev-deprecated'),
62+
By.css('.adev-api-items-section-grid li .adev-item-attribute'),
6363
);
6464
const deprecatedApiTitle = deprecatedApiIcons[0].parent?.query(By.css('.adev-item-title'));
6565

adev/src/app/features/references/api-items-section/api-items-section.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import {ChangeDetectionStrategy, Component, input} from '@angular/core';
1010
import {RouterLink} from '@angular/router';
1111
import {ApiItemsGroup} from '../interfaces/api-items-group';
1212
import ApiItemLabel from '../api-item-label/api-item-label.component';
13+
import {MatTooltipModule} from '@angular/material/tooltip';
1314

1415
@Component({
1516
selector: 'adev-api-items-section',
16-
imports: [ApiItemLabel, RouterLink],
17+
imports: [ApiItemLabel, RouterLink, MatTooltipModule],
1718
templateUrl: './api-items-section.component.html',
1819
styleUrls: ['./api-items-section.component.scss'],
1920
changeDetection: ChangeDetectionStrategy.OnPush,

adev/src/app/features/references/api-reference-details-page/api-reference-details-page.component.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const HIGHLIGHTED_CARD_CLASS = 'docs-highlighted-card';
1818

1919
@Component({
2020
selector: 'adev-reference-page',
21-
standalone: true,
2221
imports: [DocViewer],
2322
templateUrl: './api-reference-details-page.component.html',
2423
styleUrls: ['./api-reference-details-page.component.scss'],

adev/src/app/features/references/api-reference-list/api-reference-list.component.html

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,18 @@ <h1>API Reference</h1>
44

55
<div class="adev-reference-list-filter">
66
<div class="adev-reference-list-query-filter">
7-
<docs-text-field
8-
name="query"
9-
placeholder="Filter"
10-
[(ngModel)]="query"
11-
(ngModelChange)="syncUrlWithFilters()"
12-
/>
7+
<docs-text-field name="query" placeholder="Filter" [(ngModel)]="query" />
8+
</div>
139

14-
<docs-slide-toggle
15-
buttonId="includeDeprecated"
16-
label="Show @deprecated"
17-
name="includeDeprecated"
18-
[(ngModel)]="includeDeprecated"
19-
/>
10+
<div class="adev-reference-list-status">
11+
<mat-chip-listbox multiple="true" aria-label="Status selection">
12+
<!-- null indicates to not re-order the object keys -->
13+
@for (stat of statuses | keyvalue:null; track $index) {
14+
<mat-chip-option [selected]="isStatusSelected(stat.value)" (click)="setStatus(stat.value)">
15+
{{statusLabels[stat.value]}}
16+
</mat-chip-option>
17+
}
18+
</mat-chip-listbox>
2019
</div>
2120

2221
<p class="adev-reference-list-type-filter-label">Filter by Identifier type</p>
@@ -25,7 +24,7 @@ <h1>API Reference</h1>
2524
<li
2625
class="adev-reference-list-type-filter-item"
2726
[class.adev-reference-list-type-filter-item-active]="type() === itemType"
28-
(click)="filterByItemType(itemType)"
27+
(click)="setItemType(itemType)"
2928
>
3029
<docs-api-item-label [type]="itemType" mode="short" class="docs-api-item-label" />
3130
<span class="docs-api-item-label-full">{{ itemType | adevApiLabel : 'full' }}</span>

adev/src/app/features/references/api-reference-list/api-reference-list.component.scss

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,28 @@
108108
width: 100%;
109109
}
110110
}
111+
112+
.adev-reference-list-empty {
113+
flex-basis: 100%;
114+
p {
115+
font-size: 1rem;
116+
}
117+
}
118+
119+
.docs-api-item-label-full {
120+
white-space: nowrap;
121+
}
122+
123+
.map-chip-option {
124+
min-width: 190px;
125+
}
126+
127+
.adev-reference-list-status {
128+
display: flex;
129+
align-items: center;
130+
margin-top: 12px;
131+
132+
label {
133+
margin-right: 8px;
134+
}
135+
}

adev/src/app/features/references/api-reference-list/api-reference-list.component.spec.ts

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88

99
import {ComponentFixture, TestBed} from '@angular/core/testing';
1010

11-
import ApiReferenceList, {ALL_TYPES_KEY} from './api-reference-list.component';
11+
import ApiReferenceList, {
12+
ALL_TYPES_KEY,
13+
DEFAULT_STATUS,
14+
STATUSES,
15+
} from './api-reference-list.component';
1216
import {ApiReferenceManager} from './api-reference-manager.service';
1317
import {signal} from '@angular/core';
1418
import {ApiItemType} from '../interfaces/api-item-type';
@@ -26,24 +30,52 @@ describe('ApiReferenceList', () => {
2630
'url': 'api/animations/fakeItem1',
2731
'itemType': ApiItemType.FUNCTION,
2832
'isDeprecated': false,
33+
'isDeveloperPreview': false,
34+
'isExperimental': false,
2935
};
3036
let fakeItem2 = {
3137
'title': 'fakeItem2',
3238
'url': 'api/animations/fakeItem2',
3339
'itemType': ApiItemType.CLASS,
3440
'isDeprecated': false,
41+
'isDeveloperPreview': false,
42+
'isExperimental': false,
3543
};
3644
let fakeDeprecatedFeaturedItem = {
3745
'title': 'fakeItemDeprecated',
3846
'url': 'api/animations/fakeItemDeprecated',
3947
'itemType': ApiItemType.INTERFACE,
4048
'isDeprecated': true,
49+
'isDeveloperPreview': false,
50+
'isExperimental': false,
51+
};
52+
let fakeDeveloperPreviewItem = {
53+
'title': 'fakeItemDeveloperPreview',
54+
'url': 'api/animations/fakeItemDeveloperPreview',
55+
'itemType': ApiItemType.INTERFACE,
56+
'isDeprecated': false,
57+
'isDeveloperPreview': true,
58+
'isExperimental': false,
59+
};
60+
let fakeExperimentalItem = {
61+
'title': 'fakeItemExperimental',
62+
'url': 'api/animations/fakeItemExperimental',
63+
'itemType': ApiItemType.INTERFACE,
64+
'isDeprecated': false,
65+
'isDeveloperPreview': false,
66+
'isExperimental': true,
4167
};
4268
const fakeApiReferenceManager = {
4369
apiGroups: signal([
4470
{
4571
title: 'Fake Group',
46-
items: [fakeItem1, fakeItem2, fakeDeprecatedFeaturedItem],
72+
items: [
73+
fakeItem1,
74+
fakeItem2,
75+
fakeDeprecatedFeaturedItem,
76+
fakeDeveloperPreviewItem,
77+
fakeExperimentalItem,
78+
],
4779
isFeatured: false,
4880
},
4981
]),
@@ -71,33 +103,15 @@ describe('ApiReferenceList', () => {
71103
expect(component).toBeTruthy();
72104
});
73105

74-
it('should display both Deprecated and Non-deprecated APIs when includeDeprecated toggle is set to true', () => {
75-
component.includeDeprecated.set(true);
76-
fixture.detectChanges();
77-
78-
expect(component.filteredGroups()![0].items).toEqual([
79-
fakeItem1,
80-
fakeItem2,
81-
fakeDeprecatedFeaturedItem,
82-
]);
83-
});
84-
85-
it('should display both Non-deprecated APIs when includeDeprecated toggle is set to false', () => {
86-
component.includeDeprecated.set(false);
87-
fixture.detectChanges();
88-
89-
expect(component.filteredGroups()![0].items).toEqual([fakeItem1, fakeItem2]);
90-
});
91-
92106
it('should display only items which contains provided query when query is not empty', () => {
93-
component.query.set('Item1');
107+
fixture.componentRef.setInput('query', 'Item1');
94108
fixture.detectChanges();
95109

96110
expect(component.filteredGroups()![0].items).toEqual([fakeItem1]);
97111
});
98112

99113
it('should display only class items when user selects Class in the Type select', () => {
100-
fixture.componentInstance.type.set(ApiItemType.CLASS);
114+
fixture.componentRef.setInput('type', ApiItemType.CLASS);
101115
fixture.detectChanges();
102116

103117
expect(component.type()).toEqual(ApiItemType.CLASS);
@@ -106,17 +120,17 @@ describe('ApiReferenceList', () => {
106120

107121
it('should set selected type when provided type is different than selected', async () => {
108122
expect(component.type()).toBe(ALL_TYPES_KEY);
109-
component.filterByItemType(ApiItemType.BLOCK);
123+
component.setItemType(ApiItemType.BLOCK);
110124
await RouterTestingHarness.create(`/api?type=${ApiItemType.BLOCK}`);
111125
expect(component.type()).toBe(ApiItemType.BLOCK);
112126
});
113127

114128
it('should reset selected type when provided type is equal to selected', async () => {
115-
component.filterByItemType(ApiItemType.BLOCK);
129+
component.setItemType(ApiItemType.BLOCK);
116130
const harness = await RouterTestingHarness.create(`/api?type=${ApiItemType.BLOCK}`);
117131
expect(component.type()).toBe(ApiItemType.BLOCK);
118132

119-
component.filterByItemType(ApiItemType.BLOCK);
133+
component.setItemType(ApiItemType.BLOCK);
120134
harness.navigateByUrl(`/api`);
121135
expect(component.type()).toBe(ALL_TYPES_KEY);
122136
});
@@ -126,28 +140,67 @@ describe('ApiReferenceList', () => {
126140

127141
const textField = fixture.debugElement.query(By.directive(TextField));
128142
(textField.componentInstance as TextField).setValue('item1');
129-
130143
await fixture.whenStable();
131-
expect(location.path()).toBe(`?query=item1&type=All`);
144+
expect(location.path()).toBe(`?query=item1`);
132145
});
133146

134-
it('should keep the values of existing queryParams and set new queryParam equal to the type', async () => {
147+
it('should keep the values of existing queryParams and set new queryParam equal to given value', async () => {
135148
const location = TestBed.inject(Location);
136149

137150
const textField = fixture.debugElement.query(By.directive(TextField));
138151
(textField.componentInstance as TextField).setValue('item1');
139152
await fixture.whenStable();
140-
expect(location.path()).toBe(`?query=item1&type=All`);
153+
expect(location.path()).toBe(`?query=item1`);
141154

142-
component.filterByItemType(ApiItemType.BLOCK);
155+
component.setItemType(ApiItemType.BLOCK);
143156
await fixture.whenStable();
144157
expect(location.path()).toBe(`?query=item1&type=${ApiItemType.BLOCK}`);
158+
159+
fixture.componentRef.setInput('status', STATUSES.experimental);
160+
await fixture.whenStable();
161+
expect(location.path()).toBe(
162+
`?query=item1&type=${ApiItemType.BLOCK}&status=${STATUSES.experimental}`,
163+
);
145164
});
146165

147-
it('should display all items when query and type are undefined', async () => {
148-
component.query.set(undefined);
149-
component.type.set(undefined);
166+
it('should display all items when query and type and status are undefined', async () => {
167+
fixture.componentRef.setInput('query', undefined);
168+
fixture.componentRef.setInput('type', undefined);
169+
fixture.componentRef.setInput('status', undefined);
150170
await fixture.whenStable();
171+
expect(component.filteredGroups()![0].items).toEqual([
172+
fakeItem1,
173+
fakeItem2,
174+
fakeDeveloperPreviewItem,
175+
fakeExperimentalItem,
176+
]);
177+
});
178+
179+
it('should not display deprecated and developer-preview and experimental items when status is set to stable', () => {
180+
fixture.componentRef.setInput('status', STATUSES.stable);
181+
fixture.detectChanges();
182+
151183
expect(component.filteredGroups()![0].items).toEqual([fakeItem1, fakeItem2]);
152184
});
185+
186+
it('should only display deprecated items when status is set to deprecated', () => {
187+
fixture.componentRef.setInput('status', STATUSES.deprecated);
188+
fixture.detectChanges();
189+
190+
expect(component.filteredGroups()![0].items).toEqual([fakeDeprecatedFeaturedItem]);
191+
});
192+
193+
it('should only display developer-preview items when status is set to developer-preview', () => {
194+
fixture.componentRef.setInput('status', STATUSES.developerPreview);
195+
fixture.detectChanges();
196+
197+
expect(component.filteredGroups()![0].items).toEqual([fakeDeveloperPreviewItem]);
198+
});
199+
200+
it('should only display experimental items when status is set to experimental', () => {
201+
fixture.componentRef.setInput('status', STATUSES.experimental);
202+
fixture.detectChanges();
203+
204+
expect(component.filteredGroups()![0].items).toEqual([fakeExperimentalItem]);
205+
});
153206
});

0 commit comments

Comments
 (0)