Skip to content

Commit 1e1162f

Browse files
committed
chore: added username search text function build
1 parent 1816f25 commit 1e1162f

6 files changed

Lines changed: 104 additions & 13 deletions

File tree

packages/components/username/__snapshots__/username.spec.ts.snap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,17 @@ exports[`KbqUsernamePipe should format full name using custom format 1`] = `
1818
"Alice B. C.",
1919
]
2020
`;
21+
22+
exports[`kbqBuildUsernameText should append login after name 1`] = `"Root M. A. mroot"`;
23+
24+
exports[`kbqBuildUsernameText should include site without login 1`] = `"Root M. A. (corp)"`;
25+
26+
exports[`kbqBuildUsernameText should return name only when login and site are absent 1`] = `"Root M. A."`;
27+
28+
exports[`kbqBuildUsernameText should skip empty name and join remaining parts 1`] = `"mroot (corp)"`;
29+
30+
exports[`kbqBuildUsernameText should use custom formatLogin 1`] = `"Root M. A. [@mroot]"`;
31+
32+
exports[`kbqBuildUsernameText should use custom formatSite 1`] = `"Root M. A. corp"`;
33+
34+
exports[`kbqBuildUsernameText should wrap site in parentheses by default 1`] = `"Root M. A. mroot (corp)"`;

packages/components/username/username.pipe.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
KbqMappingMissingError
77
} from './constants';
88
import { KbqFormatKeyToProfileMapping, KbqFormatKeyToProfileMappingExtended, KbqUsernameFormatKey } from './types';
9+
import { KbqUserInfo } from './username';
910

1011
@Injectable({ providedIn: 'root' })
1112
@Pipe({
@@ -95,3 +96,31 @@ export class KbqUsernameCustomPipe<T = unknown> implements PipeTransform {
9596
return result.trim();
9697
}
9798
}
99+
100+
export interface KbqUsernameTextOptions {
101+
/** Formats the login segment. Defaults to identity. */
102+
formatLogin?: (login: string) => string;
103+
/**
104+
* Formats the site segment.
105+
* Defaults to wrapping in parentheses, matching kbq-username display.
106+
*/
107+
formatSite?: (site: string) => string;
108+
}
109+
110+
/**
111+
* Builds a full username string from a pre-formatted name plus optional login and site,
112+
* mirroring the text rendered by `kbq-username`.
113+
*
114+
* Provide custom `formatLogin` / `formatSite` to tailor the output.
115+
*/
116+
export function kbqBuildUsernameText(
117+
data: { name: string } & Partial<Pick<KbqUserInfo, 'login' | 'site'>>,
118+
options?: KbqUsernameTextOptions
119+
): string {
120+
const formatLogin = options?.formatLogin ?? ((login) => login);
121+
const formatSite = options?.formatSite ?? ((site) => `(${site})`);
122+
123+
return [data.name, data.login && formatLogin(data.login), data.site && formatSite(data.site)]
124+
.filter(Boolean)
125+
.join(' ');
126+
}

packages/components/username/username.spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
KbqUsernameStyle
1010
} from './types';
1111
import { KbqUsername, KbqUsernameCustomView } from './username';
12-
import { KbqUsernameCustomPipe, KbqUsernamePipe } from './username.pipe';
12+
import { kbqBuildUsernameText, KbqUsernameCustomPipe, KbqUsernamePipe } from './username.pipe';
1313

1414
const createComponent = <T>(component: Type<T>, providers: any[] = []): ComponentFixture<T> => {
1515
TestBed.configureTestingModule({ imports: [component], providers }).compileComponents();
@@ -120,6 +120,38 @@ describe(KbqUsernamePipe.name, () => {
120120
});
121121
});
122122

