mirror of
https://github.com/Ride-The-Lightning/RTL.git
synced 2026-08-13 12:33:07 +02:00
Fix CLN channel View Info modal blanking for disconnected channels (#1606)
The channel information modal renders a block-explorer link from selNode.settings.blockExplorerUrl, but the pending/inactive channels table opened the modal without passing selNode. With it undefined, that binding threw during change detection and blanked every field below it — State, Connected, Private and the balances all rendered without a value. A disconnected channel moves to the pending/inactive table, so this is what surfaced on View Info for a disconnected channel (the symptom in the original report). Pass selNode from the pending table (matching the open table), and guard the modal's explorer link (*ngIf + a no-op click when the url is absent) so a missing selNode can no longer blank the whole dialog. Add a regression test asserting the pending table passes selNode when opening the modal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b790dc7abf
commit
c15fa04986
5 changed files with 35 additions and 2 deletions
|
|
@ -16,6 +16,17 @@ this release should add its entry under the appropriate section below.
|
|||
sync, and the list columns read `peer_connected` directly. Regression tests were added for
|
||||
both channel tables.
|
||||
|
||||
- **Core Lightning: fix the channel View Info modal rendering blank for disconnected channels**
|
||||
([#1625](https://github.com/Ride-The-Lightning/RTL/pull/1625), fixes
|
||||
[#1606](https://github.com/Ride-The-Lightning/RTL/issues/1606)).
|
||||
The channel information modal renders a block-explorer link from `selNode.settings.blockExplorerUrl`,
|
||||
but the pending/inactive channels table opened the modal without passing `selNode`. With it
|
||||
undefined, that binding threw during change detection and blanked every field below it — State,
|
||||
Connected, Private and the balances all showed no value. Because a disconnected channel moves to
|
||||
the pending/inactive table, this is exactly what was seen on "View Info" for a disconnected
|
||||
channel. The pending table now passes `selNode` (matching the open table), and the modal guards
|
||||
the explorer link so a missing `selNode` can no longer blank the dialog.
|
||||
|
||||
## Developer Tooling
|
||||
|
||||
- **Added a Core Lightning node to the regtest docker fixture**
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
<h4 fxLayoutAlign="start" class="font-bold-500">Funding Transaction ID</h4>
|
||||
<span class="foreground-secondary-text">
|
||||
{{channel.funding_txid}}
|
||||
<fa-icon matTooltip="{{'Link to ' + selNode.settings.blockExplorerUrl}}" class="ml-1 fa-icon-primary" [icon]="faUpRightFromSquare" (click)="onExplorerClicked()"/>
|
||||
<fa-icon *ngIf="selNode?.settings?.blockExplorerUrl" matTooltip="{{'Link to ' + selNode?.settings?.blockExplorerUrl}}" class="ml-1 fa-icon-primary" [icon]="faUpRightFromSquare" (click)="onExplorerClicked()"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ export class CLNChannelInformationComponent implements OnInit {
|
|||
}
|
||||
|
||||
onExplorerClicked() {
|
||||
if (!this.selNode?.settings?.blockExplorerUrl) { return; }
|
||||
window.open(this.selNode.settings.blockExplorerUrl + '/tx/' + this.channel.funding_txid, '_blank');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { Store, StoreModule } from '@ngrx/store';
|
||||
|
||||
import { RootReducer } from '../../../../../store/rtl.reducers';
|
||||
import { LNDReducer } from '../../../../../lnd/store/lnd.reducers';
|
||||
|
|
@ -73,6 +73,20 @@ describe('CLNChannelPendingTableComponent', () => {
|
|||
expect(connectedCellText()).toBe('Disconnected');
|
||||
});
|
||||
|
||||
// Issue #1606: the channel information modal reads selNode.settings.blockExplorerUrl, so the
|
||||
// pending table must pass selNode when opening it. Without it the modal throws mid-render and
|
||||
// blanks State/Connected/balances for disconnected channels (which live in this table).
|
||||
it('should pass selNode when opening the channel information modal', () => {
|
||||
const store = TestBed.inject(Store);
|
||||
const dispatchSpy = spyOn(store, 'dispatch');
|
||||
const selNode: any = { settings: { blockExplorerUrl: 'https://mempool.space' } };
|
||||
component.selNode = selNode;
|
||||
component.onChannelClick({ short_channel_id: '120x1x0', peer_connected: false } as any, {} as any);
|
||||
expect(dispatchSpy).toHaveBeenCalled();
|
||||
const action: any = dispatchSpy.calls.mostRecent().args[0];
|
||||
expect(action.payload.data.selNode).toBe(selNode);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
TestBed.resetTestingModule();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { openAlert, openConfirmation } from '../../../../../store/rtl.actions';
|
|||
import { RTLState } from '../../../../../store/rtl.state';
|
||||
import { closeChannel } from '../../../../store/cln.actions';
|
||||
import { channels, clnPageSettings, nodeInfoAndBalanceAndNumPeers } from '../../../../store/cln.selector';
|
||||
import { rootSelectedNode } from '../../../../../store/rtl.selector';
|
||||
import { ColumnDefinition, PageSettings, TableSetting } from '../../../../../shared/models/pageSettings';
|
||||
import { CamelCaseWithReplacePipe } from '../../../../../shared/pipes/app.pipe';
|
||||
import { MAT_SELECT_CONFIG } from '@angular/material/select';
|
||||
|
|
@ -62,6 +63,7 @@ export class CLNChannelPendingTableComponent implements OnInit, AfterViewInit, O
|
|||
public errorMessage = '';
|
||||
public apiCallStatus: ApiCallStatusPayload | null = null;
|
||||
public apiCallStatusEnum = APICallStatusEnum;
|
||||
public selNode: Node | null = null;
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(private logger: LoggerService, private store: Store<RTLState>, private rtlEffects: RTLEffects, private commonService: CommonService, private camelCaseWithReplace: CamelCaseWithReplacePipe) {
|
||||
|
|
@ -109,6 +111,10 @@ export class CLNChannelPendingTableComponent implements OnInit, AfterViewInit, O
|
|||
}
|
||||
this.logger.info(channelsSeletor);
|
||||
});
|
||||
this.store.select(rootSelectedNode).pipe(takeUntil(this.unSubs[4])).
|
||||
subscribe((nodeSettings) => {
|
||||
this.selNode = nodeSettings;
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
|
@ -133,6 +139,7 @@ export class CLNChannelPendingTableComponent implements OnInit, AfterViewInit, O
|
|||
payload: {
|
||||
data: {
|
||||
channel: selChannel,
|
||||
selNode: this.selNode,
|
||||
showCopy: true,
|
||||
component: CLNChannelInformationComponent
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue