Skip to content

Commit 38924fb

Browse files
committed
Merge branch 'feature/state-of-the-art' into feature/path-prompt
# Conflicts: # libs/schematic/generators/ng-generate/components/table/generators/components/table-cell-link/index.ts # libs/schematic/generators/ng-generate/components/table/index.ts
2 parents cb0dac4 + 8de1cd8 commit 38924fb

File tree

15 files changed

+398
-142
lines changed

15 files changed

+398
-142
lines changed

libs/schematic/generators/ng-generate/components/table/generators/components/table-cell-link/files/__name@dasherize__.component.ts.template

Lines changed: 0 additions & 27 deletions
This file was deleted.

libs/schematic/generators/ng-generate/components/table/generators/components/table-cell-link/index.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

libs/schematic/generators/ng-generate/components/table/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {generateConfigMenu} from './generators/components/config-menu/index';
3434
import {generateTableComponent} from './generators/components/table/index';
3535
import {generateDataSource} from './generators/data-source/index';
3636
import {TableSchema} from './schema';
37-
import {generateTableCellLinkComponent} from './generators/components/table-cell-link/index';
3837
import {LOG_COLOR} from '../../../utils/constants';
3938

4039
export default function (tableSchema: TableSchema): Rule {
@@ -66,7 +65,6 @@ export function generateTable(tableSchema: TableSchema): Rule {
6665
function tableSpecificGeneration(): Array<Rule> {
6766
return [
6867
generateTableComponent(options as TableSchema),
69-
generateTableCellLinkComponent(options), // General
7068
generateDataSource(options),
7169
generateStorageService(options), // General
7270
generateColumnMenu(options), // General

libs/schematic/generators/utils/modules.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const tableModules = (options: Schema) => [
8484
{name: 'DragDropModule', fromLib: '@angular/cdk/drag-drop'},
8585
{name: 'NgTemplateOutlet', fromLib: '@angular/common'},
8686
{name: 'DatePipe', fromLib: '@angular/common'},
87-
{name: 'EsmfTableCellLinkComponent', fromLib: '../../table-cell-link/esmf-table-cell-link.component'},
87+
{name: 'TableCellLinkComponent', fromLib: '../../src/lib/components/table-cell-link/table-cell-link.component'},
8888
{
8989
name: 'MatCheckboxModule',
9090
fromLib: '@angular/material/checkbox',

libs/schematic/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
export * from './lib/table-cell/table-cell';

libs/schematic/generators/ng-generate/components/table/generators/components/table-cell-link/files/__name@dasherize__.component.html.template renamed to libs/schematic/src/lib/components/table-cell-link/table-cell-link.component.html

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
<!-- <%= options.generationDisclaimerText %> -->
2-
31
<button
42
[matTooltipDisabled]="!isDisabled()"
53
[class.button-disabled]="isDisabled()"
@@ -10,4 +8,4 @@
108
aria-label="link row"
119
>
1210
<mat-icon class="material-icons">open_in_new</mat-icon>
13-
</button>
11+
</button>

libs/schematic/generators/ng-generate/components/table/generators/components/table-cell-link/files/__name@dasherize__.component.scss.template renamed to libs/schematic/src/lib/components/table-cell-link/table-cell-link.component.scss

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/** <%= options.generationDisclaimerText %> **/
2-
31
button {
42
background-color: transparent;
53
border: none;
@@ -13,4 +11,4 @@ button {
1311
.button-disabled {
1412
cursor: not-allowed;
1513
opacity: 0.4;
16-
}
14+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import {ComponentFixture, TestBed} from '@angular/core/testing';
2+
import {TableCellLinkComponent} from './table-cell-link.component';
3+
import {By} from '@angular/platform-browser';
4+
import {ComponentRef} from '@angular/core';
5+
6+
describe('TableCellLinkComponent', () => {
7+
let component: TableCellLinkComponent;
8+
let fixture: ComponentFixture<TableCellLinkComponent>;
9+
let componentRef: ComponentRef<TableCellLinkComponent>;
10+
let windowOpenSpy: jest.SpyInstance;
11+
12+
const DISABLED_VALUE = '-';
13+
const VALID_URL = 'https://example.com';
14+
const ALTERNATIVE_URL = 'https://newsite.com';
15+
const TOOLTIP_MESSAGE = 'Open link';
16+
const NO_LINK_MESSAGE = 'No link';
17+
18+
beforeEach(async () => {
19+
await TestBed.configureTestingModule({
20+
imports: [TableCellLinkComponent],
21+
}).compileComponents();
22+
23+
fixture = TestBed.createComponent(TableCellLinkComponent);
24+
component = fixture.componentInstance;
25+
componentRef = fixture.componentRef;
26+
windowOpenSpy = jest.spyOn(window, 'open').mockImplementation();
27+
});
28+
29+
afterEach(() => {
30+
windowOpenSpy.mockRestore();
31+
});
32+
33+
describe('isDisabled computed signal', () => {
34+
it('should return true only when value is "-"', () => {
35+
componentRef.setInput('value', DISABLED_VALUE);
36+
componentRef.setInput('tooltipMessage', NO_LINK_MESSAGE);
37+
fixture.detectChanges();
38+
39+
expect(component.isDisabled()).toBe(true);
40+
});
41+
42+
it('should return false for any other value', () => {
43+
const testValues = [VALID_URL, '', 'some-text'];
44+
45+
testValues.forEach(value => {
46+
componentRef.setInput('value', value);
47+
componentRef.setInput('tooltipMessage', TOOLTIP_MESSAGE);
48+
fixture.detectChanges();
49+
50+
expect(component.isDisabled()).toBe(false);
51+
});
52+
});
53+
});
54+
55+
describe('openExternalLink', () => {
56+
it('should open link in new tab when enabled', () => {
57+
componentRef.setInput('value', VALID_URL);
58+
componentRef.setInput('tooltipMessage', TOOLTIP_MESSAGE);
59+
fixture.detectChanges();
60+
61+
component.openExternalLink();
62+
63+
expect(windowOpenSpy).toHaveBeenCalledWith(VALID_URL, '_blank');
64+
});
65+
66+
it('should not open link when disabled', () => {
67+
componentRef.setInput('value', DISABLED_VALUE);
68+
componentRef.setInput('tooltipMessage', NO_LINK_MESSAGE);
69+
fixture.detectChanges();
70+
71+
component.openExternalLink();
72+
73+
expect(windowOpenSpy).not.toHaveBeenCalled();
74+
});
75+
});
76+
77+
describe('UI rendering', () => {
78+
beforeEach(() => {
79+
componentRef.setInput('value', VALID_URL);
80+
componentRef.setInput('tooltipMessage', TOOLTIP_MESSAGE);
81+
fixture.detectChanges();
82+
});
83+
84+
it('should render button with icon', () => {
85+
const button = fixture.debugElement.query(By.css('button[mat-icon-button]'));
86+
const icon = fixture.debugElement.query(By.css('mat-icon'));
87+
88+
expect(button).toBeTruthy();
89+
expect(button.nativeElement.getAttribute('aria-label')).toBe('link row');
90+
expect(icon.nativeElement.textContent.trim()).toBe('open_in_new');
91+
});
92+
93+
it('should apply disabled class based on isDisabled state', () => {
94+
const button = fixture.debugElement.query(By.css('button'));
95+
expect(button.nativeElement.classList.contains('button-disabled')).toBe(false);
96+
97+
componentRef.setInput('value', DISABLED_VALUE);
98+
fixture.detectChanges();
99+
100+
expect(button.nativeElement.classList.contains('button-disabled')).toBe(true);
101+
});
102+
});
103+
104+
describe('UI interactions', () => {
105+
it('should open window when button is clicked and enabled', () => {
106+
componentRef.setInput('value', VALID_URL);
107+
componentRef.setInput('tooltipMessage', TOOLTIP_MESSAGE);
108+
fixture.detectChanges();
109+
110+
const button = fixture.debugElement.query(By.css('button'));
111+
button.nativeElement.click();
112+
113+
expect(windowOpenSpy).toHaveBeenCalledWith(VALID_URL, '_blank');
114+
});
115+
116+
it('should not open window when button is clicked and disabled', () => {
117+
componentRef.setInput('value', DISABLED_VALUE);
118+
componentRef.setInput('tooltipMessage', NO_LINK_MESSAGE);
119+
fixture.detectChanges();
120+
121+
const button = fixture.debugElement.query(By.css('button'));
122+
button.nativeElement.click();
123+
124+
expect(windowOpenSpy).not.toHaveBeenCalled();
125+
});
126+
});
127+
128+
describe('Dynamic input changes', () => {
129+
it('should update disabled state when value changes', () => {
130+
componentRef.setInput('value', VALID_URL);
131+
componentRef.setInput('tooltipMessage', TOOLTIP_MESSAGE);
132+
fixture.detectChanges();
133+
134+
expect(component.isDisabled()).toBe(false);
135+
136+
componentRef.setInput('value', DISABLED_VALUE);
137+
fixture.detectChanges();
138+
139+
expect(component.isDisabled()).toBe(true);
140+
});
141+
142+
it('should open new URL when value changes', () => {
143+
componentRef.setInput('value', VALID_URL);
144+
componentRef.setInput('tooltipMessage', TOOLTIP_MESSAGE);
145+
fixture.detectChanges();
146+
147+
const button = fixture.debugElement.query(By.css('button'));
148+
button.nativeElement.click();
149+
150+
expect(windowOpenSpy).toHaveBeenCalledWith(VALID_URL, '_blank');
151+
152+
componentRef.setInput('value', ALTERNATIVE_URL);
153+
fixture.detectChanges();
154+
155+
button.nativeElement.click();
156+
157+
expect(windowOpenSpy).toHaveBeenCalledWith(ALTERNATIVE_URL, '_blank');
158+
});
159+
});
160+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/** <%= options.generationDisclaimerText %> **/
2+
3+
import {ChangeDetectionStrategy, Component, computed, input} from '@angular/core';
4+
import {MatTooltipModule} from '@angular/material/tooltip';
5+
import {MatIconModule} from '@angular/material/icon';
6+
import {MatIconButton} from '@angular/material/button';
7+
8+
@Component({
9+
selector: 'esmf-table-cell-link',
10+
templateUrl: './table-cell-link.component.html',
11+
styleUrls: ['./table-cell-link.component.scss'],
12+
changeDetection: ChangeDetectionStrategy.OnPush,
13+
imports: [MatTooltipModule, MatIconModule, MatIconButton],
14+
})
15+
export class TableCellLinkComponent {
16+
value = input.required<string>();
17+
tooltipMessage = input.required<string>();
18+
19+
isDisabled = computed(() => this.value() === '-');
20+
21+
openExternalLink() {
22+
if (this.isDisabled()) return;
23+
window.open(this.value(), '_blank');
24+
}
25+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@let val = value();
2+
3+
<div
4+
class="cell-content"
5+
esmfHighlight
6+
esmfTableCellTooltip
7+
[highlight]="highlightString()"
8+
[highlightSource]="val"
9+
[highlightColor]="color()"
10+
[selected]="selected()"
11+
[value]="val"
12+
[description]="description()"
13+
>
14+
{{ val === null ? '-' : val }}
15+
</div>
16+
17+
@if (hasValue()) {
18+
<div>
19+
<mat-icon
20+
class="material-icons copy-to-clipboard"
21+
data-test="copy-to-clipboard-icon"
22+
(click)="copyToClipboard(val, $event)"
23+
>
24+
content_copy
25+
</mat-icon>
26+
</div>
27+
}

0 commit comments

Comments
 (0)