123+
describe('kbqBuildUsernameText', () => {
124+
it('should return name only when login and site are absent', () => {
125+
expect(kbqBuildUsernameText({ name: 'Root M. A.' })).toMatchSnapshot();
126+
});
127+
128+
it('should append login after name', () => {
129+
expect(kbqBuildUsernameText({ name: 'Root M. A.', login: 'mroot' })).toMatchSnapshot();
130+
});
131+
132+
it('should wrap site in parentheses by default', () => {
133+
expect(kbqBuildUsernameText({ name: 'Root M. A.', login: 'mroot', site: 'corp' })).toMatchSnapshot();
134+
});
135+
136+
it('should include site without login', () => {
137+
expect(kbqBuildUsernameText({ name: 'Root M. A.', site: 'corp' })).toMatchSnapshot();
138+
});
139+
140+
it('should use custom formatSite', () => {
141+
expect(kbqBuildUsernameText({ name: 'Root M. A.', site: 'corp' }, { formatSite: (s) => s })).toMatchSnapshot();
142+
});
143+
144+
it('should use custom formatLogin', () => {
145+
expect(
146+
kbqBuildUsernameText({ name: 'Root M. A.', login: 'mroot' }, { formatLogin: (s) => `[@${s}]` })
147+
).toMatchSnapshot();
148+
});
149+
150+
it('should skip empty name and join remaining parts', () => {
151+
expect(kbqBuildUsernameText({ name: '', login: 'mroot', site: 'corp' })).toMatchSnapshot();
152+
});
153+
});
154+
123155
describe(KbqUsername.name, () => {
124156
it('should use default input values', () => {
125157
const { debugElement } = createComponent(TestComponent);

packages/docs-examples/components/username/username-filter-bar-option/username-filter-bar-option-example.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { AfterViewInit, ChangeDetectionStrategy, Component, inject, TemplateRef, ViewChild } from '@angular/core';
1+
import { AfterViewInit, ChangeDetectionStrategy, Component, inject, TemplateRef, viewChild } from '@angular/core';
22
import { KbqHighlightBackgroundPipe } from '@koobiq/components/core';
33
import { KbqFilter, KbqFilterBarModule, KbqPipeTemplate, KbqPipeTypes } from '@koobiq/components/filter-bar';
4-
import { KbqUserInfo, KbqUsernameModule, KbqUsernamePipe } from '@koobiq/components/username';
4+
import { kbqBuildUsernameText, KbqUserInfo, KbqUsernameModule, KbqUsernamePipe } from '@koobiq/components/username';
55

66
const USERS: KbqUserInfo[] = [
77
{ firstName: 'Maxwell', middleName: 'Alan', lastName: 'Root', login: 'mroot', site: 'corp' },
@@ -45,8 +45,7 @@ const USERS: KbqUserInfo[] = [
4545
})
4646
export class UsernameFilterBarOptionExample implements AfterViewInit {
4747
private readonly usernamePipe = inject(KbqUsernamePipe);
48-
49-
@ViewChild('userOption') userOptionTemplate: TemplateRef<any>;
48+
private readonly userOptionTemplate = viewChild<TemplateRef<any>>('userOption');
5049

5150
activeFilter: KbqFilter = {
5251
name: '',
@@ -75,11 +74,14 @@ export class UsernameFilterBarOptionExample implements AfterViewInit {
7574
name: 'Assignee',
7675
type: KbqPipeTypes.Select,
7776
values: USERS.map((user) => ({
78-
name: `${this.usernamePipe.transform(user)} ${[user.login, user.site].filter(Boolean).join(' ')}`,
77+
name: kbqBuildUsernameText(
78+
{ name: this.usernamePipe.transform(user), login: user.login, site: user.site },
79+
{ formatSite: (s) => s }
80+
),
7981
value: user,
8082
id: user.login
8183
})),
82-
valueTemplate: this.userOptionTemplate,
84+
valueTemplate: this.userOptionTemplate(),
8385
cleanable: true,
8486
removable: false,
8587
disabled: false

packages/docs-examples/components/username/username-search/username-search-example.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { KbqHighlightBackgroundPipe } from '@koobiq/components/core';
55
import { KbqFormFieldModule } from '@koobiq/components/form-field';
66
import { KbqIconModule } from '@koobiq/components/icon';
77
import { KbqInputModule } from '@koobiq/components/input';
8-
import { KbqUserInfo, KbqUsernameModule, KbqUsernamePipe } from '@koobiq/components/username';
8+
import { kbqBuildUsernameText, KbqUserInfo, KbqUsernameModule, KbqUsernamePipe } from '@koobiq/components/username';
99
import { startWith } from 'rxjs';
1010

1111
/**
@@ -82,10 +82,13 @@ export class UsernameSearchExample {
8282

8383
if (!query) return this.users;
8484

85-
return this.users.filter((user) => {
86-
const formatted = this.usernamePipe.transform(user).toLowerCase();
87-
88-
return formatted.includes(query) || (user.login?.toLowerCase().includes(query) ?? false);
89-
});
85+
return this.users.filter((user) =>
86+
kbqBuildUsernameText(
87+
{ name: this.usernamePipe.transform(user), login: user.login, site: user.site },
88+
{ formatSite: (s) => s }
89+
)
90+
.toLowerCase()
91+
.includes(query)
92+
);
9093
});
9194
}

tools/public_api_guard/components/username.api.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ import { PipeTransform } from '@angular/core';
1111
// @public
1212
export const KBQ_PROFILE_MAPPING: InjectionToken<KbqFormatKeyToProfileMapping | KbqFormatKeyToProfileMappingExtended>;
1313

14+
// @public
15+
export function kbqBuildUsernameText(data: {
16+
name: string;
17+
} & Partial<Pick<KbqUserInfo, 'login' | 'site'>>, options?: KbqUsernameTextOptions): string;
18+
1419
// @public
1520
export const kbqDefaultFullNameFormat = "lf.m.";
1621

@@ -137,6 +142,12 @@ export class KbqUsernameSecondaryHint {
137142
// @public
138143
export type KbqUsernameStyle = 'default' | 'error' | 'accented' | 'inherit';
139144

145+
// @public (undocumented)
146+
export interface KbqUsernameTextOptions {
147+
formatLogin?: (login: string) => string;
148+
formatSite?: (site: string) => string;
149+
}
150+
140151
// (No @packageDocumentation comment for this package)
141152

142153
```

0 commit comments

Comments
 (0)