Skip to content

Commit 7867fcd

Browse files
committed
feat: cell renderer for text with copy action
1 parent fe7a18e commit 7867fcd

File tree

5 files changed

+151
-3
lines changed

5 files changed

+151
-3
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
@import 'font';
2+
@import 'color-palette';
3+
4+
:host {
5+
.text {
6+
overflow: hidden;
7+
@include ellipsis-overflow();
8+
@include body-1-regular($gray-7);
9+
padding-right: 8px;
10+
}
11+
12+
.copy-button {
13+
visibility: hidden;
14+
}
15+
}
16+
17+
.text-with-copy-action-cell {
18+
display: flex;
19+
flex-direction: row;
20+
align-items: center;
21+
justify-content: space-between;
22+
23+
&.first-column {
24+
@include body-1-medium($gray-9);
25+
}
26+
27+
&:hover {
28+
.copy-button {
29+
visibility: visible;
30+
}
31+
}
32+
}
33+
34+
.clickable {
35+
@include link-hover();
36+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { FormattingModule } from '@hypertrace/common';
2+
import { ButtonSize, CopyToClipboardComponent } from '@hypertrace/components';
3+
import { byText, createComponentFactory } from '@ngneat/spectator/jest';
4+
import { MockComponent } from 'ng-mocks';
5+
import { TableCellStringParser } from '../../data-parsers/table-cell-string-parser';
6+
import { tableCellColumnProvider, tableCellDataProvider, tableCellProviders } from '../../test/cell-providers';
7+
import { TextWithCopyActionTableCellRendererComponent } from './text-with-copy-table-cell-renderer.component';
8+
9+
describe('Text with copy action table cell renderer component', () => {
10+
const buildComponent = createComponentFactory({
11+
component: TextWithCopyActionTableCellRendererComponent,
12+
imports: [FormattingModule],
13+
declarations: [MockComponent(CopyToClipboardComponent)],
14+
providers: [
15+
tableCellProviders(
16+
{
17+
id: 'test'
18+
},
19+
new TableCellStringParser(undefined!)
20+
)
21+
],
22+
shallow: true
23+
});
24+
25+
test('should render a plain string', () => {
26+
const spectator = buildComponent({
27+
providers: [tableCellDataProvider('test-text')]
28+
});
29+
30+
expect(spectator.query('.text')).toHaveText('test-text');
31+
});
32+
33+
test('should render a missing string', () => {
34+
const spectator = buildComponent();
35+
36+
expect(spectator.query('.text')).toHaveText('');
37+
});
38+
39+
test('should render the copy action button as expected', () => {
40+
const spectator = buildComponent({ providers: [tableCellDataProvider('test-text')] });
41+
expect(spectator.query('.copy-button')).toExist();
42+
expect(spectator.query(CopyToClipboardComponent)?.label).toBe('');
43+
expect(spectator.query(CopyToClipboardComponent)?.size).toBe(ButtonSize.ExtraSmall);
44+
expect(spectator.query(CopyToClipboardComponent)?.text).toBe('test-text');
45+
});
46+
47+
test('should not render the copy action button if string is empty', () => {
48+
const spectator = buildComponent({ providers: [tableCellDataProvider('')] });
49+
expect(spectator.query('.copy-button')).not.toExist();
50+
});
51+
52+
test('should add clickable class for clickable columns', () => {
53+
const spectator = buildComponent({
54+
providers: [
55+
tableCellDataProvider('test-text'),
56+
tableCellColumnProvider({
57+
id: 'test',
58+
onClick: () => {
59+
/* NOOP */
60+
}
61+
})
62+
]
63+
});
64+
65+
expect(spectator.query('.text-with-copy-action-cell')).toHaveClass('clickable');
66+
});
67+
68+
test('should not add clickable class for columns without a click handler', () => {
69+
const spectator = buildComponent({
70+
providers: [tableCellDataProvider('test-text')]
71+
});
72+
73+
expect(spectator.query(byText('test-text'))).not.toHaveClass('clickable');
74+
});
75+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { ButtonSize } from '../../../../button/button';
3+
import { TableCellRenderer } from '../../table-cell-renderer';
4+
import { TableCellRendererBase } from '../../table-cell-renderer-base';
5+
import { CoreTableCellParserType } from '../../types/core-table-cell-parser-type';
6+
import { CoreTableCellRendererType } from '../../types/core-table-cell-renderer-type';
7+
import { TableCellAlignmentType } from '../../types/table-cell-alignment-type';
8+
9+
@Component({
10+
selector: 'ht-text-table-with-copy-cell-renderer',
11+
styleUrls: ['./text-with-copy-table-cell-renderer.component.scss'],
12+
changeDetection: ChangeDetectionStrategy.OnPush,
13+
template: `
14+
<div
15+
[ngClass]="{ clickable: this.clickable, 'first-column': this.isFirstColumn }"
16+
class="text-with-copy-action-cell"
17+
>
18+
<span class="text" [htTooltip]="this.value">{{ this.value | htDisplayString }}</span>
19+
20+
<div class="copy-button" *ngIf="this.value !== ''">
21+
<ht-copy-to-clipboard size="${ButtonSize.ExtraSmall}" label="" [text]="this.value"></ht-copy-to-clipboard>
22+
</div>
23+
</div>
24+
`
25+
})
26+
@TableCellRenderer({
27+
type: CoreTableCellRendererType.TextWithCopyAction,
28+
alignment: TableCellAlignmentType.Left,
29+
parser: CoreTableCellParserType.String
30+
})
31+
export class TextWithCopyActionTableCellRendererComponent extends TableCellRendererBase<string> {}

projects/components/src/table/cells/table-cells.module.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
33
import { Inject, InjectionToken, NgModule } from '@angular/core';
44
import { FormattingModule } from '@hypertrace/common';
55
import { TraceCheckboxModule } from '../../checkbox/checkbox.module';
6+
import { CopyToClipboardModule } from '../../copy-to-clipboard/copy-to-clipboard.module';
67
import { ExpanderToggleModule } from '../../expander/expander-toggle.module';
78
import { FilterButtonModule } from '../../filtering/filter-button/filter-button.module';
89
import { FilterModalModule } from '../../filtering/filter-modal/filter-modal.module';
@@ -21,6 +22,7 @@ import { IconTableCellRendererComponent } from './data-renderers/icon/icon-table
2122
import { NumericTableCellRendererComponent } from './data-renderers/numeric/numeric-table-cell-renderer.component';
2223
import { StringArrayTableCellRendererComponent } from './data-renderers/string-array/string-array-table-cell-renderer.component';
2324
import { TableDataCellRendererComponent } from './data-renderers/table-data-cell-renderer.component';
25+
import { TextWithCopyActionTableCellRendererComponent } from './data-renderers/text-with-copy/text-with-copy-table-cell-renderer.component';
2426
import { TextTableCellRendererComponent } from './data-renderers/text/text-table-cell-renderer.component';
2527
import { TimeAgoTableCellRendererComponent } from './data-renderers/time-ago/time-ago-table-cell-renderer.component';
2628
import { TimestampTableCellRendererComponent } from './data-renderers/timestamp/timestamp-table-cell-renderer.component';
@@ -47,7 +49,8 @@ export const TABLE_CELL_PARSERS = new InjectionToken<unknown[][]>('TABLE_CELL_PA
4749
TraceCheckboxModule,
4850
FilterButtonModule,
4951
FilterModalModule,
50-
PopoverModule
52+
PopoverModule,
53+
CopyToClipboardModule
5154
],
5255
exports: [
5356
TableHeaderCellRendererComponent,
@@ -66,7 +69,8 @@ export const TABLE_CELL_PARSERS = new InjectionToken<unknown[][]>('TABLE_CELL_PA
6669
TimestampTableCellRendererComponent,
6770
TimeAgoTableCellRendererComponent,
6871
CodeTableCellRendererComponent,
69-
StringArrayTableCellRendererComponent
72+
StringArrayTableCellRendererComponent,
73+
TextWithCopyActionTableCellRendererComponent
7074
],
7175
providers: [
7276
{
@@ -80,7 +84,8 @@ export const TABLE_CELL_PARSERS = new InjectionToken<unknown[][]>('TABLE_CELL_PA
8084
TimestampTableCellRendererComponent,
8185
TimeAgoTableCellRendererComponent,
8286
CodeTableCellRendererComponent,
83-
StringArrayTableCellRendererComponent
87+
StringArrayTableCellRendererComponent,
88+
TextWithCopyActionTableCellRendererComponent
8489
],
8590
multi: true
8691
},

projects/components/src/table/cells/types/core-table-cell-renderer-type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const enum CoreTableCellRendererType {
66
RowExpander = 'row-expander',
77
StringArray = 'string-array',
88
Text = 'text',
9+
TextWithCopyAction = 'text-with-copy-action',
910
Timestamp = 'timestamp',
1011
TimeAgo = 'time-ago'
1112
}

0 commit comments

Comments
 (0)