diff --git a/packages/components-dev/filter-bar/module.ts b/packages/components-dev/filter-bar/module.ts index eaea0b3ba..a6f6b4577 100644 --- a/packages/components-dev/filter-bar/module.ts +++ b/packages/components-dev/filter-bar/module.ts @@ -31,6 +31,9 @@ import { DevLocaleSelector } from '../locale-selector'; imports: [FilterBarExamplesModule], selector: 'dev-docs-examples', template: ` + +
+


@@ -613,6 +616,25 @@ export class DemoComponent implements AfterViewInit { removable: false, disabled: false }, + { + name: 'mySelect', + type: KbqPipeTypes.Select, + id: 'mySelect', + values: [ + { name: 'Option 1', id: '1', type: 'error' }, + { name: 'Option 2', id: '2', type: 'warning' }, + { name: 'Option 3', id: '3', type: 'success' }, + { name: 'Option 4', id: '4', type: 'error' }, + { name: 'Option 5', id: '5', type: 'warning' } + ], + valueTemplate: this.optionTemplate, + search: true, + + required: false, + cleanable: false, + removable: false, + disabled: false + }, { name: 'MultiSelect', type: KbqPipeTypes.MultiSelect, @@ -636,6 +658,25 @@ export class DemoComponent implements AfterViewInit { removable: true, disabled: false }, + { + name: 'myMultiSelect', + type: KbqPipeTypes.MultiSelect, + id: 'myMultiSelect', + values: [ + { name: 'Option 1', id: '1', type: 'error' }, + { name: 'Option 2', id: '2', type: 'warning' }, + { name: 'Option 3', id: '3', type: 'success' }, + { name: 'Option 4', id: '4', type: 'error' }, + { name: 'Option 5', id: '5', type: 'warning' } + ], + valueTemplate: this.optionTemplate, + search: true, + + required: false, + cleanable: false, + removable: true, + disabled: false + }, { name: 'Text', type: KbqPipeTypes.Text, @@ -645,6 +686,16 @@ export class DemoComponent implements AfterViewInit { removable: false, disabled: false }, + { + name: 'myText', + type: KbqPipeTypes.Text, + id: 'myText', + + required: false, + cleanable: false, + removable: false, + disabled: false + }, { name: 'Date', type: KbqPipeTypes.Date, @@ -661,6 +712,23 @@ export class DemoComponent implements AfterViewInit { removable: false, disabled: false }, + { + name: 'myDate', + type: KbqPipeTypes.Date, + id: 'myDate', + values: [ + { name: 'Последний день', end: null, start: { days: -1 } }, + { name: 'Последние 3 дня', end: null, start: { days: -3 } }, + { name: 'Последние 7 дней', end: null, start: { days: -7 } }, + { name: 'Последние 30 дней', end: null, start: { days: -30 } }, + { name: 'Последние 90 дней', end: null, start: { days: -90 } }, + { name: 'Последний год', end: null, start: { years: -1 } } + ], + required: false, + cleanable: false, + removable: false, + disabled: false + }, { name: 'Datetime', type: KbqPipeTypes.Datetime, @@ -676,6 +744,23 @@ export class DemoComponent implements AfterViewInit { cleanable: true, removable: false, disabled: false + }, + { + name: 'myDatetime', + type: KbqPipeTypes.Datetime, + id: 'myDatetime', + values: [ + { name: 'Последний день', end: null, start: { days: -1 } }, + { name: 'Последние 3 дня', end: null, start: { days: -3 } }, + { name: 'Последние 7 дней', end: null, start: { days: -7 } }, + { name: 'Последние 30 дней', end: null, start: { days: -30 } }, + { name: 'Последние 90 дней', end: null, start: { days: -90 } }, + { name: 'Последний год', end: null, start: { years: -1 } } + ], + required: false, + cleanable: true, + removable: false, + disabled: false } ]; } diff --git a/packages/components/filter-bar/examples.filter-bar.en.md b/packages/components/filter-bar/examples.filter-bar.en.md index 8ee4766f6..317222a19 100644 --- a/packages/components/filter-bar/examples.filter-bar.en.md +++ b/packages/components/filter-bar/examples.filter-bar.en.md @@ -1 +1,7 @@ +#### Example of adding a custom pipe + + +#### Example of multiple pipes with the same type + + diff --git a/packages/components/filter-bar/examples.filter-bar.ru.md b/packages/components/filter-bar/examples.filter-bar.ru.md index d30519895..4df7b39ce 100644 --- a/packages/components/filter-bar/examples.filter-bar.ru.md +++ b/packages/components/filter-bar/examples.filter-bar.ru.md @@ -1,3 +1,7 @@ #### Пример добавления пользовательского пайпа + +#### Пример множества пайпов с одинаковым типом + + diff --git a/packages/components/filter-bar/pipe-add.ts b/packages/components/filter-bar/pipe-add.ts index d445965ea..dded35ee5 100644 --- a/packages/components/filter-bar/pipe-add.ts +++ b/packages/components/filter-bar/pipe-add.ts @@ -18,6 +18,7 @@ import { KbqSelect, KbqSelectModule } from '@koobiq/components/select'; import { KbqToolTipModule } from '@koobiq/components/tooltip'; import { KbqFilterBar } from './filter-bar'; import { KbqFilter, KbqPipe, KbqPipeTemplate } from './filter-bar.types'; +import { getId } from './pipes/base-pipe'; @Component({ standalone: true, @@ -92,14 +93,14 @@ export class KbqPipeAdd { constructor() { this.filterBar.changes.pipe(takeUntilDestroyed()).subscribe(() => { if (this.filterBar?.filter) { - this.addedPipes = this.filterBar.filter.pipes.map((pipe: KbqPipe) => pipe.id || pipe.name); + this.addedPipes = this.filterBar.filter.pipes.map((pipe: KbqPipe) => getId(pipe)); } }); } addPipeFromTemplate(option: KbqOption) { if (option.selected) { - this.filterBar.openPipe.next(option.value.id || option.value.name); + this.filterBar.openPipe.next(getId(option.value)); } else { option.select(); @@ -125,6 +126,6 @@ export class KbqPipeAdd { * should be returned. */ compareWith(o1: KbqPipe, o2: string): boolean { - return (o1.id || o1.name) === o2; + return getId(o1) === o2; } } diff --git a/packages/components/filter-bar/pipes/base-pipe.ts b/packages/components/filter-bar/pipes/base-pipe.ts index 6009b74bc..92d33d08d 100644 --- a/packages/components/filter-bar/pipes/base-pipe.ts +++ b/packages/components/filter-bar/pipes/base-pipe.ts @@ -13,11 +13,16 @@ import { isMac } from '@koobiq/components/core'; import { Subject } from 'rxjs'; import { delay, filter } from 'rxjs/operators'; import { KbqFilterBar } from '../filter-bar'; -import { KbqPipeData, KbqPipeTemplate } from '../filter-bar.types'; +import { KbqPipeData, KbqPipeTemplate, KbqPipeType } from '../filter-bar.types'; /** Injection Token for providing configuration of filter-bar */ export const KBQ_PIPE_DATA = new InjectionToken('KBQ_PIPE_DATA'); +/** function to get unique identifier of an element */ +export function getId(item: KbqPipeTemplate): KbqPipeType | string | number { + return item?.id ?? item?.name; +} + @Directive({ standalone: true, host: { @@ -86,8 +91,8 @@ export abstract class KbqBasePipe implements AfterViewInit { this.open(); } - this.filterBar?.openPipe.pipe(filter(Boolean)).subscribe((name) => { - if (this.data.name === name) { + this.filterBar?.openPipe.pipe(filter(Boolean)).subscribe((id) => { + if (getId(this.data) === id) { this.open(); } }); @@ -100,7 +105,7 @@ export abstract class KbqBasePipe implements AfterViewInit { /** updates values for selection and value template */ updateTemplates = (templates: KbqPipeTemplate[] | null) => { - const template = templates?.find((template) => template.type === this.data?.type); + const template = templates?.find((template) => getId(template) === getId(this.data)); if (template?.values) { this.values = template.values; diff --git a/packages/docs-examples/components/filter-bar/filter-bar-removable/filter-bar-removable-example.ts b/packages/docs-examples/components/filter-bar/filter-bar-removable/filter-bar-removable-example.ts index b556422e6..be937a84a 100644 --- a/packages/docs-examples/components/filter-bar/filter-bar-removable/filter-bar-removable-example.ts +++ b/packages/docs-examples/components/filter-bar/filter-bar-removable/filter-bar-removable-example.ts @@ -41,7 +41,7 @@ export class FilterBarRemovableExample { disabled: false }, { - name: 'SelectMultiple', + name: 'MultiSelect', type: KbqPipeTypes.MultiSelect, value: [], diff --git a/packages/docs-examples/components/filter-bar/filter-bar-uniq-pipes/filter-bar-uniq-pipes-example.ts b/packages/docs-examples/components/filter-bar/filter-bar-uniq-pipes/filter-bar-uniq-pipes-example.ts new file mode 100644 index 000000000..c5df17c1c --- /dev/null +++ b/packages/docs-examples/components/filter-bar/filter-bar-uniq-pipes/filter-bar-uniq-pipes-example.ts @@ -0,0 +1,420 @@ +import { Component } from '@angular/core'; +import { LuxonDateModule } from '@koobiq/angular-luxon-adapter/adapter'; +import { KbqFilter, KbqFilterBarModule, KbqPipeTemplate, KbqPipeTypes } from '@koobiq/components/filter-bar'; + +/** + * @title filter bar + */ +@Component({ + standalone: true, + selector: 'filter-bar-uniq-pipes-example', + imports: [ + KbqFilterBarModule, + LuxonDateModule + ], + template: ` + + + + @for (pipe of activeFilter?.pipes; track pipe) { + + } + + + + @if (activeFilter?.name !== defaultFilter?.name || activeFilter?.changed) { + + } + + + + ` +}) +export class FilterBarUniqPipesExample { + filters: KbqFilter[] = [ + { + name: 'Saved Filter 1', + readonly: false, + disabled: false, + changed: false, + saved: true, + pipes: [ + { + name: 'Datetime', + value: { + name: 'Последние 7 дней', + end: null, + start: { days: -7 } + }, + type: KbqPipeTypes.Datetime, + + required: true, + cleanable: false, + removable: false, + disabled: false + }, + { + name: 'Select', + value: { name: 'Option 6', id: '6' }, + type: KbqPipeTypes.Select, + + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Text', + value: 'Angular Rules', + type: KbqPipeTypes.Text, + + required: false, + cleanable: false, + removable: true, + disabled: false + } + ] + }, + { + name: 'Saved Filter 2', + readonly: false, + disabled: false, + changed: false, + saved: true, + pipes: [ + { + name: 'Datetime', + value: { + name: 'Последний год', + end: null, + start: { years: -1 } + }, + type: KbqPipeTypes.Datetime, + + required: true, + cleanable: false, + removable: false, + disabled: false + }, + { + name: 'MultiSelect', + value: [ + { name: 'Option 1', id: '1' }, + { name: 'Option 3', id: '3' }, + { name: 'Option 4', id: '4' } + ], + type: KbqPipeTypes.MultiSelect, + + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Date', + value: { + name: 'Последние 7 дней', + end: null, + start: { days: -7 } + }, + type: KbqPipeTypes.Date, + + required: false, + cleanable: false, + removable: true, + disabled: false + } + ] + }, + { + name: 'Saved Filter 3', + readonly: false, + disabled: false, + changed: false, + saved: true, + pipes: [ + { + name: 'Datetime', + value: { + name: 'Последние 3 дня', + end: null, + start: { days: -3 } + }, + type: KbqPipeTypes.Datetime, + + required: true, + cleanable: false, + removable: false, + disabled: false + }, + { + name: 'Select', + value: { name: 'Option 5', id: '5' }, + type: KbqPipeTypes.Select, + + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'MultiSelect', + value: [ + { name: 'Option 1', id: '1' }, + { name: 'Option 2', id: '2' } + ], + type: KbqPipeTypes.MultiSelect, + + required: false, + cleanable: false, + removable: true, + disabled: false + } + ] + } + ]; + savedFilters: KbqFilter[] = structuredClone(this.filters); + + defaultFilter: KbqFilter | null = this.getDefaultFilter(); + activeFilter: KbqFilter | null = this.getDefaultFilter(); + + pipeTemplates: KbqPipeTemplate[] = [ + { + name: 'Date', + type: KbqPipeTypes.Date, + values: [ + { name: 'Последний день', start: { days: -1 }, end: null }, + { name: 'Последние 3 дня', start: { days: -3 }, end: null }, + { name: 'Последние 7 дней', start: { days: -7 }, end: null }, + { name: 'Последние 30 дней', start: { days: -30 }, end: null }, + { name: 'Последние 90 дней', start: { days: -90 }, end: null }, + { name: 'Последний год', start: { years: -1 }, end: null } + ], + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'myDate', + type: KbqPipeTypes.Date, + values: [ + { name: 'Последний день', start: { days: -1 }, end: null }, + { name: 'Последние 3 дня', start: { days: -3 }, end: null }, + { name: 'Последние 7 дней', start: { days: -7 }, end: null } + ], + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Datetime', + type: KbqPipeTypes.Datetime, + values: [ + { name: 'Последний час', start: { hours: -1 }, end: null }, + { name: 'Последние 3 часа', start: { hours: -3 }, end: null }, + { name: 'Последние 24 часа', start: { hours: -24 }, end: null }, + { name: 'Последние 3 дня', start: { days: -3 }, end: null }, + { name: 'Последние 7 дней', start: { days: -7 }, end: null }, + { name: 'Последние 30 дней', start: { days: -30 }, end: null }, + { name: 'Последние 90 дней', start: { days: -90 }, end: null }, + { name: 'Последний год', start: { years: -1 }, end: null } + ], + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Datetime_1', + id: 'myDatetime', + type: KbqPipeTypes.Datetime, + values: [ + { name: 'Последний час', start: { hours: -1 }, end: null }, + { name: 'Последние 3 часа', start: { hours: -3 }, end: null }, + { name: 'Последние 24 часа', start: { hours: -24 }, end: null } + ], + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'MultiSelect', + type: KbqPipeTypes.MultiSelect, + values: [ + { name: 'Option 1', id: '1' }, + { name: 'Option 2', id: '2' }, + { name: 'Option 3', id: '3' }, + { name: 'Option 4', id: '4' }, + { name: 'Option 5', id: '5' }, + { name: 'Option 6', id: '6' }, + { name: 'Option 7', id: '7' } + ], + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'MultiSelect_1', + id: 'myMultiSelect', + type: KbqPipeTypes.MultiSelect, + values: [ + { name: 'Option 1', id: '1' }, + { name: 'Option 2', id: '2' }, + { name: 'Option 3', id: '3' }, + { name: 'Option 4', id: '4' } + ], + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Select', + type: KbqPipeTypes.Select, + values: [ + { name: 'Option 1', id: '1' }, + { name: 'Option 2', id: '2' }, + { name: 'Option 3', id: '3' }, + { name: 'Option 4', id: '4' }, + { name: 'Option 5', id: '5' }, + { name: 'Option 6', id: '6' }, + { name: 'Option 7', id: '7' } + ], + + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Select_1', + id: 'mySelect', + type: KbqPipeTypes.Select, + values: [ + { name: 'Option 1', id: '1' }, + { name: 'Option 2', id: '2' }, + { name: 'Option 3', id: '3' }, + { name: 'Option 4', id: '4' }, + { name: 'Option 5', id: '5' }, + { name: 'Option 6', id: '6' }, + { name: 'Option 7', id: '7' } + ], + + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Text', + type: KbqPipeTypes.Text, + + required: false, + cleanable: false, + removable: true, + disabled: false + }, + { + name: 'Text_1', + id: 'myText', + type: KbqPipeTypes.Text, + + required: false, + cleanable: false, + removable: true, + disabled: false + } + ]; + + onFilterChange(filter: KbqFilter | null) { + console.log('onFilterChange: ', filter); + } + + onResetFilter() { + console.log('onResetFilter: '); + this.activeFilter = this.getDefaultFilter(); + } + + onResetFilterChanges(filter: KbqFilter | null) { + console.log('onResetFilterChanges: '); + const defaultFilter = this.getSavedFilter(filter); + + this.filters.splice( + this.filters.findIndex(({ name }) => name === filter?.name), + 1, + defaultFilter + ); + + this.activeFilter = defaultFilter; + } + + onDeleteFilter(filter: KbqFilter) { + const currentFilterIndex = this.filters.findIndex(({ name }) => name === filter?.name); + + this.filters.splice(currentFilterIndex, 1); + + this.activeFilter = null; + } + + onSaveFilter({ filter, filterBar }) { + console.log('filter to save: ', filter); + + this.filters.splice( + this.filters.findIndex(({ name }) => name === filter?.name), + 1, + filter + ); + + filterBar.filters.filterSavedSuccessfully(); + } + + onSaveAsNewFilter({ filter, filterBar }) { + if (filter) { + this.filters.push(filter); + } + + this.activeFilter = filter; + + filterBar.filters.filterSavedSuccessfully(); + } + + getSavedFilter(filter: KbqFilter | null): KbqFilter { + return structuredClone(this.savedFilters.find(({ name }) => name === filter?.name)!); + } + + getDefaultFilter(): KbqFilter { + return { + name: '', + readonly: false, + disabled: false, + changed: false, + saved: false, + pipes: [ + { + name: 'Datetime', + value: { name: 'Последние 24 часа', end: null, start: { hours: -24 } }, + type: KbqPipeTypes.Datetime, + + required: true, + cleanable: false, + removable: false, + disabled: false + } + ] + }; + } +} diff --git a/packages/docs-examples/components/filter-bar/index.ts b/packages/docs-examples/components/filter-bar/index.ts index ac1b89ff2..882e8eb61 100644 --- a/packages/docs-examples/components/filter-bar/index.ts +++ b/packages/docs-examples/components/filter-bar/index.ts @@ -8,6 +8,7 @@ import { FilterBarRemovableExample } from './filter-bar-removable/filter-bar-rem import { FilterBarRequiredExample } from './filter-bar-required/filter-bar-required-example'; import { FilterBarSavedFiltersExample } from './filter-bar-saved-filters/filter-bar-saved-filters-example'; import { FilterBarSearchExample } from './filter-bar-search/filter-bar-search-example'; +import { FilterBarUniqPipesExample } from './filter-bar-uniq-pipes/filter-bar-uniq-pipes-example'; export { FilterBarCleanableExample, @@ -18,7 +19,8 @@ export { FilterBarRemovableExample, FilterBarRequiredExample, FilterBarSavedFiltersExample, - FilterBarSearchExample + FilterBarSearchExample, + FilterBarUniqPipesExample }; const EXAMPLES = [ @@ -30,7 +32,8 @@ const EXAMPLES = [ FilterBarSearchExample, FilterBarCompleteFunctionsExample, FilterBarSavedFiltersExample, - FilterBarCustomPipeExample + FilterBarCustomPipeExample, + FilterBarUniqPipesExample ]; @NgModule({ diff --git a/packages/docs-examples/example-module.ts b/packages/docs-examples/example-module.ts index 0ae9770da..cd69da818 100644 --- a/packages/docs-examples/example-module.ts +++ b/packages/docs-examples/example-module.ts @@ -1502,6 +1502,18 @@ export const EXAMPLE_COMPONENTS: {[id: string]: LiveExample} = { "primaryFile": "filter-bar-search-example.ts", "importPath": "components/filter-bar" }, + "filter-bar-uniq-pipes": { + "packagePath": "components/filter-bar/filter-bar-uniq-pipes", + "title": "filter bar", + "componentName": "FilterBarUniqPipesExample", + "files": [ + "filter-bar-uniq-pipes-example.ts" + ], + "selector": "filter-bar-uniq-pipes-example", + "additionalComponents": [], + "primaryFile": "filter-bar-uniq-pipes-example.ts", + "importPath": "components/filter-bar" + }, "form-field-password-overview": { "packagePath": "components/form-field/form-field-password-overview", "title": "Form field password overview", @@ -4290,6 +4302,8 @@ return import('@koobiq/docs-examples/components/filter-bar'); case 'filter-bar-saved-filters': return import('@koobiq/docs-examples/components/filter-bar'); case 'filter-bar-search': +return import('@koobiq/docs-examples/components/filter-bar'); + case 'filter-bar-uniq-pipes': return import('@koobiq/docs-examples/components/filter-bar'); case 'form-field-password-overview': return import('@koobiq/docs-examples/components/form-field'); diff --git a/tools/public_api_guard/components/filter-bar.api.md b/tools/public_api_guard/components/filter-bar.api.md index 15c905571..9a886327a 100644 --- a/tools/public_api_guard/components/filter-bar.api.md +++ b/tools/public_api_guard/components/filter-bar.api.md @@ -37,6 +37,9 @@ import { UntypedFormControl } from '@angular/forms'; // @public export const defaultFilterBarPipes: [string, unknown][]; +// @public +export function getId(item: KbqPipeTemplate): KbqPipeType | string | number; + // @public export const KBQ_FILTER_BAR_CONFIGURATION: InjectionToken;