From 79664fa4efc59d53e21a7d5c7e0115793794c5dd Mon Sep 17 00:00:00 2001 From: Sobyt483 Date: Mon, 25 May 2026 12:47:02 +0400 Subject: [PATCH 1/5] feat: add tags display Signed-off-by: Sobyt483 --- docs/declarative-table.md | 3 +- docs/value-cell.md | 58 +++++++++- .../declarative-ui/models/ui-definition.ts | 13 ++- .../stories/declarative-table.stories.ts | 39 +++++++ .../ngx/declarative-ui/value-cell/index.ts | 1 + .../tag-list-value.component.html | 9 ++ .../tag-list-value.component.scss | 9 ++ .../tag-list-value.component.spec.ts | 106 ++++++++++++++++++ .../tag-list-value.component.ts | 16 +++ .../value-cell/value-cell.component.html | 6 + .../value-cell/value-cell.component.spec.ts | 72 ++++++++++++ .../value-cell/value-cell.component.ts | 15 ++- 12 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html create mode 100644 projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.scss create mode 100644 projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.spec.ts create mode 100644 projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.ts diff --git a/docs/declarative-table.md b/docs/declarative-table.md index a0d9509..93d89ff 100644 --- a/docs/declarative-table.md +++ b/docs/declarative-table.md @@ -1,6 +1,6 @@ # DeclarativeTable -A data table web component that renders rows and columns from a declarative column definition. Supports pagination, grouped columns, conditional cell styling, and multiple cell display modes (plain text, link, boolean icon, secret, tooltip, button, image). +A data table web component that renders rows and columns from a declarative column definition. Supports pagination, grouped columns, conditional cell styling, and multiple cell display modes (plain text, link, boolean icon, secret, tooltip, button, image, tag). ## Tags @@ -201,6 +201,7 @@ By default a cell renders its value as plain text. Use `uiSettings.displayAs` to | `'alert'` | Alert-styled text | | `'img'` | `` element using the value as `src` | | `'button'` | Action button (requires `buttonSettings`) | +| `'tag'` | One `` chip per value (split by `tagSettings.separator`, default `','`); also accepts an array of values | ### Copy button diff --git a/docs/value-cell.md b/docs/value-cell.md index 7b74c8e..29079f1 100644 --- a/docs/value-cell.md +++ b/docs/value-cell.md @@ -1,6 +1,6 @@ # ValueCell -A standalone cell renderer that displays a single field value from a resource object. Supports seven display modes (plain text, secret, boolean icon, link, tooltip, alert, image, button), conditional CSS rules, static CSS overrides, a copy-to-clipboard button, and a label badge mode. Used internally by `DeclarativeTable` and available for direct use in custom layouts. +A standalone cell renderer that displays a single field value from a resource object. Supports eight display modes (plain text, secret, boolean icon, link, tooltip, alert, image, button, tag), conditional CSS rules, static CSS overrides, a copy-to-clipboard button, and a label badge mode. Used internally by `DeclarativeTable` and available for direct use in custom layouts. ## Tags @@ -135,6 +135,7 @@ By default the cell renders its value as plain text. Use `uiSettings.displayAs` | `'alert'` | Critical alert icon when the value is falsy; empty otherwise | | `'img'` | `` element using the value as `src` | | `'button'` | Action button (requires `buttonSettings`) | +| `'tag'` | One `` chip per value (split by `tagSettings.separator`, default `','`); also accepts an array of values | ### Secret @@ -209,6 +210,36 @@ Renders a ``. A `buttonClick` event fires with `{ event, field, reso } ``` +### Tags + +Renders each value as a `` chip. String values are split by `tagSettings.separator` (default `','`); array values each become a separate chip. Empty segments are filtered out automatically. + +```ts +// Comma-separated string → three chips +{ + property: 'labels', + uiSettings: { displayAs: 'tag' }, + // resource value: 'api,backend,v2' +} + +// Custom separator +{ + property: 'environments', + uiSettings: { + displayAs: 'tag', + tagSettings: { design: 'Information', separator: '|' }, + }, + // resource value: 'prod|staging' +} + +// Array value +{ + property: 'tags', + uiSettings: { displayAs: 'tag' }, + // resource value: ['prod', 'staging'] +} +``` + --- ## Copy button @@ -262,7 +293,7 @@ uiSettings: { cssCustomization: { fontStyle: 'italic' } } ## Sub-components -`ValueCell` composes three internal components that are also exported from the public API and can be used independently. +`ValueCell` composes four internal components that are also exported from the public API and can be used independently. ### `BooleanValue` @@ -306,14 +337,29 @@ import { SecretValue } from '@openmfp/webcomponents'; The masked form renders `*` repeated to the same length as `value` (minimum 8 characters when the value is empty). +### `TagListValue` + +Renders an array of strings as `` chips in a wrapping flex container. + +```ts +import { TagListValue } from '@openmfp/webcomponents'; +``` + +| Input | Type | Required | Description | +| ------------ | ------------- | -------- | --------------------------------------------------------- | +| `tags` | `string[]` | yes | Each string becomes one chip | +| `tagSettings`| `TagSettings` | no | Controls chip `design` and `colorScheme` | +| `testId` | `string` | no | `test-id` attribute on the wrapper element (default `'tag-list-value'`) | + --- ## Types ```ts interface UiSettings { - displayAs?: 'secret' | 'boolIcon' | 'link' | 'tooltip' | 'alert' | 'img' | 'button'; + displayAs?: 'secret' | 'boolIcon' | 'link' | 'tooltip' | 'alert' | 'img' | 'button' | 'tag'; buttonSettings?: ButtonSettings; + tagSettings?: TagSettings; tooltipIcon?: string; withCopyButton?: boolean; labelDisplay?: boolean; @@ -323,6 +369,12 @@ interface UiSettings { align?: 'start' | 'center' | 'end'; } +interface TagSettings { + design?: 'Neutral' | 'Positive' | 'Critical' | 'Negative' | 'Information' | 'Set1' | 'Set2'; + colorScheme?: string; // '1'–'10' + separator?: string; // default ',' +} + interface ButtonSettings { text?: string; icon?: string; diff --git a/projects/ngx/declarative-ui/models/ui-definition.ts b/projects/ngx/declarative-ui/models/ui-definition.ts index 1c904e0..6953dd2 100644 --- a/projects/ngx/declarative-ui/models/ui-definition.ts +++ b/projects/ngx/declarative-ui/models/ui-definition.ts @@ -16,6 +16,14 @@ export interface PropertyField { transform?: TransformType[]; } +/** Appearance settings for tag chip rendering. */ +export interface TagSettings { + design?: 'Neutral' | 'Positive' | 'Critical' | 'Negative' | 'Information' | 'Set1' | 'Set2'; + colorScheme?: string; + /** Delimiter used to split a plain-string value into individual tags. Default: `','`. */ + separator?: string; +} + /** Display and interaction settings for a table cell. */ export interface UiSettings { /** When `true`, renders the cell value as a styled badge (blue pill). */ @@ -28,9 +36,12 @@ export interface UiSettings { | 'tooltip' | 'alert' | 'img' - | 'button'; + | 'button' + | 'tag'; /** Button appearance and action — only used when `displayAs` is `'button'`. */ buttonSettings?: ButtonSettings; + /** Tag chip configuration — only used when `displayAs` is `'tag'`. */ + tagSettings?: TagSettings; /** SAP UI5 icon name shown as the tooltip trigger icon. */ tooltipIcon?: string; /** When `true`, a copy-to-clipboard button is rendered next to the value. */ diff --git a/projects/ngx/declarative-ui/stories/declarative-table.stories.ts b/projects/ngx/declarative-ui/stories/declarative-table.stories.ts index 66d0883..107632e 100644 --- a/projects/ngx/declarative-ui/stories/declarative-table.stories.ts +++ b/projects/ngx/declarative-ui/stories/declarative-table.stories.ts @@ -379,6 +379,45 @@ export const ButtonCell: Story = { }, }; +/** + * `displayAs: 'tag'` renders comma-separated strings (or arrays) as `` chips. + * `tagSettings.separator` overrides the default `','` delimiter. + * `tagSettings.design` sets the chip colour scheme. + */ +export const Tags: Story = { + args: { + columns: [ + { label: 'Name', property: 'metadata.name' }, + { + label: 'Labels', + property: 'labels', + uiSettings: { displayAs: 'tag' }, + }, + { + label: 'Environments', + property: 'environments', + uiSettings: { + displayAs: 'tag', + tagSettings: { design: 'Information', separator: '|' }, + }, + }, + ] satisfies TableFieldDefinition[], + resources: [ + { + ...PODS[0], + labels: 'api,backend,v2', + environments: ['prod', 'staging'], + }, + { ...PODS[1], labels: 'worker', environments: 'dev' }, + { + ...PODS[2], + labels: 'cache,infra', + environments: 'prod|dev|staging', + }, + ], + }, +}; + /** Empty resources array triggers the illustrated empty-state message. */ export const EmptyState: Story = { args: { diff --git a/projects/ngx/declarative-ui/value-cell/index.ts b/projects/ngx/declarative-ui/value-cell/index.ts index 00de7da..41bc6be 100644 --- a/projects/ngx/declarative-ui/value-cell/index.ts +++ b/projects/ngx/declarative-ui/value-cell/index.ts @@ -2,3 +2,4 @@ export * from './value-cell.component'; export * from './boolean-value/boolean-value.component'; export * from './link-value/link-value.component'; export * from './secret-value/secret-value.component'; +export * from './tag-list-value/tag-list-value.component'; diff --git a/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html new file mode 100644 index 0000000..e6f2e5b --- /dev/null +++ b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html @@ -0,0 +1,9 @@ + + @for (tag of tags(); track tag) { + {{ tag }} + } + diff --git a/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.scss b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.scss new file mode 100644 index 0000000..8054245 --- /dev/null +++ b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.scss @@ -0,0 +1,9 @@ +:host { + display: inline-flex; +} + +.tag-list { + display: flex; + flex-wrap: wrap; + gap: 4px; +} diff --git a/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.spec.ts b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.spec.ts new file mode 100644 index 0000000..b0f970e --- /dev/null +++ b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.spec.ts @@ -0,0 +1,106 @@ +import { TagSettings } from '../../models'; +import { TagListValue } from './tag-list-value.component'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +describe('TagListValue', () => { + let fixture: ComponentFixture; + let component: TagListValue; + + function setup(tags: string[], tagSettings?: TagSettings) { + fixture = TestBed.createComponent(TagListValue); + component = fixture.componentInstance; + fixture.componentRef.setInput('tags', tags); + if (tagSettings !== undefined) { + fixture.componentRef.setInput('tagSettings', tagSettings); + } + fixture.detectChanges(); + return { fixture, component }; + } + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TagListValue], + }).overrideComponent(TagListValue, { + set: { + imports: [], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }, + }); + }); + + it('creates', () => { + const { component } = setup(['a']); + expect(component).toBeTruthy(); + }); + + describe('testId', () => { + it('defaults to "tag-list-value"', () => { + const { component } = setup(['x']); + expect(component.testId()).toBe('tag-list-value'); + }); + + it('accepts a custom testId', () => { + const { fixture } = setup(['x']); + fixture.componentRef.setInput('testId', 'my-tags'); + fixture.detectChanges(); + const span = fixture.nativeElement.querySelector('[test-id="my-tags"]'); + expect(span).not.toBeNull(); + }); + }); + + describe('tag rendering', () => { + it('renders one ui5-tag per item', () => { + const { fixture } = setup(['api', 'backend', 'v2']); + const tags = fixture.nativeElement.querySelectorAll('ui5-tag'); + expect(tags).toHaveLength(3); + }); + + it('renders no tags for empty array', () => { + const { fixture } = setup([]); + const tags = fixture.nativeElement.querySelectorAll('ui5-tag'); + expect(tags).toHaveLength(0); + }); + + it('renders tag text content', () => { + const { fixture } = setup(['prod', 'staging']); + const tags = fixture.nativeElement.querySelectorAll('ui5-tag'); + const texts = Array.from(tags).map((t) => + (t as Element).textContent?.trim(), + ); + expect(texts).toEqual(['prod', 'staging']); + }); + }); + + describe('tagSettings', () => { + it('passes design to ui5-tag', () => { + const { fixture } = setup(['x'], { design: 'Positive' }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tag = fixture.nativeElement.querySelector('ui5-tag') as any; + expect(tag?.design).toBe('Positive'); + }); + + it('defaults design to Neutral when tagSettings is absent', () => { + const { fixture } = setup(['x']); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tag = fixture.nativeElement.querySelector('ui5-tag') as any; + expect(tag?.design).toBe('Neutral'); + }); + + it('passes colorScheme to ui5-tag', () => { + const { fixture } = setup(['x'], { colorScheme: '5' }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tag = fixture.nativeElement.querySelector('ui5-tag') as any; + expect(tag?.colorScheme).toBe('5'); + }); + + it('hides state icon on all tags', () => { + const { fixture } = setup(['a', 'b']); + const tags = fixture.nativeElement.querySelectorAll('ui5-tag'); + Array.from(tags).forEach((tag) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((tag as any).hideStateIcon).toBe(true); + }); + }); + }); +}); diff --git a/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.ts b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.ts new file mode 100644 index 0000000..ada1408 --- /dev/null +++ b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.ts @@ -0,0 +1,16 @@ +import { TagSettings } from '../../models'; +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; +import { Tag } from '@fundamental-ngx/ui5-webcomponents/tag'; + +@Component({ + selector: 'mfp-tag-list-value', + imports: [Tag], + templateUrl: './tag-list-value.component.html', + styleUrl: './tag-list-value.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TagListValue { + tags = input.required(); + tagSettings = input(); + testId = input('tag-list-value'); +} diff --git a/projects/ngx/declarative-ui/value-cell/value-cell.component.html b/projects/ngx/declarative-ui/value-cell/value-cell.component.html index 4946213..462e360 100644 --- a/projects/ngx/declarative-ui/value-cell/value-cell.component.html +++ b/projects/ngx/declarative-ui/value-cell/value-cell.component.html @@ -44,6 +44,12 @@ (click)="buttonClicked($event)" >{{ buttonSettings?.text }}  + } @else if (displayType === 'tag') { + } @else { {{ value() }} } diff --git a/projects/ngx/declarative-ui/value-cell/value-cell.component.spec.ts b/projects/ngx/declarative-ui/value-cell/value-cell.component.spec.ts index 85ea763..c7ba441 100644 --- a/projects/ngx/declarative-ui/value-cell/value-cell.component.spec.ts +++ b/projects/ngx/declarative-ui/value-cell/value-cell.component.spec.ts @@ -313,4 +313,76 @@ describe('ValueCell', () => { expect(emitted[0].resource).toEqual(resource); }); }); + + describe('displayAs: tag', () => { + it('renders mfp-tag-list-value component', () => { + const { fixture } = setup( + { property: 'labels', uiSettings: { displayAs: 'tag' } }, + { labels: 'api,backend' }, + ); + expect(el(fixture, 'value-cell-labels-tags')).not.toBeNull(); + }); + + it('does not render plain text when displayAs is tag', () => { + const { fixture } = setup( + { property: 'labels', uiSettings: { displayAs: 'tag' } }, + { labels: 'api,backend' }, + ); + const span = q(fixture, '[test-id="value-cell-labels"]'); + expect(span?.textContent?.trim()).not.toBe('api,backend'); + }); + }); + + describe('normalizeTagsArray', () => { + it('splits comma-separated string into trimmed array', () => { + const { component } = setup( + { property: 'labels', uiSettings: { displayAs: 'tag' } }, + { labels: 'api, backend , v2' }, + ); + expect(component.tags()).toEqual(['api', 'backend', 'v2']); + }); + + it('uses custom separator from tagSettings', () => { + const { component } = setup( + { + property: 'envs', + uiSettings: { displayAs: 'tag', tagSettings: { separator: '|' } }, + }, + { envs: 'prod|staging|dev' }, + ); + expect(component.tags()).toEqual(['prod', 'staging', 'dev']); + }); + + it('filters out empty segments', () => { + const { component } = setup( + { property: 'labels', uiSettings: { displayAs: 'tag' } }, + { labels: 'api,,backend,' }, + ); + expect(component.tags()).toEqual(['api', 'backend']); + }); + + it('converts array values to string array', () => { + const { component } = setup( + { property: 'items', uiSettings: { displayAs: 'tag' } }, + { items: ['prod', 'staging'] }, + ); + expect(component.tags()).toEqual(['prod', 'staging']); + }); + + it('returns empty array for non-string non-array value', () => { + const { component } = setup( + { property: 'count', uiSettings: { displayAs: 'tag' } }, + { count: 42 }, + ); + expect(component.tags()).toEqual([]); + }); + + it('returns empty array when value is absent', () => { + const { component } = setup( + { property: 'missing', uiSettings: { displayAs: 'tag' } }, + {}, + ); + expect(component.tags()).toEqual([]); + }); + }); }); diff --git a/projects/ngx/declarative-ui/value-cell/value-cell.component.ts b/projects/ngx/declarative-ui/value-cell/value-cell.component.ts index 256535e..8dc2ab9 100644 --- a/projects/ngx/declarative-ui/value-cell/value-cell.component.ts +++ b/projects/ngx/declarative-ui/value-cell/value-cell.component.ts @@ -8,6 +8,7 @@ import { getFieldValue } from '../table/utils/field-definition.utils'; import { BooleanValue } from './boolean-value/boolean-value.component'; import { LinkValue } from './link-value/link-value.component'; import { SecretValue } from './secret-value/secret-value.component'; +import { TagListValue } from './tag-list-value/tag-list-value.component'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, @@ -24,7 +25,7 @@ import '@ui5/webcomponents-icons/dist/AllIcons.js'; @Component({ selector: 'mfp-value-cell', - imports: [Icon, BooleanValue, LinkValue, SecretValue, Button], + imports: [Icon, BooleanValue, LinkValue, SecretValue, Button, TagListValue], templateUrl: './value-cell.component.html', styleUrl: './value-cell.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, @@ -60,6 +61,7 @@ export class ValueCell { boolValue = computed(() => this.normalizeBoolean(this.value())); stringValue = computed(() => this.normalizeString(this.value())); + tags = computed(() => this.normalizeTagsArray(this.value())); isVisible = signal(false); toggleVisibility(e: Event): void { @@ -86,6 +88,17 @@ export class ValueCell { return value; } + private normalizeTagsArray(value: unknown): string[] { + if (Array.isArray(value)) { + return value.map(v => String(v).trim()).filter(v => v.length > 0); + } + if (typeof value === 'string') { + const separator = this.uiSettings()?.tagSettings?.separator ?? ','; + return value.split(separator).map(v => v.trim()).filter(v => v.length > 0); + } + return []; + } + private checkValidUrl(value: string | undefined): boolean { if (!value) { return false; From 475c7f58e0bcdd5775bf363a2b8be4232a28f867 Mon Sep 17 00:00:00 2001 From: Sobyt483 Date: Mon, 25 May 2026 13:03:44 +0400 Subject: [PATCH 2/5] feat: remove label display Signed-off-by: Sobyt483 --- docs/value-cell.md | 11 ----------- projects/ngx/declarative-ui/models/ui-definition.ts | 2 -- .../stories/declarative-table.stories.ts | 12 ++++++------ .../ngx/declarative-ui/stories/pods-table.config.ts | 4 ++-- .../declarative-table.component.html | 2 +- .../declarative-table.component.scss | 4 ++++ .../value-cell/value-cell.component.html | 2 +- .../value-cell/value-cell.component.scss | 13 ------------- .../value-cell/value-cell.component.ts | 1 - 9 files changed, 14 insertions(+), 37 deletions(-) diff --git a/docs/value-cell.md b/docs/value-cell.md index 29079f1..c36dfbb 100644 --- a/docs/value-cell.md +++ b/docs/value-cell.md @@ -254,16 +254,6 @@ The icon appears beside the rendered value. Clicking it writes the resolved valu --- -## Label badge - -Wrap the value in a styled blue badge pill: - -```ts -{ property: 'metadata.namespace', uiSettings: { labelDisplay: true } } -``` - ---- - ## Conditional cell styling (`cssRules`) Apply inline styles to the cell when its value meets a condition: @@ -362,7 +352,6 @@ interface UiSettings { tagSettings?: TagSettings; tooltipIcon?: string; withCopyButton?: boolean; - labelDisplay?: boolean; cssCustomization?: Partial; cssRules?: CssRule[]; columnWidth?: string; diff --git a/projects/ngx/declarative-ui/models/ui-definition.ts b/projects/ngx/declarative-ui/models/ui-definition.ts index 6953dd2..fd03ada 100644 --- a/projects/ngx/declarative-ui/models/ui-definition.ts +++ b/projects/ngx/declarative-ui/models/ui-definition.ts @@ -26,8 +26,6 @@ export interface TagSettings { /** Display and interaction settings for a table cell. */ export interface UiSettings { - /** When `true`, renders the cell value as a styled badge (blue pill). */ - labelDisplay?: boolean; /** How the cell value is rendered. Defaults to plain text when omitted. */ displayAs?: | 'secret' diff --git a/projects/ngx/declarative-ui/stories/declarative-table.stories.ts b/projects/ngx/declarative-ui/stories/declarative-table.stories.ts index 107632e..f471cbf 100644 --- a/projects/ngx/declarative-ui/stories/declarative-table.stories.ts +++ b/projects/ngx/declarative-ui/stories/declarative-table.stories.ts @@ -235,17 +235,17 @@ export const GroupedColumns: Story = { }; /** - * Group with a space delimiter and labelDisplay — values rendered as blue - * badge labels, separated by a single space. Also demonstrates the alert - * display type: a warning icon appears when the field value is falsy. + * Group with a space delimiter and tag display — values rendered as ui5-tag + * chips, separated by a single space. Also demonstrates the alert display + * type: a warning icon appears when the field value is falsy. */ -export const GroupedWithLabelsAndAlert: Story = { +export const GroupedWithTagsAndAlert: Story = { args: { columns: [ { label: 'Name', property: 'metadata.name' }, { property: 'spec.nodeName', - uiSettings: { labelDisplay: true }, + uiSettings: { displayAs: 'tag' }, group: { name: 'placement', label: 'Placement', @@ -255,7 +255,7 @@ export const GroupedWithLabelsAndAlert: Story = { }, { property: 'spec.image', - uiSettings: { labelDisplay: true }, + uiSettings: { displayAs: 'tag' }, group: { name: 'placement' }, }, { diff --git a/projects/ngx/declarative-ui/stories/pods-table.config.ts b/projects/ngx/declarative-ui/stories/pods-table.config.ts index c6402ee..3e43d4b 100644 --- a/projects/ngx/declarative-ui/stories/pods-table.config.ts +++ b/projects/ngx/declarative-ui/stories/pods-table.config.ts @@ -103,12 +103,12 @@ export const TABLE_COLUMNS: TableFieldDefinition[] = [ }, { property: 'spec.image', - uiSettings: { labelDisplay: true }, + uiSettings: { displayAs: 'tag' }, group: { name: 'placement', label: 'Placement', delimiter: ' ' }, }, { property: 'spec.nodeName', - uiSettings: { labelDisplay: true }, + uiSettings: { displayAs: 'tag' }, group: { name: 'placement' }, }, { diff --git a/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html b/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html index b5fa2f8..4187a13 100644 --- a/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html +++ b/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html @@ -64,7 +64,7 @@ /> @if (!last && column.group.delimiter) { - {{ column.group.delimiter }} + {{ column.group.delimiter }} } } diff --git a/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.scss b/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.scss index a962bd8..ba6ab0f 100644 --- a/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.scss +++ b/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.scss @@ -23,4 +23,8 @@ .flex { display: flex; width: 100%; +} + +.delimiter { + min-width: 4px; } \ No newline at end of file diff --git a/projects/ngx/declarative-ui/value-cell/value-cell.component.html b/projects/ngx/declarative-ui/value-cell/value-cell.component.html index 462e360..895e864 100644 --- a/projects/ngx/declarative-ui/value-cell/value-cell.component.html +++ b/projects/ngx/declarative-ui/value-cell/value-cell.component.html @@ -1,5 +1,5 @@ @let displayType = displayAs(); - + @if (displayType === 'secret') { diff --git a/projects/ngx/declarative-ui/value-cell/value-cell.component.scss b/projects/ngx/declarative-ui/value-cell/value-cell.component.scss index 61e556e..12dba3c 100644 --- a/projects/ngx/declarative-ui/value-cell/value-cell.component.scss +++ b/projects/ngx/declarative-ui/value-cell/value-cell.component.scss @@ -3,19 +3,6 @@ align-items: center; } -.label-value { - background-color: #01B4FF; - color: #ffffff; - border-radius: 1.4rem; - padding-inline: 0.4375rem; - letter-spacing: -0.00875rem; - display: inline-block; - border: 0; - font-size: 0.875rem; - line-height: 1.4rem; - margin: 3px 3px; -} - .secret-value-container { display: flex; align-items: center; diff --git a/projects/ngx/declarative-ui/value-cell/value-cell.component.ts b/projects/ngx/declarative-ui/value-cell/value-cell.component.ts index 8dc2ab9..f0807e0 100644 --- a/projects/ngx/declarative-ui/value-cell/value-cell.component.ts +++ b/projects/ngx/declarative-ui/value-cell/value-cell.component.ts @@ -44,7 +44,6 @@ export class ValueCell { uiSettings = computed(() => this.fieldDefinition().uiSettings); displayAs = computed(() => this.uiSettings()?.displayAs); withCopyButton = computed(() => this.uiSettings()?.withCopyButton); - labelDisplay = computed(() => this.uiSettings()?.labelDisplay); cssCustomization = computed(() => this.uiSettings()?.cssCustomization); tooltipIcon = computed(() => this.uiSettings()?.tooltipIcon); cssRules = computed(() => From cd2d55740ffb345263d4d767923e772518134080 Mon Sep 17 00:00:00 2001 From: Sobyt483 Date: Mon, 25 May 2026 13:53:21 +0400 Subject: [PATCH 3/5] fix: fix liner errors Signed-off-by: Sobyt483 --- .../table-card/declarative-table-card.component.html | 6 +++--- .../declarative-table/declarative-table.component.html | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/projects/ngx/declarative-ui/table-card/declarative-table-card.component.html b/projects/ngx/declarative-ui/table-card/declarative-table-card.component.html index ff9699e..c5ec708 100644 --- a/projects/ngx/declarative-ui/table-card/declarative-table-card.component.html +++ b/projects/ngx/declarative-ui/table-card/declarative-table-card.component.html @@ -53,16 +53,16 @@ @if (tableConfig(); as config) { } diff --git a/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html b/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html index 4187a13..c97b9b2 100644 --- a/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html +++ b/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html @@ -1,7 +1,7 @@ + [style.overflow-y]="'auto'"> @for (column of viewColumns(); track columnTrackBy(column, $index)) { @if (column.group) { @@ -35,9 +35,9 @@ @let isMultiline = column.group.multiline ?? true;
+ [style.flexDirection]="isMultiline ? 'column' : 'row'" + [style.justifyContent]="isMultiline ? null : column.uiSettings?.align"> @for ( field of column.group.fields; let last = $last; @@ -98,9 +98,9 @@ @if (hasMore()) { } From 2e7d393d6f19dbd21f4d876c1d28d96fc6fdd7ab Mon Sep 17 00:00:00 2001 From: Sobyt483 Date: Mon, 25 May 2026 14:01:17 +0400 Subject: [PATCH 4/5] feat: update docs Signed-off-by: Sobyt483 --- docs/value-cell.md | 4 ++-- projects/ngx/declarative-ui/models/ui-definition.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/value-cell.md b/docs/value-cell.md index c36dfbb..89bcd65 100644 --- a/docs/value-cell.md +++ b/docs/value-cell.md @@ -338,7 +338,7 @@ import { TagListValue } from '@openmfp/webcomponents'; | Input | Type | Required | Description | | ------------ | ------------- | -------- | --------------------------------------------------------- | | `tags` | `string[]` | yes | Each string becomes one chip | -| `tagSettings`| `TagSettings` | no | Controls chip `design` and `colorScheme` | +| `tagSettings`| `TagSettings` | no | Controls chip `design`, `colorScheme` (`'1'`–`'10'`, default `'1'`), and `separator` | | `testId` | `string` | no | `test-id` attribute on the wrapper element (default `'tag-list-value'`) | --- @@ -360,7 +360,7 @@ interface UiSettings { interface TagSettings { design?: 'Neutral' | 'Positive' | 'Critical' | 'Negative' | 'Information' | 'Set1' | 'Set2'; - colorScheme?: string; // '1'–'10' + colorScheme?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10'; // default '1' separator?: string; // default ',' } diff --git a/projects/ngx/declarative-ui/models/ui-definition.ts b/projects/ngx/declarative-ui/models/ui-definition.ts index fd03ada..0748892 100644 --- a/projects/ngx/declarative-ui/models/ui-definition.ts +++ b/projects/ngx/declarative-ui/models/ui-definition.ts @@ -19,7 +19,7 @@ export interface PropertyField { /** Appearance settings for tag chip rendering. */ export interface TagSettings { design?: 'Neutral' | 'Positive' | 'Critical' | 'Negative' | 'Information' | 'Set1' | 'Set2'; - colorScheme?: string; + colorScheme?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10'; /** Delimiter used to split a plain-string value into individual tags. Default: `','`. */ separator?: string; } From 833d134611bdfaff35149fb07b2e8c11b88da918 Mon Sep 17 00:00:00 2001 From: Sobyt483 Date: Mon, 25 May 2026 14:14:36 +0400 Subject: [PATCH 5/5] fix: fix trackBy Signed-off-by: Sobyt483 --- .../value-cell/tag-list-value/tag-list-value.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html index e6f2e5b..9d513fa 100644 --- a/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html +++ b/projects/ngx/declarative-ui/value-cell/tag-list-value/tag-list-value.component.html @@ -1,5 +1,5 @@ - @for (tag of tags(); track tag) { + @for (tag of tags(); track $index) {