Merge pull request #1314 from Ride-The-Lightning/Release-0.14.1

Release 0.14.1
pull/1315/head v0.14.1
ShahanaFarooqui 7 months ago committed by GitHub
commit d083be1196
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,7 +1,7 @@
{ {
"root": true, "root": true,
"ignorePatterns": [ "ignorePatterns": [
"src/**/*.js" "backend/**/*.js"
], ],
"overrides": [ "overrides": [
{ {
@ -20,17 +20,18 @@
"extends": [ "extends": [
"plugin:@angular-eslint/all", "plugin:@angular-eslint/all",
"plugin:@angular-eslint/recommended", "plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/recommended--extra" "plugin:@angular-eslint/template/process-inline-templates"
], ],
"rules": { "rules": {
"deprecation/deprecation": "error", "deprecation/deprecation": "error",
"@angular-eslint/prefer-on-push-component-change-detection": "off", "@angular-eslint/prefer-on-push-component-change-detection": "off",
"@angular-eslint/prefer-standalone-component": "off",
"@angular-eslint/sort-ngmodule-metadata-arrays": "off", "@angular-eslint/sort-ngmodule-metadata-arrays": "off",
"@angular-eslint/use-component-view-encapsulation": "off", "@angular-eslint/use-component-view-encapsulation": "off",
"@angular-eslint/use-injectable-provided-in": "off", "@angular-eslint/use-injectable-provided-in": "off",
"@typescript-eslint/member-delimiter-style": ["error", { "multiline": { "delimiter": "semi", "requireLast": true}, "singleline": { "delimiter": "comma", "requireLast": false }}], "@typescript-eslint/member-delimiter-style": "off",
"@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/type-annotation-spacing": "error", "@typescript-eslint/type-annotation-spacing": 0,
"quotes": ["error", "single"], "quotes": ["error", "single"],
"comma-dangle": ["error", "never"], "comma-dangle": ["error", "never"],
"comma-spacing": ["error", { "before": false, "after": true }], "comma-spacing": ["error", { "before": false, "after": true }],
@ -124,7 +125,7 @@
"indent": ["error", 2, { "SwitchCase": 1, "MemberExpression": 1, "ArrayExpression": "off" }], "indent": ["error", 2, { "SwitchCase": 1, "MemberExpression": 1, "ArrayExpression": "off" }],
"keyword-spacing": ["error", { "before": true, "after": true, "overrides": { "this": { "before": false }}}], "keyword-spacing": ["error", { "before": true, "after": true, "overrides": { "this": { "before": false }}}],
"lines-around-comment": "error", "lines-around-comment": "error",
"max-depth": ["error", { "max": 6 }], "max-depth": ["error", { "max": 7 }],
"max-nested-callbacks": "error", "max-nested-callbacks": "error",
"max-statements-per-line": ["error", { "max": 3 }], "max-statements-per-line": ["error", { "max": 3 }],
"no-array-constructor": "error", "no-array-constructor": "error",
@ -196,12 +197,14 @@
"@angular-eslint/template/click-events-have-key-events": "off", "@angular-eslint/template/click-events-have-key-events": "off",
"@angular-eslint/template/conditional-complexity": "off", "@angular-eslint/template/conditional-complexity": "off",
"@angular-eslint/template/cyclomatic-complexity": "off", "@angular-eslint/template/cyclomatic-complexity": "off",
"@angular-eslint/template/elements-content": "off",
"@angular-eslint/template/i18n": "off", "@angular-eslint/template/i18n": "off",
"@angular-eslint/template/no-autofocus": "off", "@angular-eslint/template/no-autofocus": "off",
"@angular-eslint/template/no-call-expression": "off", "@angular-eslint/template/no-call-expression": "off",
"@angular-eslint/template/no-inline-styles": "off", "@angular-eslint/template/no-inline-styles": "off",
"@angular-eslint/template/no-interpolation-in-attributes": "off", "@angular-eslint/template/no-interpolation-in-attributes": "off",
"@angular-eslint/template/no-positive-tabindex": "off", "@angular-eslint/template/no-positive-tabindex": "off",
"@angular-eslint/template/prefer-ngsrc": "off",
"@angular-eslint/template/use-track-by-function": "off" "@angular-eslint/template/use-track-by-function": "off"
} }
} }

@ -40,7 +40,7 @@ export const listChannels = (req, res, next) => {
request(options).then((body) => { request(options).then((body) => {
body?.map((channel) => { body?.map((channel) => {
if (!channel.alias || channel.alias === '') { if (!channel.alias || channel.alias === '') {
channel.alias = channel.id.substring(0, 20); channel.alias = channel.channel_id.substring(0, 20);
} }
const local = channel.to_us_msat || 0; const local = channel.to_us_msat || 0;
const remote = (channel.total_msat - local) || 0; const remote = (channel.total_msat - local) || 0;

@ -62,7 +62,6 @@ export const getInfo = (req, res, next) => {
req.session.selectedNode.ln_version = body.version || ''; req.session.selectedNode.ln_version = body.version || '';
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' });
clWsClient.updateSelectedNode(req.session.selectedNode); clWsClient.updateSelectedNode(req.session.selectedNode);
databaseService.loadDatabase(req.session);
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
return res.status(200).json(body); return res.status(200).json(body);
} }

@ -16,14 +16,12 @@ export const simplifyAllChannels = (selNode, channels) => {
nodeId: channel.nodeId ? channel.nodeId : '', nodeId: channel.nodeId ? channel.nodeId : '',
channelId: channel.channelId ? channel.channelId : '', channelId: channel.channelId ? channel.channelId : '',
state: channel.state ? channel.state : '', state: channel.state ? channel.state : '',
announceChannel: channel.data && channel.data.commitments && channel.data.commitments.channelFlags && channel.data.commitments.channelFlags.announceChannel ? channel.data.commitments.channelFlags.announceChannel : false, announceChannel: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.channelFlags && channel.data.commitments.params.channelFlags.announceChannel ? channel.data.commitments.params.channelFlags.announceChannel : false,
toLocal: (channel.data.commitments.localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.localCommit.spec.toLocal / 1000) : 0, toLocal: (channel.data.commitments.active[0].localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toLocal / 1000) : 0,
toRemote: (channel.data.commitments.localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.localCommit.spec.toRemote / 1000) : 0, toRemote: (channel.data.commitments.active[0].localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toRemote / 1000) : 0,
shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '', shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '',
isFunder: channel.data && channel.data.commitments && channel.data.commitments.localParams && channel.data.commitments.localParams.isFunder ? channel.data.commitments.localParams.isFunder : false, isInitiator: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.localParams && channel.data.commitments.params.localParams.isInitiator ? channel.data.commitments.params.localParams.isInitiator : false,
buried: channel.data && channel.data.buried ? channel.data.buried : false,
feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0, feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0,
feeRatePerKw: (channel.data.commitments.localCommit.spec.feeratePerKw) ? channel.data.commitments.localCommit.spec.feeratePerKw : 0,
feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0, feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0,
alias: '' alias: ''
}); });
@ -159,7 +157,6 @@ export const closeChannel = (req, res, next) => {
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };
// options.form = { sourceNodeId: req.params.source, targetNodeId: req.params.target, amountMsat: req.params.amount, ignoreNodeIds: req.params.ignore };
export const circularRebalance = (req, res, next) => { export const circularRebalance = (req, res, next) => {
const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats'; const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats';
options = common.getOptions(req); options = common.getOptions(req);

@ -38,7 +38,6 @@ export const getInfo = (req, res, next) => {
body.lnImplementation = 'Eclair'; body.lnImplementation = 'Eclair';
req.session.selectedNode.ln_version = body.version.split('-')[0] || ''; req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
eclWsClient.updateSelectedNode(req.session.selectedNode); eclWsClient.updateSelectedNode(req.session.selectedNode);
databaseService.loadDatabase(req.session);
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
return res.status(200).json(body); return res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {

@ -141,7 +141,11 @@ export const postChannel = (req, res, next) => {
else if (req.body.trans_type === '2') { else if (req.body.trans_type === '2') {
options.form.sat_per_byte = req.body.trans_type_value; options.form.sat_per_byte = req.body.trans_type_value;
} }
if (req.body.commitment_type) {
options.form.commitment_type = req.body.commitment_type;
}
options.form = JSON.stringify(options.form); options.form = JSON.stringify(options.form);
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Channels', msg: 'Channel Open Options', data: options.form });
request.post(options).then((body) => { request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Channel Opened', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Channel Opened', data: body });
res.status(201).json(body); res.status(201).json(body);

@ -44,7 +44,6 @@ export const getInfo = (req, res, next) => {
else { else {
req.session.selectedNode.ln_version = body.version.split('-')[0] || ''; req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
lndWsClient.updateSelectedNode(req.session.selectedNode); lndWsClient.updateSelectedNode(req.session.selectedNode);
databaseService.loadDatabase(req.session);
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
return res.status(200).json(body); return res.status(200).json(body);
} }

@ -18,9 +18,12 @@ export const updateSelectedNode = (req, res, next) => {
req.session.selectedNode = common.findNode(selNodeIndex); req.session.selectedNode = common.findNode(selNodeIndex);
if (req.headers && req.headers.authorization && req.headers.authorization !== '') { if (req.headers && req.headers.authorization && req.headers.authorization !== '') {
wsServer.updateLNWSClientDetails(req.session.id, +req.session.selectedNode.index, +req.params.prevNodeIndex); wsServer.updateLNWSClientDetails(req.session.id, +req.session.selectedNode.index, +req.params.prevNodeIndex);
if (req.params.prevNodeIndex !== -1) { if (req.params.prevNodeIndex !== '-1') {
databaseService.unloadDatabase(req.params.prevNodeIndex, req.session.id); databaseService.unloadDatabase(req.params.prevNodeIndex, req.session.id);
} }
if (req.params.currNodeIndex !== '-1') {
databaseService.loadDatabase(req.session);
}
} }
const responseVal = !req.session.selectedNode.ln_node ? '' : req.session.selectedNode.ln_node; const responseVal = !req.session.selectedNode.ln_node ? '' : req.session.selectedNode.ln_node;
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'RTLConf', msg: 'Selected Node Updated To ' + responseVal }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'RTLConf', msg: 'Selected Node Updated To ' + responseVal });

@ -6,13 +6,7 @@ const logger = Logger;
const common = Common; const common = Common;
export const loopOut = (req, res, next) => { export const loopOut = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
sweep_conf_target: req.body.targetConf, sweep_conf_target: req.body.targetConf,
@ -41,13 +35,7 @@ export const loopOut = (req, res, next) => {
}; };
export const loopOutTerms = (req, res, next) => { export const loopOutTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -58,13 +46,7 @@ export const loopOutTerms = (req, res, next) => {
}; };
export const loopOutQuote = (req, res, next) => { export const loopOutQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url });
request(options).then((quoteRes) => { request(options).then((quoteRes) => {
quoteRes.amount = +req.params.amount; quoteRes.amount = +req.params.amount;
@ -78,19 +60,13 @@ export const loopOutQuote = (req, res, next) => {
}; };
export const loopOutTermsAndQuotes = (req, res, next) => { export const loopOutTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms });
const options1 = common.getSwapServerOptions(req); const options1 = options;
const options2 = common.getSwapServerOptions(req); const options2 = options;
options1.url = options1.url + '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.uri = '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.url = options2.url + '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.uri = '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -112,13 +88,7 @@ export const loopOutTermsAndQuotes = (req, res, next) => {
}; };
export const loopIn = (req, res, next) => { export const loopIn = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
max_swap_fee: req.body.swapFee, max_swap_fee: req.body.swapFee,
@ -136,13 +106,7 @@ export const loopIn = (req, res, next) => {
}; };
export const loopInTerms = (req, res, next) => { export const loopInTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -153,13 +117,7 @@ export const loopInTerms = (req, res, next) => {
}; };
export const loopInQuote = (req, res, next) => { export const loopInQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url });
request(options).then((body) => { request(options).then((body) => {
body.amount = +req.params.amount; body.amount = +req.params.amount;
@ -173,19 +131,13 @@ export const loopInQuote = (req, res, next) => {
}; };
export const loopInTermsAndQuotes = (req, res, next) => { export const loopInTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms });
const options1 = common.getSwapServerOptions(req); const options1 = options;
const options2 = common.getSwapServerOptions(req); const options2 = options;
options1.url = options1.url + '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.uri = '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.url = options2.url + '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.uri = '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -207,13 +159,12 @@ export const loopInTermsAndQuotes = (req, res, next) => {
}; };
export const swaps = (req, res, next) => { export const swaps = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' });
options = common.getSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.url = options.url + '/v1/loop/swaps'; options.uri = '/v1/loop/swaps';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body });
res.status(200).json(body.swaps); res.status(200).json(body.swaps);
@ -224,18 +175,29 @@ export const swaps = (req, res, next) => {
}; };
export const swap = (req, res, next) => { export const swap = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/swap/' + req.params.id;
request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const loopInfo = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Information..' });
options = common.setSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Get Swap Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'Get Loop Info Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.url = options.url + '/v1/loop/swap/' + req.params.id; options.uri = '/v1/loop/info';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Information Received', data: body });
res.status(200).json(body); res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode); const err = common.handleError(errRes, 'Loop', 'Get Loop Info Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };

@ -137,3 +137,25 @@ export const CollectionFieldsEnum = { ...OfferFieldsEnum, ...PageSettingsFieldsE
export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS]; export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS];
export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS]; export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS];
export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS]; export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS];
export const ECL_UPDATED_DB = [
{
pageId: 'peers_channels',
tables: [
{
tableId: 'open_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'pending_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'inactive_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
}
]
}
];

@ -1,8 +1,9 @@
import exprs from 'express'; import exprs from 'express';
const { Router } = exprs; const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js'; import { isAuthenticated } from '../../utils/authCheck.js';
import { loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js'; import { loopInfo, loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js';
const router = Router(); const router = Router();
router.get('/info', isAuthenticated, loopInfo);
router.get('/in/terms', isAuthenticated, loopInTerms); router.get('/in/terms', isAuthenticated, loopInTerms);
router.get('/in/quote/:amount', isAuthenticated, loopInQuote); router.get('/in/quote/:amount', isAuthenticated, loopInQuote);
router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes); router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes);

@ -10,6 +10,7 @@ import sharedRoutes from '../routes/shared/index.js';
import lndRoutes from '../routes/lnd/index.js'; import lndRoutes from '../routes/lnd/index.js';
import clnRoutes from '../routes/cln/index.js'; import clnRoutes from '../routes/cln/index.js';
import eclRoutes from '../routes/eclair/index.js'; import eclRoutes from '../routes/eclair/index.js';
import { Database } from './database.js';
import { Common } from './common.js'; import { Common } from './common.js';
import { Logger } from './logger.js'; import { Logger } from './logger.js';
import { CLWSClient } from '../controllers/cln/webSocketClient.js'; import { CLWSClient } from '../controllers/cln/webSocketClient.js';
@ -24,6 +25,7 @@ export class ExpressApplication {
this.eclWsClient = ECLWSClient; this.eclWsClient = ECLWSClient;
this.clWsClient = CLWSClient; this.clWsClient = CLWSClient;
this.lndWsClient = LNDWSClient; this.lndWsClient = LNDWSClient;
this.databaseService = Database;
this.directoryName = dirname(fileURLToPath(import.meta.url)); this.directoryName = dirname(fileURLToPath(import.meta.url));
this.getApp = () => this.app; this.getApp = () => this.app;
this.setCORS = () => { CORS.mount(this.app); }; this.setCORS = () => { CORS.mount(this.app); };
@ -79,6 +81,7 @@ export class ExpressApplication {
this.setCORS(); this.setCORS();
this.setCSRF(); this.setCSRF();
this.setApplicationRoutes(); this.setApplicationRoutes();
this.databaseService.migrateDatabase();
} }
} }
export default ExpressApplication; export default ExpressApplication;

@ -29,9 +29,10 @@ export class CommonService {
{ name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 }, { name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 },
{ name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 } { name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 }
]; ];
this.getSwapServerOptions = (req) => { this.setSwapServerOptions = (req) => {
const swapOptions = { const swapOptions = {
url: req.session.selectedNode.swap_server_url, baseUrl: req.session.selectedNode.swap_server_url,
uri: '',
rejectUnauthorized: false, rejectUnauthorized: false,
json: true, json: true,
headers: { 'Grpc-Metadata-macaroon': '' } headers: { 'Grpc-Metadata-macaroon': '' }
@ -225,6 +226,10 @@ export class CommonService {
errRes.error = errRes.error.stack || errRes.error.message; errRes.error = errRes.error.stack || errRes.error.message;
err = JSON.parse(JSON.stringify(errRes)); err = JSON.parse(JSON.stringify(errRes));
} }
else if (errRes.message || errRes.stack) {
errRes.error = errRes.message || errRes.stack;
err = JSON.parse(JSON.stringify(errRes));
}
if (!selectedNode) { if (!selectedNode) {
selectedNode = this.initSelectedNode; selectedNode = this.initSelectedNode;
} }

@ -2,7 +2,7 @@ import * as fs from 'fs';
import { join, sep } from 'path'; import { join, sep } from 'path';
import { Common } from '../utils/common.js'; import { Common } from '../utils/common.js';
import { Logger } from '../utils/logger.js'; import { Logger } from '../utils/logger.js';
import { validateDocument, LNDCollection, ECLCollection, CLNCollection } from '../models/database.model.js'; import { CollectionsEnum, validateDocument, LNDCollection, ECLCollection, CLNCollection, ECL_UPDATED_DB } from '../models/database.model.js';
export class DatabaseService { export class DatabaseService {
constructor() { constructor() {
this.common = Common; this.common = Common;
@ -10,6 +10,58 @@ export class DatabaseService {
this.dbDirectory = join(this.common.db_directory_path, 'database'); this.dbDirectory = join(this.common.db_directory_path, 'database');
this.nodeDatabase = {}; this.nodeDatabase = {};
} }
migrateDatabase() {
this.common.nodes?.map((node) => {
if (node.ln_implementation === 'ECL') {
this.nodeDatabase[node.index] = { adapter: null, data: {} };
this.nodeDatabase[node.index].adapter = new DatabaseAdapter(this.dbDirectory, node);
this.fetchNodeData(node);
if (this.nodeDatabase[node.index].data.PageSettings) {
try {
const currPageSettings = JSON.parse(JSON.stringify(this.nodeDatabase[node.index].data.PageSettings));
ECL_UPDATED_DB.forEach((updatePage) => {
const foundPageDB = this.nodeDatabase[node.index].data.PageSettings.find((currPage) => currPage.pageId === updatePage.pageId);
if (foundPageDB) {
updatePage.tables.forEach((updateTable) => {
const foundTableDB = foundPageDB.tables.find((currTable) => currTable.tableId === updateTable.tableId);
if (foundTableDB) {
updateTable.removed.forEach((colToBeRemoved) => {
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === colToBeRemoved);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === colToBeRemoved);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1);
}
});
updateTable.renamed.forEach((colToBeRenamed) => {
const [oldName, newName] = colToBeRenamed.split(':');
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === oldName);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === oldName);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1, newName);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1, newName);
}
});
}
});
}
});
if (currPageSettings !== this.nodeDatabase[node.index].data.PageSettings) {
this.saveDatabase(node, CollectionsEnum.PAGE_SETTINGS);
}
}
catch (err) {
this.logger.log({ selectedNode: node, level: 'ERROR', fileName: 'Database', msg: 'Database Migration Error', error: err });
}
}
}
return true;
});
}
loadDatabase(session) { loadDatabase(session) {
const { id, selectedNode } = session; const { id, selectedNode } = session;
try { try {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -603,12 +603,90 @@ to represent the company, product, or service to which they refer.**
@ngrx/effects @ngrx/effects
MIT MIT
The MIT License (MIT)
Copyright (c) 2017-2023 Brandon Roberts, Mike Ryan, Victor Savkin, Rob Wormald
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This repository includes a file "debounceSync.ts" originially copied from
https://github.com/cartant/rxjs-etc by Nicholas Jamieson, MIT licensed. See the
file header for details.
@ngrx/store @ngrx/store
MIT MIT
The MIT License (MIT)
Copyright (c) 2017-2023 Brandon Roberts, Mike Ryan, Victor Savkin, Rob Wormald
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This repository includes a file "debounceSync.ts" originially copied from
https://github.com/cartant/rxjs-etc by Nicholas Jamieson, MIT licensed. See the
file header for details.
@ngrx/store-devtools @ngrx/store-devtools
MIT MIT
The MIT License (MIT)
Copyright (c) 2017-2023 Brandon Roberts, Mike Ryan, Victor Savkin, Rob Wormald
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This repository includes a file "debounceSync.ts" originially copied from
https://github.com/cartant/rxjs-etc by Nicholas Jamieson, MIT licensed. See the
file header for details.
@otplib/core @otplib/core
MIT MIT
@ -1113,163 +1191,93 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
d3-array d3-array
BSD-3-Clause ISC
Copyright 2010-2020 Mike Bostock Copyright 2010-2023 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-brush d3-brush
BSD-3-Clause ISC
Copyright 2010-2016 Mike Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-color d3-color
BSD-3-Clause ISC
Copyright 2010-2016 Mike Bostock Copyright 2010-2022 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-dispatch d3-dispatch
BSD-3-Clause ISC
Copyright 2010-2016 Mike Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-drag d3-drag
BSD-3-Clause ISC
Copyright 2010-2016 Mike Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-ease d3-ease
BSD-3-Clause BSD-3-Clause
Copyright 2010-2016 Mike Bostock Copyright 2010-2021 Mike Bostock
Copyright 2001 Robert Penner Copyright 2001 Robert Penner
All rights reserved. All rights reserved.
@ -1300,157 +1308,88 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-format d3-format
BSD-3-Clause ISC
Copyright 2010-2015 Mike Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-interpolate d3-interpolate
BSD-3-Clause ISC
Copyright 2010-2016 Mike Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-scale d3-scale
BSD-3-Clause ISC
Copyright 2010-2015 Mike Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-selection d3-selection
BSD-3-Clause ISC
Copyright (c) 2010-2018, Michael Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name Michael Bostock may not be used to endorse or promote products Permission to use, copy, modify, and/or distribute this software for any purpose
derived from this software without specific prior written permission. with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY THIS SOFTWARE.
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-time d3-time
BSD-3-Clause ISC
Copyright 2010-2016 Mike Bostock Copyright 2010-2022 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-time-format d3-time-format
@ -1485,96 +1424,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-timer d3-timer
BSD-3-Clause ISC
Copyright 2010-2016 Mike Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-transition d3-transition
BSD-3-Clause ISC
Copyright (c) 2010-2015, Michael Bostock Copyright 2010-2021 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name Michael Bostock may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
TERMS OF USE - EASING EQUATIONS
Open source under the BSD License.
Copyright 2001 Robert Penner
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the author nor the names of contributors may be used to Permission to use, copy, modify, and/or distribute this software for any purpose
endorse or promote products derived from this software without specific prior with or without fee is hereby granted, provided that the above copyright notice
written permission. and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON THIS SOFTWARE.
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
des.js des.js
@ -1749,6 +1629,23 @@ PERFORMANCE OF THIS SOFTWARE.
internmap
ISC
Copyright 2021 Mike Bostock
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
material-icons material-icons
Apache-2.0 Apache-2.0
@ -3014,7 +2911,7 @@ zone.js
MIT MIT
The MIT License The MIT License
Copyright (c) 2010-2022 Google LLC. https://angular.io/license Copyright (c) 2010-2023 Google LLC. https://angular.io/license
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
(()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],s=!0,d=0;d<t.length;d++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[d]))?t.splice(d--,1):(s=!1,o<a&&(a=o));if(s){e.splice(n--,1);var u=i();void 0!==u&&(f=u)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>e+"."+{167:"a3774800f5f9ed5a",267:"5508f97536cb5708",315:"d20113f8d2f54786",636:"eaef3bec0eb4cb7a"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="RTLApp:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,s;if(void 0!==o)for(var d=document.getElementsByTagName("script"),u=0;u<d.length;u++){var l=d[u];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==f+o){a=l;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var c=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(y=>y(b)),g)return g(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),r.r=e=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:f=>f},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=i){var a=new Promise((l,c)=>n=e[i]=[l,c]);o.push(n[2]=a);var s=r.p+r.u(i),d=new Error;r.l(s,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var c=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;d.message="Loading chunk "+i+" failed.\n("+c+": "+p+")",d.name="ChunkLoadError",d.type=c,d.request=p,n[1](d)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var d,u,[n,a,s]=o,l=0;if(n.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(s)var c=s(r)}for(i&&i(o);l<n.length;l++)r.o(e,u=n[l])&&e[u]&&e[u][0](),e[u]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})(); (()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],s=!0,d=0;d<t.length;d++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[d]))?t.splice(d--,1):(s=!1,o<a&&(a=o));if(s){e.splice(n--,1);var u=i();void 0!==u&&(f=u)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>e+"."+{125:"020bb8ec6698fd7e",456:"a54c45d211d6d10c",570:"28ed94d292ccd982",758:"2801e2da6f8bba94"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="RTLApp:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,s;if(void 0!==o)for(var d=document.getElementsByTagName("script"),u=0;u<d.length;u++){var l=d[u];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==f+o){a=l;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var c=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(y=>y(b)),g)return g(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),r.r=e=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:f=>f},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=i){var a=new Promise((l,c)=>n=e[i]=[l,c]);o.push(n[2]=a);var s=r.p+r.u(i),d=new Error;r.l(s,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var c=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;d.message="Loading chunk "+i+" failed.\n("+c+": "+p+")",d.name="ChunkLoadError",d.type=c,d.request=p,n[1](d)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var d,u,[n,a,s]=o,l=0;if(n.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(s)var c=s(r)}for(i&&i(o);l<n.length;l++)r.o(e,u=n[l])&&e[u]&&e[u][0](),e[u]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

9336
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{ {
"name": "rtl", "name": "rtl",
"version": "0.14.0-beta", "version": "0.14.1-beta",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
@ -10,8 +10,8 @@
"prebuildfrontend": "node src/prebuild.cjs", "prebuildfrontend": "node src/prebuild.cjs",
"buildfrontendtest": "ng test --watch=false && ng build", "buildfrontendtest": "ng test --watch=false && ng build",
"buildfrontend": "ng build --configuration production", "buildfrontend": "ng build --configuration production",
"buildbackend": "tsc --project tsconfig.json", "buildbackend": "tsc --project ./server/tsconfig.server.json",
"watchbackend": "tsc --project tsconfig.json --watch", "watchbackend": "tsc --project ./server/tsconfig.server.json --watch",
"server": "set NODE_ENV=development&&nodemon --watch backend --watch server ./rtl.js", "server": "set NODE_ENV=development&&nodemon --watch backend --watch server ./rtl.js",
"serverUbuntu": "NODE_ENV=development nodemon --watch backend --watch server ./rtl.js", "serverUbuntu": "NODE_ENV=development nodemon --watch backend --watch server ./rtl.js",
"testdev": "ng test --watch=true --code-coverage", "testdev": "ng test --watch=true --code-coverage",
@ -21,10 +21,10 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ngrx/effects": "^15.0.0", "@ngrx/effects": "^16.3.0",
"@ngrx/store": "^15.0.0", "@ngrx/store": "^16.3.0",
"@swimlane/ngx-charts": "^20.1.2", "@swimlane/ngx-charts": "^20.4.1",
"angular-user-idle": "^3.0.0", "angular-user-idle": "^4.0.0",
"atob": "^2.1.2", "atob": "^2.1.2",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"crypto-browserify": "^3.12.0", "crypto-browserify": "^3.12.0",
@ -32,65 +32,65 @@
"express": "^4.18.2", "express": "^4.18.2",
"express-session": "^1.17.3", "express-session": "^1.17.3",
"hocon-parser": "^1.0.1", "hocon-parser": "^1.0.1",
"ini": "^3.0.1", "ini": "^4.1.1",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.2",
"ng-qrcode": "^8.0.1", "ng-qrcode": "^16.0.0",
"ngx-perfect-scrollbar-next": "^10.1.1", "ngx-perfect-scrollbar-next": "^10.1.1",
"otplib": "^12.0.1", "otplib": "^12.0.1",
"pdfmake": "^0.2.6", "pdfmake": "^0.2.7",
"request": "^2.88.2", "request": "^2.88.2",
"request-promise": "^4.2.6", "request-promise": "^4.2.6",
"rxjs": "~7.5.0", "rxjs": "~7.8.0",
"sha256": "^0.2.0", "sha256": "^0.2.0",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"ws": "^8.11.0", "ws": "^8.14.2",
"zone.js": "~0.12.0" "zone.js": "~0.13.0"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^15.0.1", "@angular-devkit/build-angular": "^16.2.5",
"@angular-eslint/builder": "^15.1.0", "@angular-eslint/builder": "^16.2.0",
"@angular-eslint/eslint-plugin": "^15.1.0", "@angular-eslint/eslint-plugin": "^16.2.0",
"@angular-eslint/eslint-plugin-template": "^15.1.0", "@angular-eslint/eslint-plugin-template": "^16.2.0",
"@angular-eslint/schematics": "^15.1.0", "@angular-eslint/schematics": "^16.2.0",
"@angular-eslint/template-parser": "^15.1.0", "@angular-eslint/template-parser": "^16.2.0",
"@angular/animations": "^15.0.0", "@angular/animations": "^16.2.0",
"@angular/cdk": "^15.0.1", "@angular/cdk": "^16.2.7",
"@angular/cli": "~15.0.1", "@angular/cli": "^16.2.5",
"@angular/common": "^15.0.0", "@angular/compiler-cli": "^16.2.0",
"@angular/compiler": "^15.0.0", "@angular/common": "^16.2.0",
"@angular/compiler-cli": "^15.0.0", "@angular/compiler": "^16.2.0",
"@angular/core": "^15.0.0", "@angular/core": "^16.2.0",
"@angular/flex-layout": "^14.0.0-beta.41", "@angular/flex-layout": "^15.0.0-beta.42",
"@angular/forms": "^15.0.0", "@angular/forms": "^16.2.0",
"@angular/material": "^15.0.1", "@angular/material": "^16.2.7",
"@angular/platform-browser": "^15.0.0", "@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^15.0.0", "@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^15.0.0", "@angular/router": "^16.2.0",
"@fortawesome/angular-fontawesome": "^0.12.0", "@fortawesome/angular-fontawesome": "^0.13.0",
"@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-regular-svg-icons": "^6.2.1", "@fortawesome/free-regular-svg-icons": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.4.2",
"@ngrx/store-devtools": "^15.0.0", "@ngrx/store-devtools": "^16.3.0",
"@types/jasmine": "~4.3.0", "@types/jasmine": "~4.3.0",
"@types/node": "^18.11.13", "@types/node": "^20.8.2",
"@typescript-eslint/eslint-plugin": "^5.44.0", "@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^5.44.0", "@typescript-eslint/parser": "^6.7.4",
"dotenv": "^16.0.3", "dotenv": "^16.3.1",
"eslint": "^8.28.0", "eslint": "^8.50.0",
"eslint-plugin-deprecation": "^1.3.3", "eslint-plugin-deprecation": "^2.0.0",
"jasmine-core": "~4.5.0", "jasmine-core": "~4.6.0",
"jasmine-spec-reporter": "^7.0.0", "jasmine-spec-reporter": "^7.0.0",
"karma": "~6.4.0", "karma": "~6.4.0",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0", "karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.0.0", "karma-jasmine-html-reporter": "~2.1.0",
"material-icons": "^1.13.1", "material-icons": "^1.13.12",
"nodemon": "^2.0.20", "nodemon": "^3.0.1",
"protractor": "^7.0.0", "protractor": "^7.0.0",
"roboto-fontface": "^0.10.0", "roboto-fontface": "^0.10.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "~4.8.4" "typescript": "~5.1.3"
} }
} }

@ -35,7 +35,7 @@ export const listChannels = (req, res, next) => {
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels'; options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels';
request(options).then((body) => { request(options).then((body) => {
body?.map((channel) => { body?.map((channel) => {
if (!channel.alias || channel.alias === '') { channel.alias = channel.id.substring(0, 20); } if (!channel.alias || channel.alias === '') { channel.alias = channel.channel_id.substring(0, 20); }
const local = channel.to_us_msat || 0; const local = channel.to_us_msat || 0;
const remote = (channel.total_msat - local) || 0; const remote = (channel.total_msat - local) || 0;
const total = channel.total_msat || 0; const total = channel.total_msat || 0;

@ -56,7 +56,6 @@ export const getInfo = (req, res, next) => {
req.session.selectedNode.ln_version = body.version || ''; req.session.selectedNode.ln_version = body.version || '';
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' });
clWsClient.updateSelectedNode(req.session.selectedNode); clWsClient.updateSelectedNode(req.session.selectedNode);
databaseService.loadDatabase(req.session);
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
return res.status(200).json(body); return res.status(200).json(body);
} }

@ -19,14 +19,12 @@ export const simplifyAllChannels = (selNode: CommonSelectedNode, channels) => {
nodeId: channel.nodeId ? channel.nodeId : '', nodeId: channel.nodeId ? channel.nodeId : '',
channelId: channel.channelId ? channel.channelId : '', channelId: channel.channelId ? channel.channelId : '',
state: channel.state ? channel.state : '', state: channel.state ? channel.state : '',
announceChannel: channel.data && channel.data.commitments && channel.data.commitments.channelFlags && channel.data.commitments.channelFlags.announceChannel ? channel.data.commitments.channelFlags.announceChannel : false, announceChannel: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.channelFlags && channel.data.commitments.params.channelFlags.announceChannel ? channel.data.commitments.params.channelFlags.announceChannel : false,
toLocal: (channel.data.commitments.localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.localCommit.spec.toLocal / 1000) : 0, toLocal: (channel.data.commitments.active[0].localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toLocal / 1000) : 0,
toRemote: (channel.data.commitments.localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.localCommit.spec.toRemote / 1000) : 0, toRemote: (channel.data.commitments.active[0].localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toRemote / 1000) : 0,
shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '', shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '',
isFunder: channel.data && channel.data.commitments && channel.data.commitments.localParams && channel.data.commitments.localParams.isFunder ? channel.data.commitments.localParams.isFunder : false, isInitiator: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.localParams && channel.data.commitments.params.localParams.isInitiator ? channel.data.commitments.params.localParams.isInitiator : false,
buried: channel.data && channel.data.buried ? channel.data.buried : false,
feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0, feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0,
feeRatePerKw: (channel.data.commitments.localCommit.spec.feeratePerKw) ? channel.data.commitments.localCommit.spec.feeratePerKw : 0,
feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0, feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0,
alias: '' alias: ''
}); });
@ -155,8 +153,6 @@ export const closeChannel = (req, res, next) => {
}); });
}; };
// options.form = { sourceNodeId: req.params.source, targetNodeId: req.params.target, amountMsat: req.params.amount, ignoreNodeIds: req.params.ignore };
export const circularRebalance = (req, res, next) => { export const circularRebalance = (req, res, next) => {
const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats'; const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats';
options = common.getOptions(req); options = common.getOptions(req);

@ -36,7 +36,6 @@ export const getInfo = (req, res, next) => {
body.lnImplementation = 'Eclair'; body.lnImplementation = 'Eclair';
req.session.selectedNode.ln_version = body.version.split('-')[0] || ''; req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
eclWsClient.updateSelectedNode(req.session.selectedNode); eclWsClient.updateSelectedNode(req.session.selectedNode);
databaseService.loadDatabase(req.session);
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
return res.status(200).json(body); return res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {

@ -140,7 +140,11 @@ export const postChannel = (req, res, next) => {
} else if (req.body.trans_type === '2') { } else if (req.body.trans_type === '2') {
options.form.sat_per_byte = req.body.trans_type_value; options.form.sat_per_byte = req.body.trans_type_value;
} }
if (req.body.commitment_type) {
options.form.commitment_type = req.body.commitment_type;
}
options.form = JSON.stringify(options.form); options.form = JSON.stringify(options.form);
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Channels', msg: 'Channel Open Options', data: options.form });
request.post(options).then((body) => { request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Channel Opened', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Channel Opened', data: body });
res.status(201).json(body); res.status(201).json(body);

@ -40,7 +40,6 @@ export const getInfo = (req, res, next) => {
} else { } else {
req.session.selectedNode.ln_version = body.version.split('-')[0] || ''; req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
lndWsClient.updateSelectedNode(req.session.selectedNode); lndWsClient.updateSelectedNode(req.session.selectedNode);
databaseService.loadDatabase(req.session);
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
return res.status(200).json(body); return res.status(200).json(body);
} }

@ -21,9 +21,12 @@ export const updateSelectedNode = (req, res, next) => {
req.session.selectedNode = common.findNode(selNodeIndex); req.session.selectedNode = common.findNode(selNodeIndex);
if (req.headers && req.headers.authorization && req.headers.authorization !== '') { if (req.headers && req.headers.authorization && req.headers.authorization !== '') {
wsServer.updateLNWSClientDetails(req.session.id, +req.session.selectedNode.index, +req.params.prevNodeIndex); wsServer.updateLNWSClientDetails(req.session.id, +req.session.selectedNode.index, +req.params.prevNodeIndex);
if (req.params.prevNodeIndex !== -1) { if (req.params.prevNodeIndex !== '-1') {
databaseService.unloadDatabase(req.params.prevNodeIndex, req.session.id); databaseService.unloadDatabase(req.params.prevNodeIndex, req.session.id);
} }
if (req.params.currNodeIndex !== '-1') {
databaseService.loadDatabase(req.session);
}
} }
const responseVal = !req.session.selectedNode.ln_node ? '' : req.session.selectedNode.ln_node; const responseVal = !req.session.selectedNode.ln_node ? '' : req.session.selectedNode.ln_node;
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'RTLConf', msg: 'Selected Node Updated To ' + responseVal }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'RTLConf', msg: 'Selected Node Updated To ' + responseVal });

@ -7,13 +7,7 @@ const common: CommonService = Common;
export const loopOut = (req, res, next) => { export const loopOut = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
sweep_conf_target: req.body.targetConf, sweep_conf_target: req.body.targetConf,
@ -39,13 +33,7 @@ export const loopOut = (req, res, next) => {
export const loopOutTerms = (req, res, next) => { export const loopOutTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -57,13 +45,7 @@ export const loopOutTerms = (req, res, next) => {
export const loopOutQuote = (req, res, next) => { export const loopOutQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url });
request(options).then((quoteRes) => { request(options).then((quoteRes) => {
quoteRes.amount = +req.params.amount; quoteRes.amount = +req.params.amount;
@ -78,18 +60,12 @@ export const loopOutQuote = (req, res, next) => {
export const loopOutTermsAndQuotes = (req, res, next) => { export const loopOutTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/out/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms });
const options1 = common.getSwapServerOptions(req); const options2 = common.getSwapServerOptions(req); const options1 = options; const options2 = options;
options1.url = options1.url + '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.uri = '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.url = options2.url + '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.uri = '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -112,13 +88,7 @@ export const loopOutTermsAndQuotes = (req, res, next) => {
export const loopIn = (req, res, next) => { export const loopIn = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
max_swap_fee: req.body.swapFee, max_swap_fee: req.body.swapFee,
@ -137,13 +107,7 @@ export const loopIn = (req, res, next) => {
export const loopInTerms = (req, res, next) => { export const loopInTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -155,13 +119,7 @@ export const loopInTerms = (req, res, next) => {
export const loopInQuote = (req, res, next) => { export const loopInQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url });
request(options).then((body) => { request(options).then((body) => {
body.amount = +req.params.amount; body.amount = +req.params.amount;
@ -176,18 +134,12 @@ export const loopInQuote = (req, res, next) => {
export const loopInTermsAndQuotes = (req, res, next) => { export const loopInTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/in/terms';
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms });
const options1 = common.getSwapServerOptions(req); const options2 = common.getSwapServerOptions(req); const options1 = options; const options2 = options;
options1.url = options1.url + '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.uri = '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.url = options2.url + '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.uri = '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -210,13 +162,12 @@ export const loopInTermsAndQuotes = (req, res, next) => {
export const swaps = (req, res, next) => { export const swaps = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' });
options = common.getSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.url = options.url + '/v1/loop/swaps'; options.uri = '/v1/loop/swaps';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body });
res.status(200).json(body.swaps); res.status(200).json(body.swaps);
@ -228,18 +179,30 @@ export const swaps = (req, res, next) => {
export const swap = (req, res, next) => { export const swap = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' });
options = common.getSwapServerOptions(req); options.uri = '/v1/loop/swap/' + req.params.id;
request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const loopInfo = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Information..' });
options = common.setSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Get Swap Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'Get Loop Info Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.url = options.url + '/v1/loop/swap/' + req.params.id; options.uri = '/v1/loop/info';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Information Received', data: body });
res.status(200).json(body); res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode); const err = common.handleError(errRes, 'Loop', 'Get Loop Info Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };

@ -154,3 +154,26 @@ export const CollectionFieldsEnum = { ...OfferFieldsEnum, ...PageSettingsFieldsE
export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS]; export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS];
export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS]; export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS];
export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS]; export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS];
export const ECL_UPDATED_DB = [
{
pageId: 'peers_channels',
tables: [
{
tableId: 'open_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'pending_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'inactive_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
}
]
}
];

@ -1,10 +1,11 @@
import exprs from 'express'; import exprs from 'express';
const { Router } = exprs; const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js'; import { isAuthenticated } from '../../utils/authCheck.js';
import { loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js'; import { loopInfo, loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js';
const router = Router(); const router = Router();
router.get('/info', isAuthenticated, loopInfo);
router.get('/in/terms', isAuthenticated, loopInTerms); router.get('/in/terms', isAuthenticated, loopInTerms);
router.get('/in/quote/:amount', isAuthenticated, loopInQuote); router.get('/in/quote/:amount', isAuthenticated, loopInQuote);
router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes); router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes);

@ -0,0 +1,11 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"baseUrl": "../",
"outDir": "../backend",
},
"include": [
"./**/*"
]
}

@ -11,6 +11,7 @@ import sharedRoutes from '../routes/shared/index.js';
import lndRoutes from '../routes/lnd/index.js'; import lndRoutes from '../routes/lnd/index.js';
import clnRoutes from '../routes/cln/index.js'; import clnRoutes from '../routes/cln/index.js';
import eclRoutes from '../routes/eclair/index.js'; import eclRoutes from '../routes/eclair/index.js';
import { Database, DatabaseService } from './database.js';
import { Common, CommonService } from './common.js'; import { Common, CommonService } from './common.js';
import { Logger, LoggerService } from './logger.js'; import { Logger, LoggerService } from './logger.js';
import { CLWSClient, CLWebSocketClient } from '../controllers/cln/webSocketClient.js'; import { CLWSClient, CLWebSocketClient } from '../controllers/cln/webSocketClient.js';
@ -27,6 +28,7 @@ export class ExpressApplication {
public eclWsClient: ECLWebSocketClient = ECLWSClient; public eclWsClient: ECLWebSocketClient = ECLWSClient;
public clWsClient: CLWebSocketClient = CLWSClient; public clWsClient: CLWebSocketClient = CLWSClient;
public lndWsClient: LNDWebSocketClient = LNDWSClient; public lndWsClient: LNDWebSocketClient = LNDWSClient;
public databaseService: DatabaseService = Database;
public directoryName = dirname(fileURLToPath(import.meta.url)); public directoryName = dirname(fileURLToPath(import.meta.url));
constructor() { constructor() {
@ -40,6 +42,7 @@ export class ExpressApplication {
this.setCORS(); this.setCORS();
this.setCSRF(); this.setCSRF();
this.setApplicationRoutes(); this.setApplicationRoutes();
this.databaseService.migrateDatabase();
} }
public getApp = () => this.app; public getApp = () => this.app;

@ -34,9 +34,10 @@ export class CommonService {
constructor() { } constructor() { }
public getSwapServerOptions = (req) => { public setSwapServerOptions = (req) => {
const swapOptions = { const swapOptions = {
url: req.session.selectedNode.swap_server_url, baseUrl: req.session.selectedNode.swap_server_url,
uri: '',
rejectUnauthorized: false, rejectUnauthorized: false,
json: true, json: true,
headers: { 'Grpc-Metadata-macaroon': '' } headers: { 'Grpc-Metadata-macaroon': '' }
@ -241,6 +242,9 @@ export class CommonService {
if (err && err.error && Object.keys(err.error).length === 0 && errRes.error && (errRes.error.stack || errRes.error.message)) { if (err && err.error && Object.keys(err.error).length === 0 && errRes.error && (errRes.error.stack || errRes.error.message)) {
errRes.error = errRes.error.stack || errRes.error.message; errRes.error = errRes.error.stack || errRes.error.message;
err = JSON.parse(JSON.stringify(errRes)); err = JSON.parse(JSON.stringify(errRes));
} else if (errRes.message || errRes.stack) {
errRes.error = errRes.message || errRes.stack;
err = JSON.parse(JSON.stringify(errRes));
} }
if (!selectedNode) { selectedNode = this.initSelectedNode; } if (!selectedNode) { selectedNode = this.initSelectedNode; }
switch (selectedNode.ln_implementation) { switch (selectedNode.ln_implementation) {

@ -2,7 +2,7 @@ import * as fs from 'fs';
import { join, sep } from 'path'; import { join, sep } from 'path';
import { Common, CommonService } from '../utils/common.js'; import { Common, CommonService } from '../utils/common.js';
import { Logger, LoggerService } from '../utils/logger.js'; import { Logger, LoggerService } from '../utils/logger.js';
import { Collections, CollectionsEnum, validateDocument, LNDCollection, ECLCollection, CLNCollection } from '../models/database.model.js'; import { Collections, CollectionsEnum, validateDocument, LNDCollection, ECLCollection, CLNCollection, ECL_UPDATED_DB } from '../models/database.model.js';
import { CommonSelectedNode } from '../models/config.model.js'; import { CommonSelectedNode } from '../models/config.model.js';
export class DatabaseService { export class DatabaseService {
@ -14,6 +14,58 @@ export class DatabaseService {
constructor() { } constructor() { }
migrateDatabase() {
this.common.nodes?.map((node: any) => {
if (node.ln_implementation === 'ECL') {
this.nodeDatabase[node.index] = { adapter: null, data: {} };
this.nodeDatabase[node.index].adapter = new DatabaseAdapter(this.dbDirectory, node);
this.fetchNodeData(node);
if (this.nodeDatabase[node.index].data.PageSettings) {
try {
const currPageSettings = JSON.parse(JSON.stringify(this.nodeDatabase[node.index].data.PageSettings));
ECL_UPDATED_DB.forEach((updatePage) => {
const foundPageDB = this.nodeDatabase[node.index].data.PageSettings.find((currPage) => currPage.pageId === updatePage.pageId);
if (foundPageDB) {
updatePage.tables.forEach((updateTable) => {
const foundTableDB = foundPageDB.tables.find((currTable) => currTable.tableId === updateTable.tableId);
if (foundTableDB) {
updateTable.removed.forEach((colToBeRemoved) => {
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === colToBeRemoved);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === colToBeRemoved);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1);
}
});
updateTable.renamed.forEach((colToBeRenamed) => {
const [oldName, newName] = colToBeRenamed.split(':');
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === oldName);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === oldName);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1, newName);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1, newName);
}
});
}
});
}
});
if (currPageSettings !== this.nodeDatabase[node.index].data.PageSettings) {
this.saveDatabase(node, CollectionsEnum.PAGE_SETTINGS);
}
} catch (err) {
this.logger.log({ selectedNode: node, level: 'ERROR', fileName: 'Database', msg: 'Database Migration Error', error: err });
}
}
}
return true;
});
}
loadDatabase(session: any) { loadDatabase(session: any) {
const { id, selectedNode } = session; const { id, selectedNode } = session;
try { try {
@ -198,7 +250,7 @@ export class DatabaseAdapter {
private dbFilePath = ''; private dbFilePath = '';
private userSessions = []; private userSessions = [];
constructor(public dbDirectoryPath: string, private selNode: CommonSelectedNode = null, private id: string = '') { constructor(public dbDirectoryPath: string, public selNode: CommonSelectedNode = null, public id: string = '') {
this.dbFilePath = dbDirectoryPath + sep + 'node-' + selNode.index; this.dbFilePath = dbDirectoryPath + sep + 'node-' + selNode.index;
// For backward compatibility Start // For backward compatibility Start
const oldFilePath = dbDirectoryPath + sep + 'rtldb-node-' + selNode.index + '.json'; const oldFilePath = dbDirectoryPath + sep + 'rtldb-node-' + selNode.index + '.json';

@ -16,21 +16,21 @@
<span *ngIf="!smallScreen" class="font-size-120 font-weight-500">{{information.alias ? 'Ride The Lightning - ' + information.alias : 'Ride The Lightning'}}</span> <span *ngIf="!smallScreen" class="font-size-120 font-weight-500">{{information.alias ? 'Ride The Lightning - ' + information.alias : 'Ride The Lightning'}}</span>
</div> </div>
<div> <div>
<rtl-top-menu></rtl-top-menu> <rtl-top-menu />
</div> </div>
</mat-toolbar> </mat-toolbar>
<mat-sidenav-container> <mat-sidenav-container>
<mat-sidenav #sideNavigation class="sidenav mat-elevation-z6" [perfectScrollbar] [opened]="flgSideNavOpened && flgLoggedIn" [mode]="(flgSidenavPinned && !smallScreen) ? 'side' : 'over'"> <mat-sidenav #sideNavigation class="sidenav mat-elevation-z6" [perfectScrollbar] [opened]="flgSideNavOpened && flgLoggedIn" [mode]="(flgSidenavPinned && !smallScreen) ? 'side' : 'over'">
<rtl-side-navigation fxFlex="100" (ChildNavClicked)="onNavigationClicked($event)"></rtl-side-navigation> <rtl-side-navigation fxFlex="100" (ChildNavClicked)="onNavigationClicked($event)" />
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content #sideNavContent [perfectScrollbar]> <mat-sidenav-content #sideNavContent [perfectScrollbar]>
<div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch"> <div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<router-outlet #outlet="outlet"></router-outlet> <router-outlet #outlet="outlet" />
</div> </div>
</mat-sidenav-content>> </mat-sidenav-content>>
</mat-sidenav-container> </mat-sidenav-container>
<div *ngIf="!settings.themeColor" class="rtl-spinner"> <div *ngIf="!settings.themeColor" class="rtl-spinner">
<mat-spinner color="accent"></mat-spinner> <mat-spinner color="accent" />
<h4>Loading RTL...</h4> <h4>Loading RTL...</h4>
</div> </div>
</div> </div>

@ -8,12 +8,11 @@ import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects'; import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools'; import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { UserIdleModule } from 'angular-user-idle'; import { provideUserIdleConfig } from 'angular-user-idle';
import { routing } from './app.routing'; import { routing } from './app.routing';
import { SharedModule } from './shared/shared.module'; import { SharedModule } from './shared/shared.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { AuthGuard } from './shared/services/auth.guard';
import { AuthInterceptor } from './shared/services/auth.interceptor'; import { AuthInterceptor } from './shared/services/auth.interceptor';
import { SessionService } from './shared/services/session.service'; import { SessionService } from './shared/services/session.service';
import { LoopService } from './shared/services/loop.service'; import { LoopService } from './shared/services/loop.service';
@ -42,7 +41,6 @@ if (isDevMode()) { isDevEnvironemt = true; }
routing, routing,
LayoutModule, LayoutModule,
HammerModule, HammerModule,
UserIdleModule.forRoot({ idle: (HOUR_SECONDS - 10), timeout: 10, ping: 12000 }),
StoreModule.forRoot( StoreModule.forRoot(
{ root: RootReducer, lnd: LNDReducer, cln: CLNReducer, ecl: ECLReducer }, { root: RootReducer, lnd: LNDReducer, cln: CLNReducer, ecl: ECLReducer },
{ {
@ -56,6 +54,7 @@ if (isDevMode()) { isDevEnvironemt = true; }
], ],
declarations: [AppComponent], declarations: [AppComponent],
providers: [ providers: [
provideUserIdleConfig({ idle: (HOUR_SECONDS - 10), timeout: 10, ping: 12000 }),
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
SessionService, DataService, WebSocketClientService, LoopService, CommonService, BoltzService SessionService, DataService, WebSocketClientService, LoopService, CommonService, BoltzService
], ],

@ -1,4 +1,4 @@
<div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch"> <div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate" />
<router-outlet #outlet="outlet"></router-outlet> <router-outlet #outlet="outlet" />
</div> </div>

@ -1,5 +1,5 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router'; import { Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router, RouterEvent } from '@angular/router';
import { routeAnimation } from '../shared/animation/route-animation'; import { routeAnimation } from '../shared/animation/route-animation';
@Component({ @Component({
@ -13,7 +13,7 @@ export class CLNRootComponent {
loading = false; loading = false;
constructor(private router: Router) { constructor(private router: Router) {
this.router.events.subscribe((event: Event) => { this.router.events.subscribe((event: Event | RouterEvent) => {
switch (true) { switch (true) {
case event instanceof NavigationStart: { case event instanceof NavigationStart: {
this.loading = true; this.loading = true;

@ -1,16 +1,16 @@
<div fxLayout="row wrap" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row wrap" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faSearch"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faSearch" />
<span class="page-title">Graph Lookups</span> <span class="page-title">Graph Lookups</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x"> <div fxLayout="column" class="padding-gap-x">
<mat-card> <mat-card>
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel"> <nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel">
<div *ngFor="let link of links" role="tab" mat-tab-link class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div> <div *ngFor="let link of links" tabindex="1" role="tab" mat-tab-link class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div>
</nav> </nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel> <mat-tab-nav-panel #tabPanel />
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="mat-tab-body-wrapper"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="mat-tab-body-wrapper">
<router-outlet></router-outlet> <router-outlet />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -1,77 +1,77 @@
<div *ngIf="lookupResult" fxLayout="column" class="mt-1"> <div *ngIf="lookupResult" fxLayout="column" class="mt-1">
<mat-divider></mat-divider> <mat-divider />
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row"> <div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row">
<div fxLayout="column" fxFlex="49" fxLayoutAlign="start stretch" class="mt-1 bordered-box padding-gap-large"> <div fxLayout="column" fxFlex="49" fxLayoutAlign="start stretch" class="mt-1 bordered-box padding-gap-large">
<div fxLayout="column"> <div fxLayout="column">
<h3 *ngIf="!node1_match" class="page-title font-bold-500">Node 1</h3> <h3 *ngIf="!node1_match" class="page-title font-bold-500">Node 1</h3>
<h3 *ngIf="node1_match" class="page-title font-bold-500">Node 1 (Your Node)</h3> <h3 *ngIf="node1_match" class="page-title font-bold-500">Node 1 (Your Node)</h3>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Short Channel ID</h4> <h4 class="font-bold-500">Short Channel ID</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.short_channel_id}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.short_channel_id}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Active</h4> <h4 class="font-bold-500">Active</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.active ? 'True' : 'False'}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.active ? 'True' : 'False'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Last Update</h4> <h4 class="font-bold-500">Last Update</h4>
<span class="foreground-secondary-text">{{(lookupResult[0]?.last_update * 1000) | date:'dd/MMM/y HH:mm'}}</span> <span class="foreground-secondary-text">{{(lookupResult[0]?.last_update * 1000) | date:'dd/MMM/y HH:mm'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Amount (Sats)</h4> <h4 class="font-bold-500">Amount (Sats)</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.amount_msat / 1000 | number:'1.0-0'}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.amount_msat / 1000 | number:'1.0-0'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Base Fee (mSats)</h4> <h4 class="font-bold-500">Base Fee (mSats)</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.base_fee_millisatoshi | number}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.base_fee_millisatoshi | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Fee/Millionth</h4> <h4 class="font-bold-500">Fee/Millionth</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.fee_per_millionth | number}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.fee_per_millionth | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Channel Flags</h4> <h4 class="font-bold-500">Channel Flags</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.channel_flags | number}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.channel_flags | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Delay</h4> <h4 class="font-bold-500">Delay</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.delay | number}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.delay | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Max Htlc (mSat)</h4> <h4 class="font-bold-500">Max Htlc (mSat)</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.htlc_maximum_msat | number}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.htlc_maximum_msat | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Min Htlc (mSat)</h4> <h4 class="font-bold-500">Min Htlc (mSat)</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.htlc_minimum_msat | number}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.htlc_minimum_msat | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Message Flags</h4> <h4 class="font-bold-500">Message Flags</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.message_flags | number}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.message_flags | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Public</h4> <h4 class="font-bold-500">Public</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.public ? 'Yes' : 'No'}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.public ? 'Yes' : 'No'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Source</h4> <h4 class="font-bold-500">Source</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.source}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.source}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Destination</h4> <h4 class="font-bold-500">Destination</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.destination}}</span> <span class="foreground-secondary-text">{{lookupResult[0]?.destination}}</span>
@ -82,72 +82,72 @@
<h3 *ngIf="!node2_match" class="page-title font-bold-500">Node 2</h3> <h3 *ngIf="!node2_match" class="page-title font-bold-500">Node 2</h3>
<h3 *ngIf="node2_match" class="page-title font-bold-500">Node 2 (Your Node)</h3> <h3 *ngIf="node2_match" class="page-title font-bold-500">Node 2 (Your Node)</h3>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Short Channel ID</h4> <h4 class="font-bold-500">Short Channel ID</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.short_channel_id}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.short_channel_id}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Active</h4> <h4 class="font-bold-500">Active</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.active ? 'True' : 'False'}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.active ? 'True' : 'False'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Last Update</h4> <h4 class="font-bold-500">Last Update</h4>
<span class="foreground-secondary-text">{{(lookupResult[1]?.last_update * 1000) | date:'dd/MMM/y HH:mm'}}</span> <span class="foreground-secondary-text">{{(lookupResult[1]?.last_update * 1000) | date:'dd/MMM/y HH:mm'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Amount (Sats)</h4> <h4 class="font-bold-500">Amount (Sats)</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.amount_msat / 1000 | number:'1.0-0'}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.amount_msat / 1000 | number:'1.0-0'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Base Fee (mSats)</h4> <h4 class="font-bold-500">Base Fee (mSats)</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.base_fee_millisatoshi | number}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.base_fee_millisatoshi | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Fee/Millionth</h4> <h4 class="font-bold-500">Fee/Millionth</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.fee_per_millionth | number}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.fee_per_millionth | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Channel Flags</h4> <h4 class="font-bold-500">Channel Flags</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.channel_flags | number}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.channel_flags | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Delay</h4> <h4 class="font-bold-500">Delay</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.delay | number}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.delay | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Max Htlc (mSat)</h4> <h4 class="font-bold-500">Max Htlc (mSat)</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.htlc_maximum_msat | number}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.htlc_maximum_msat | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Min Htlc (mSat)</h4> <h4 class="font-bold-500">Min Htlc (mSat)</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.htlc_minimum_msat | number}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.htlc_minimum_msat | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Message Flags</h4> <h4 class="font-bold-500">Message Flags</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.message_flags | number}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.message_flags | number}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Public</h4> <h4 class="font-bold-500">Public</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.public ? 'Yes' : 'No'}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.public ? 'Yes' : 'No'}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Source</h4> <h4 class="font-bold-500">Source</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.source}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.source}}</span>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 class="font-bold-500">Destination</h4> <h4 class="font-bold-500">Destination</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.destination}}</span> <span class="foreground-secondary-text">{{lookupResult[1]?.destination}}</span>

@ -24,8 +24,8 @@
<span class="page-title font-bold-500">{{lookupFields[selectedFieldId].name}} Details</span> <span class="page-title font-bold-500">{{lookupFields[selectedFieldId].name}} Details</span>
</div> </div>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start center" [ngSwitch]="selectedFieldId"> <div fxLayout="row" fxFlex="100" fxLayoutAlign="start center" [ngSwitch]="selectedFieldId">
<span *ngSwitchCase="0" fxFlex="100"><div *ngIf="nodeLookupValue.nodeid !== ''; else errorBlock"><rtl-cln-node-lookup [lookupResult]="nodeLookupValue"></rtl-cln-node-lookup></div></span> <span *ngSwitchCase="0" fxFlex="100"><div *ngIf="nodeLookupValue.nodeid !== ''; else errorBlock"><rtl-cln-node-lookup [lookupResult]="nodeLookupValue" /></div></span>
<span *ngSwitchCase="1" fxFlex="100"><div *ngIf="channelLookupValue.length>0; else errorBlock"><rtl-cln-channel-lookup [lookupResult]="channelLookupValue"></rtl-cln-channel-lookup></div></span> <span *ngSwitchCase="1" fxFlex="100"><div *ngIf="channelLookupValue.length>0; else errorBlock"><rtl-cln-channel-lookup [lookupResult]="channelLookupValue" /></div></span>
<span *ngSwitchDefault> fxFlex="100"<h3>Error! Unable to find details!</h3></span> <span *ngSwitchDefault> fxFlex="100"<h3>Error! Unable to find details!</h3></span>
</div> </div>
</div> </div>

@ -41,7 +41,7 @@ export class CLNLookupsComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
if (window.history.state && window.history.state.lookupType) { if (window.history.state && (window.history.state.lookupType || window.history.state.lookupValue)) {
this.selectedFieldId = +window.history.state.lookupType || 0; this.selectedFieldId = +window.history.state.lookupType || 0;
this.lookupKey = window.history.state.lookupValue || ''; this.lookupKey = window.history.state.lookupValue || '';
} }

@ -1,5 +1,5 @@
<div *ngIf="lookupResult" fxLayout="column" class="mt-1"> <div *ngIf="lookupResult" fxLayout="column" class="mt-1">
<mat-divider class="mb-1"></mat-divider> <mat-divider class="mb-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="30"> <div fxFlex="30">
<h4 fxLayoutAlign="start" class="font-bold-500">Alias</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Alias</h4>
@ -10,7 +10,7 @@
<span class="foreground-secondary-text w-100">{{lookupResult?.nodeid}}</span> <span class="foreground-secondary-text w-100">{{lookupResult?.nodeid}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="30"> <div fxFlex="30">
<h4 fxLayoutAlign="start" class="font-bold-500">Last Update</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Last Update</h4>
@ -21,7 +21,7 @@
<span *ngFor="let featureDescription of featureDescriptions" class="foreground-secondary-text">{{featureDescription}}</span> <span *ngFor="let featureDescription of featureDescriptions" class="foreground-secondary-text">{{featureDescription}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="column"> <div fxLayout="column">
<h4 fxFlex="100" fxLayoutAlign="start" class="font-bold-500 mb-1">Addresses</h4> <h4 fxFlex="100" fxLayoutAlign="start" class="font-bold-500 mb-1">Addresses</h4>
<div fxLayout="row" fxFlex="100" class="table-container" [perfectScrollbar]> <div fxLayout="row" fxFlex="100" class="table-container" [perfectScrollbar]>
@ -45,7 +45,7 @@
<td *matCellDef="let address" mat-cell fxLayoutAlign="end center"> <td *matCellDef="let address" mat-cell fxLayoutAlign="end center">
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onConnectNode(address)">Connect</mat-option> <mat-option (click)="onConnectNode(address)">Connect</mat-option>
<mat-option rtlClipboard [payload]="lookupResult?.nodeid + '@' + address.address + ':' + address.port" (copied)="onCopyNodeURI($event)">Copy URI</mat-option> <mat-option rtlClipboard [payload]="lookupResult?.nodeid + '@' + address.address + ':' + address.port" (copied)="onCopyNodeURI($event)">Copy URI</mat-option>
</mat-select> </mat-select>

@ -1,7 +1,7 @@
<div fxLayout="column" fxFlex="100" class="padding-gap"> <div fxLayout="column" fxFlex="100" class="padding-gap">
<form #queryRoutesForm="ngForm" fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" (ngSubmit)="queryRoutesForm.form.valid && onQueryRoutes()"> <form #queryRoutesForm="ngForm" fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" (ngSubmit)="queryRoutesForm.form.valid && onQueryRoutes()">
<div fxFlex="100" class="alert alert-warn"> <div fxFlex="100" class="alert alert-warn">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>The actual routing fee on a payment can be different from the fee shown on query routes.</span> <span>The actual routing fee on a payment can be different from the fee shown on query routes.</span>
</div> </div>
<mat-form-field fxLayout="column" fxFlex="69" fxLayoutAlign="start end"> <mat-form-field fxLayout="column" fxFlex="69" fxLayoutAlign="start end">
@ -21,12 +21,12 @@
</form> </form>
<div fxLayout="row" fxLayoutAlign="start center" class="page-sub-title-container mt-2 mb-1"> <div fxLayout="row" fxLayoutAlign="start center" class="page-sub-title-container mt-2 mb-1">
<div fxFlex="70"> <div fxFlex="70">
<fa-icon class="page-title-img mr-1" [icon]="faRoute"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faRoute" />
<span class="page-title">Transaction Route</span> <span class="page-title">Transaction Route</span>
</div> </div>
</div> </div>
<div class="table-container mb-6" [perfectScrollbar]> <div class="table-container mb-6" [perfectScrollbar]>
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate" />
<table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="qrHops" [ngClass]="{'overflow-auto error-border': flgLoading[0]==='error','overflow-auto': true}"> <table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="qrHops" [ngClass]="{'overflow-auto error-border': flgLoading[0]==='error','overflow-auto': true}">
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<th *matHeaderCellDef mat-header-cell mat-sort-header>ID</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>ID</th>

@ -2,12 +2,12 @@
<div> <div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">Lightning</h4> <h4 fxLayoutAlign="start" class="dashboard-info-title">Lightning</h4>
<div class="overflow-wrap dashboard-info-value">{{balances.lightning | number:'1.0-0'}} Sats</div> <div class="overflow-wrap dashboard-info-value">{{balances.lightning | number:'1.0-0'}} Sats</div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{balances.lightning/balances.total*100}}"></mat-progress-bar> <mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{balances.lightning/balances.total*100}}" />
</div> </div>
<div> <div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">On-chain</h4> <h4 fxLayoutAlign="start" class="dashboard-info-title">On-chain</h4>
<div class="overflow-wrap dashboard-info-value">{{balances.onchain | number:'1.0-0'}} Sats</div> <div class="overflow-wrap dashboard-info-value">{{balances.onchain | number:'1.0-0'}} Sats</div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{balances.onchain/balances.total*100}}"></mat-progress-bar> <mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{balances.onchain/balances.total*100}}" />
</div> </div>
<div> <div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">Total</h4> <h4 fxLayoutAlign="start" class="dashboard-info-title">Total</h4>

@ -4,14 +4,14 @@
<div fxLayout="row" fxLayoutAlign="space-between start" class="w-100"> <div fxLayout="row" fxLayoutAlign="space-between start" class="w-100">
<mat-hint fxFlex="40" fxLayoutAlign="start center" class="font-size-90"><strong class="font-weight-900 mr-5px">Local:</strong>{{channelBalances?.localBalance || 0 | number:'1.0-0'}} Sats</mat-hint> <mat-hint fxFlex="40" fxLayoutAlign="start center" class="font-size-90"><strong class="font-weight-900 mr-5px">Local:</strong>{{channelBalances?.localBalance || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint fxFlex="20" fxLayoutAlign="center center" class="font-size-90"> <mat-hint fxFlex="20" fxLayoutAlign="center center" class="font-size-90">
<fa-icon class="mr-3px" matTooltip="Balance Score" [icon]="faBalanceScale"></fa-icon> <fa-icon class="mr-3px" matTooltip="Balance Score" [icon]="faBalanceScale" />
({{channelBalances?.balancedness || 0 | number}}) ({{channelBalances?.balancedness || 0 | number}})
</mat-hint> </mat-hint>
<mat-hint fxFlex="40" fxLayoutAlign="end center" class="font-size-90"><strong class="font-weight-900 mr-5px">Remote:</strong>{{channelBalances?.remoteBalance || 0 | number:'1.0-0'}} Sats</mat-hint> <mat-hint fxFlex="40" fxLayoutAlign="end center" class="font-size-90"><strong class="font-weight-900 mr-5px">Remote:</strong>{{channelBalances?.remoteBalance || 0 | number:'1.0-0'}} Sats</mat-hint>
</div> </div>
<mat-progress-bar class="dashboard-progress-bar this-channel-bar" mode="determinate" color="accent" value="{{channelBalances?.localBalance && channelBalances?.localBalance > 0 ? ((+channelBalances?.localBalance/((+channelBalances?.localBalance)+(+channelBalances?.remoteBalance)))*100) : 0}}"></mat-progress-bar> <mat-progress-bar class="dashboard-progress-bar this-channel-bar" mode="determinate" color="accent" value="{{channelBalances?.localBalance && channelBalances?.localBalance > 0 ? ((+channelBalances?.localBalance/((+channelBalances?.localBalance)+(+channelBalances?.remoteBalance)))*100) : 0}}" />
</div> </div>
<div fxLayout="column" fxFlex="3" fxLayoutAlign="end stretch"><mat-divider class="dashboard-divider"></mat-divider></div> <div fxLayout="column" fxFlex="3" fxLayoutAlign="end stretch"><mat-divider class="dashboard-divider" /></div>
<div class="channels-capacity-scroll" [perfectScrollbar]> <div class="channels-capacity-scroll" [perfectScrollbar]>
<div *ngIf="activeChannels && activeChannels.length > 0; else noChannelBlock" fxLayout="column"fxFlex="100"> <div *ngIf="activeChannels && activeChannels.length > 0; else noChannelBlock" fxLayout="column"fxFlex="100">
<div *ngFor="let channel of activeChannels" class="mt-2"> <div *ngFor="let channel of activeChannels" class="mt-2">
@ -21,12 +21,12 @@
<div fxLayout="row" fxLayoutAlign="space-between start" class="w-100"> <div fxLayout="row" fxLayoutAlign="space-between start" class="w-100">
<mat-hint fxFlex="40" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Local:</strong>{{channel.to_us_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint> <mat-hint fxFlex="40" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Local:</strong>{{channel.to_us_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint fxFlex="20" fxLayoutAlign="center center" class="font-size-90 color-primary"> <mat-hint fxFlex="20" fxLayoutAlign="center center" class="font-size-90 color-primary">
<fa-icon class="color-primary mr-3px" matTooltip="Balance Score" [icon]="faBalanceScale"></fa-icon> <fa-icon class="color-primary mr-3px" matTooltip="Balance Score" [icon]="faBalanceScale" />
({{channel.balancedness || 0 | number}}) ({{channel.balancedness || 0 | number}})
</mat-hint> </mat-hint>
<mat-hint fxFlex="40" fxLayoutAlign="end center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Remote:</strong>{{channel.to_them_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint> <mat-hint fxFlex="40" fxLayoutAlign="end center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Remote:</strong>{{channel.to_them_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
</div> </div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{channel.to_us_msat && channel.to_us_msat > 0 ? ((channel.to_us_msat/((channel.to_us_msat)+(channel.to_them_msat)))*100) : 0}}"></mat-progress-bar> <mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{channel.to_us_msat && channel.to_us_msat > 0 ? ((channel.to_us_msat/((channel.to_us_msat)+(channel.to_them_msat)))*100) : 0}}" />
</div> </div>
</div> </div>
</div> </div>

@ -2,9 +2,9 @@
<div fxLayout="column" fxFlex="8" fxLayoutAlign="end start"> <div fxLayout="column" fxFlex="8" fxLayoutAlign="end start">
<span class="dashboard-capacity-header this-channel-capacity">Total Capacity</span> <span class="dashboard-capacity-header this-channel-capacity">Total Capacity</span>
<mat-hint class="font-size-90">{{totalLiquidity | number:'1.0-0'}} Sats</mat-hint> <mat-hint class="font-size-90">{{totalLiquidity | number:'1.0-0'}} Sats</mat-hint>
<mat-progress-bar class="dashboard-progress-bar this-channel-bar" mode="determinate" color="accent" value="100"></mat-progress-bar> <mat-progress-bar class="dashboard-progress-bar this-channel-bar" mode="determinate" color="accent" value="100" />
</div> </div>
<div fxLayout="column" fxFlex="3" fxLayoutAlign="end stretch"><mat-divider class="dashboard-divider"></mat-divider></div> <div fxLayout="column" fxFlex="3" fxLayoutAlign="end stretch"><mat-divider class="dashboard-divider" /></div>
<div fxLayout="column" fxFlex.gt-sm="88" fxFlex="84" fxLayoutAlign="start start" [perfectScrollbar]> <div fxLayout="column" fxFlex.gt-sm="88" fxFlex="84" fxLayoutAlign="start start" [perfectScrollbar]>
<div *ngIf="activeChannels && activeChannels.length > 0; else noChannelBlock" fxLayout="column" fxFlex="100"class="w-100"> <div *ngIf="activeChannels && activeChannels.length > 0; else noChannelBlock" fxLayout="column" fxFlex="100"class="w-100">
<div *ngFor="let channel of activeChannels" class="mt-2"> <div *ngFor="let channel of activeChannels" class="mt-2">
@ -15,8 +15,8 @@
<mat-hint *ngIf="direction === 'In'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.to_them_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint> <mat-hint *ngIf="direction === 'In'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.to_them_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint *ngIf="direction === 'Out'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.to_us_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint> <mat-hint *ngIf="direction === 'Out'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.to_us_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
</div> </div>
<mat-progress-bar *ngIf="direction === 'In'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((channel.to_them_msat/1000 || 0)/(totalLiquidity) * 100) : 0}}"></mat-progress-bar> <mat-progress-bar *ngIf="direction === 'In'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((channel.to_them_msat/1000 || 0)/(totalLiquidity) * 100) : 0}}" />
<mat-progress-bar *ngIf="direction === 'Out'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((channel.to_us_msat/1000 || 0)/(totalLiquidity) * 100) : 0}}"></mat-progress-bar> <mat-progress-bar *ngIf="direction === 'Out'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((channel.to_us_msat/1000 || 0)/(totalLiquidity) * 100) : 0}}" />
</div> </div>
</div> </div>
</div> </div>

@ -10,6 +10,12 @@
<h4 fxLayoutAlign="start" class="dashboard-info-title">Transactions</h4> <h4 fxLayoutAlign="start" class="dashboard-info-title">Transactions</h4>
<div class="overflow-wrap dashboard-info-value">{{fees?.totalTxCount | number}}</div> <div class="overflow-wrap dashboard-info-value">{{fees?.totalTxCount | number}}</div>
</div> </div>
<div *ngIf="!fees?.totalTxCount">
<h4 fxLayoutAlign="start" class="dashboard-info-title">Transactions</h4>
<a class="overflow-wrap dashboard-info-value" [routerLink]="['../routing']">
Go to Routing
</a>
</div>
</div> </div>
</div> </div>
<ng-template #errorBlock> <ng-template #errorBlock>

@ -1,6 +1,6 @@
<div *ngIf="selNode?.userPersona === userPersonaEnum.OPERATOR; else merchantDashboard"fxLayout="column"> <div *ngIf="selNode?.userPersona === userPersonaEnum.OPERATOR; else merchantDashboard"fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start start" class="page-title-container mb-2"> <div fxLayout="row" fxLayoutAlign="start start" class="page-title-container mb-2">
<fa-icon class="page-title-img mr-1" [icon]="apiCallStatusNodeInfo.status === apiCallStatusEnum.ERROR ? faFrown : faSmile"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="apiCallStatusNodeInfo.status === apiCallStatusEnum.ERROR ? faFrown : faSmile" />
<span class="page-title">{{apiCallStatusNodeInfo.status === apiCallStatusEnum.COMPLETED ? 'Welcome ' + information.alias + '! Your node is up and running.' : apiCallStatusNodeInfo.status === apiCallStatusEnum.INITIATED ? 'Wait! Getting your node information...' : 'Error! Please check the server connection.'}}</span> <span class="page-title">{{apiCallStatusNodeInfo.status === apiCallStatusEnum.COMPLETED ? 'Welcome ' + information.alias + '! Your node is up and running.' : apiCallStatusNodeInfo.status === apiCallStatusEnum.INITIATED ? 'Wait! Getting your node information...' : 'Error! Please check the server connection.'}}</span>
</div> </div>
<mat-grid-list cols="10" gutterSize="20px" [rowHeight]="operatorCardHeight"> <mat-grid-list cols="10" gutterSize="20px" [rowHeight]="operatorCardHeight">
@ -9,7 +9,7 @@
<mat-card-header> <mat-card-header>
<mat-card-title fxLayoutAlign="space-between center"> <mat-card-title fxLayoutAlign="space-between center">
<div> <div>
<fa-icon class="mr-1" [icon]="card.icon"></fa-icon> <fa-icon class="mr-1" [icon]="card.icon" />
<span>{{card.title}}</span> <span>{{card.title}}</span>
</div> </div>
<div> <div>
@ -36,13 +36,13 @@
(card.id === 'fee' && (apiCallStatusFees.status === apiCallStatusEnum.INITIATED || apiCallStatusChannels.status === apiCallStatusEnum.INITIATED || apiCallStatusFHistory.status === apiCallStatusEnum.INITIATED)) || (card.id === 'fee' && (apiCallStatusFees.status === apiCallStatusEnum.INITIATED || apiCallStatusChannels.status === apiCallStatusEnum.INITIATED || apiCallStatusFHistory.status === apiCallStatusEnum.INITIATED)) ||
(card.id === 'status' && (apiCallStatusNodeInfo.status === apiCallStatusEnum.INITIATED || apiCallStatusChannels.status === apiCallStatusEnum.INITIATED || apiCallStatusLRBal.status === apiCallStatusEnum.INITIATED))" (card.id === 'status' && (apiCallStatusNodeInfo.status === apiCallStatusEnum.INITIATED || apiCallStatusChannels.status === apiCallStatusEnum.INITIATED || apiCallStatusLRBal.status === apiCallStatusEnum.INITIATED))"
mode="indeterminate" mode="indeterminate"
></mat-progress-bar> />
<div fxLayout="column" fxFlex="100" [ngSwitch]="card.id"> <div fxLayout="column" fxFlex="100" [ngSwitch]="card.id">
<rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information" [showColorFieldSeparately]="false"></rtl-cln-node-info> <rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information" [showColorFieldSeparately]="false" />
<rtl-cln-balances-info *ngSwitchCase="'balance'" fxFlex="100" [balances]="balances" [errorMessage]="errorMessages[2] + ' ' + errorMessages[3]"></rtl-cln-balances-info> <rtl-cln-balances-info *ngSwitchCase="'balance'" fxFlex="100" [balances]="balances" [errorMessage]="errorMessages[2] + ' ' + errorMessages[3]" />
<rtl-cln-channel-capacity-info *ngSwitchCase="'capacity'" fxFlex="100" [sortBy]="sortField" [channelBalances]="channelBalances" [activeChannels]="activeChannelsCapacity" [errorMessage]="errorMessages[4] + ' ' + errorMessages[3]"></rtl-cln-channel-capacity-info> <rtl-cln-channel-capacity-info *ngSwitchCase="'capacity'" fxFlex="100" [sortBy]="sortField" [channelBalances]="channelBalances" [activeChannels]="activeChannelsCapacity" [errorMessage]="errorMessages[4] + ' ' + errorMessages[3]" />
<rtl-cln-fee-info *ngSwitchCase="'fee'" fxFlex="100" [fees]="fees" [errorMessage]="errorMessages[1] + ' ' + errorMessages[4] + ' ' + errorMessages[5]"></rtl-cln-fee-info> <rtl-cln-fee-info *ngSwitchCase="'fee'" fxFlex="100" [fees]="fees" [errorMessage]="errorMessages[1] + ' ' + errorMessages[4] + ' ' + errorMessages[5]" />
<rtl-cln-channel-status-info *ngSwitchCase="'status'" fxFlex="100" [channelsStatus]="channelsStatus" [errorMessage]="errorMessages[0] + ' ' + errorMessages[3] + ' ' + errorMessages[4]"></rtl-cln-channel-status-info> <rtl-cln-channel-status-info *ngSwitchCase="'status'" fxFlex="100" [channelsStatus]="channelsStatus" [errorMessage]="errorMessages[0] + ' ' + errorMessages[3] + ' ' + errorMessages[4]" />
<h3 *ngSwitchDefault>Error! Unable to find information!</h3> <h3 *ngSwitchDefault>Error! Unable to find information!</h3>
</div> </div>
</mat-card-content> </mat-card-content>
@ -52,7 +52,7 @@
</div> </div>
<ng-template #merchantDashboard> <ng-template #merchantDashboard>
<div fxLayout="row" fxLayoutAlign="start end" class="page-title-container mb-2"> <div fxLayout="row" fxLayoutAlign="start end" class="page-title-container mb-2">
<fa-icon class="page-title-img mr-1" [icon]="faSmile"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faSmile" />
<span class="page-title">Welcome {{information.alias}}! Your node is up and running.</span> <span class="page-title">Welcome {{information.alias}}! Your node is up and running.</span>
</div> </div>
<mat-grid-list cols="6" gutterSize="20px" [rowHeight]="merchantCardHeight"> <mat-grid-list cols="6" gutterSize="20px" [rowHeight]="merchantCardHeight">
@ -61,7 +61,7 @@
<mat-card-header *ngIf="card.id !== 'transactions'"> <mat-card-header *ngIf="card.id !== 'transactions'">
<mat-card-title fxLayoutAlign="space-between center"> <mat-card-title fxLayoutAlign="space-between center">
<div> <div>
<fa-icon class="mr-1" [icon]="card.icon"></fa-icon> <fa-icon class="mr-1" [icon]="card.icon" />
<span>{{card.title}}</span> <span>{{card.title}}</span>
</div> </div>
<div> <div>
@ -83,16 +83,16 @@
(card.id === 'balance' && (apiCallStatusBalance.status === apiCallStatusEnum.INITIATED || apiCallStatusLRBal.status === apiCallStatusEnum.INITIATED)) || (card.id === 'balance' && (apiCallStatusBalance.status === apiCallStatusEnum.INITIATED || apiCallStatusLRBal.status === apiCallStatusEnum.INITIATED)) ||
((card.id === 'inboundLiq' || card.id === 'outboundLiq') && apiCallStatusChannels.status === apiCallStatusEnum.INITIATED)" ((card.id === 'inboundLiq' || card.id === 'outboundLiq') && apiCallStatusChannels.status === apiCallStatusEnum.INITIATED)"
mode="indeterminate" mode="indeterminate"
></mat-progress-bar> />
<div fxLayout="column" fxFlex="100" [ngSwitch]="card.id"> <div fxLayout="column" fxFlex="100" [ngSwitch]="card.id">
<rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information"></rtl-cln-node-info> <rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information" />
<rtl-cln-balances-info *ngSwitchCase="'balance'" fxFlex="100" [balances]="balances" [errorMessage]="errorMessages[2] + ' ' + errorMessages[3]"></rtl-cln-balances-info> <rtl-cln-balances-info *ngSwitchCase="'balance'" fxFlex="100" [balances]="balances" [errorMessage]="errorMessages[2] + ' ' + errorMessages[3]" />
<rtl-cln-channel-liquidity-info *ngSwitchCase="'inboundLiq'" fxFlex="100" [direction]="'In'" [totalLiquidity]="totalInboundLiquidity" [activeChannels]="allInboundChannels" [errorMessage]="errorMessages[4]"></rtl-cln-channel-liquidity-info> <rtl-cln-channel-liquidity-info *ngSwitchCase="'inboundLiq'" fxFlex="100" [direction]="'In'" [totalLiquidity]="totalInboundLiquidity" [activeChannels]="allInboundChannels" [errorMessage]="errorMessages[4]" />
<rtl-cln-channel-liquidity-info *ngSwitchCase="'outboundLiq'" fxFlex="100" [direction]="'Out'" [totalLiquidity]="totalOutboundLiquidity" [activeChannels]="allOutboundChannels" [errorMessage]="errorMessages[4]"></rtl-cln-channel-liquidity-info> <rtl-cln-channel-liquidity-info *ngSwitchCase="'outboundLiq'" fxFlex="100" [direction]="'Out'" [totalLiquidity]="totalOutboundLiquidity" [activeChannels]="allOutboundChannels" [errorMessage]="errorMessages[4]" />
<span *ngSwitchCase="'transactions'" fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start"> <span *ngSwitchCase="'transactions'" fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start">
<mat-tab-group mat-stretch-tabs="false" mat-align-tabs="start" fxLayout="column" class="dashboard-tabs-group"> <mat-tab-group mat-stretch-tabs="false" mat-align-tabs="start" fxLayout="column" class="dashboard-tabs-group">
<mat-tab label="Receive"><rtl-cln-lightning-invoices-table class="h-100" [calledFrom]="'home'"></rtl-cln-lightning-invoices-table></mat-tab> <mat-tab label="Receive"><rtl-cln-lightning-invoices-table class="h-100" [calledFrom]="'home'" /></mat-tab>
<mat-tab label="Pay"><rtl-cln-lightning-payments [calledFrom]="'home'"></rtl-cln-lightning-payments></mat-tab> <mat-tab label="Pay"><rtl-cln-lightning-payments [calledFrom]="'home'" /></mat-tab>
</mat-tab-group> </mat-tab-group>
<div class="underline"> <div class="underline">
<button mat-icon-button class="more-button" aria-label="Toggle menu" [matMenuTriggerFor]="menuTransactions"> <button mat-icon-button class="more-button" aria-label="Toggle menu" [matMenuTriggerFor]="menuTransactions">

@ -1,5 +1,5 @@
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faBullhorn"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faBullhorn" />
<span class="page-title">Liquidity Ads</span> <span class="page-title">Liquidity Ads</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x"> <div fxLayout="column" class="padding-gap-x">
@ -8,7 +8,7 @@
<div fxLayout="column" fxLayoutAlign="space-between stretch"> <div fxLayout="column" fxLayoutAlign="space-between stretch">
<form #formAsk="ngForm" fxFlex="100" fxLayout="column" fxLayoutAlign="start stretch" fxLayoutAlign.gt-sm="space-between stretch" fxLayout.gt-sm="row wrap"> <form #formAsk="ngForm" fxFlex="100" fxLayout="column" fxLayoutAlign="start stretch" fxLayoutAlign.gt-sm="space-between stretch" fxLayout.gt-sm="row wrap">
<div fxFlex.gt-xs="100" fxLayout="row" class="alert alert-warn"> <div fxFlex.gt-xs="100" fxLayout="row" class="alert alert-warn">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>Ads should be supplemented with additional research of the node, before buying liquidity.</span> <span>Ads should be supplemented with additional research of the node, before buying liquidity.</span>
</div> </div>
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="page-sub-title-container mt-1"> <div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="page-sub-title-container mt-1">
@ -50,7 +50,7 @@
</form> --> </form> -->
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container mt-2"> <div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container mt-2">
<div fxFlex="70"> <div fxFlex="70">
<fa-icon class="page-title-img mr-1" [icon]="faUsers"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faUsers" />
<span class="page-title">Liquidity Providing Peers</span> <span class="page-title">Liquidity Providing Peers</span>
</div> </div>
<div fxFlex.gt-xs="30" fxLayoutAlign.gt-xs="space-between center" fxLayout="row" fxLayoutAlign="space-between stretch"> <div fxFlex.gt-xs="30" fxLayoutAlign.gt-xs="space-between center" fxLayout="row" fxLayoutAlign="space-between stretch">
@ -67,7 +67,7 @@
</div> </div>
</div> </div>
<div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]> <div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="listNodesCallStatus === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="listNodesCallStatus === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="liquidityNodes" [ngClass]="{'error-border': errorMessage !== ''}"> <table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="liquidityNodes" [ngClass]="{'error-border': errorMessage !== ''}">
<ng-container matColumnDef="alias"> <ng-container matColumnDef="alias">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Alias</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Alias</th>
@ -138,7 +138,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -146,7 +146,7 @@
<td *matCellDef="let lqNode" mat-cell fxLayoutAlign="end center"> <td *matCellDef="let lqNode" mat-cell fxLayoutAlign="end center">
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onViewLeaseInfo(lqNode)">View Info</mat-option> <mat-option (click)="onViewLeaseInfo(lqNode)">View Info</mat-option>
<mat-option (click)="onOpenChannel(lqNode)">Open Channel</mat-option> <mat-option (click)="onOpenChannel(lqNode)">Open Channel</mat-option>
<mat-option (click)="viewLeaseOn(lqNode, 'LN')">View on Lnrouter</mat-option> <mat-option (click)="viewLeaseOn(lqNode, 'LN')">View on Lnrouter</mat-option>
@ -167,7 +167,7 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -8,7 +8,7 @@
</mat-card-header> </mat-card-header>
<mat-card-content class="padding-gap-x-large"> <mat-card-content class="padding-gap-x-large">
<form #form="ngForm" fxLayout="column"> <form #form="ngForm" fxLayout="column">
<ng-container *ngTemplateOutlet="nodeDetailsExpansionBlock"></ng-container> <ng-container *ngTemplateOutlet="nodeDetailsExpansionBlock" />
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayoutAlign.gt-sm="space-between center" fxLayout.gt-sm="row wrap"> <div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayoutAlign.gt-sm="space-between center" fxLayout.gt-sm="row wrap">
<mat-form-field fxLayout="column" fxFlex="30" fxLayoutAlign="start end"> <mat-form-field fxLayout="column" fxFlex="30" fxLayoutAlign="start end">
<mat-label>Requested Amount</mat-label> <mat-label>Requested Amount</mat-label>
@ -36,7 +36,7 @@
<span>Total cost to lease {{node.channel_opening_fee | number}} (Sats)</span> <span>Total cost to lease {{node.channel_opening_fee | number}} (Sats)</span>
</div> </div>
<div *ngIf="channelConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-2"> <div *ngIf="channelConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-2">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span *ngIf="channelConnectionError !== ''">{{channelConnectionError}}</span> <span *ngIf="channelConnectionError !== ''">{{channelConnectionError}}</span>
</div> </div>
<div class="mt-2" fxLayout="row" fxLayoutAlign="end center"> <div class="mt-2" fxLayout="row" fxLayoutAlign="end center">
@ -62,14 +62,14 @@
<span class="foreground-secondary-text">{{node.nodeid}}</span> <span class="foreground-secondary-text">{{node.nodeid}}</span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Last Timestamp</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Last Timestamp</h4>
<span class="overflow-wrap foreground-secondary-text">{{(node.last_timestamp * 1000) | date:'dd/MMM/y HH:mm'}}</span> <span class="overflow-wrap foreground-secondary-text">{{(node.last_timestamp * 1000) | date:'dd/MMM/y HH:mm'}}</span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="column" fxLayoutAlign="start stretch"> <div fxLayout="column" fxLayoutAlign="start stretch">
<h4 fxFlex="100" class="font-bold-500 mb-1">Addresses</h4> <h4 fxFlex="100" class="font-bold-500 mb-1">Addresses</h4>
<div class="table-container"> <div class="table-container">

@ -4,7 +4,7 @@
<div fxLayout="column" fxLayoutAlign="stretch start" fxFlex="100" class="h-100"> <div fxLayout="column" fxLayoutAlign="stretch start" fxFlex="100" class="h-100">
<div fxLayout="row" fxLayoutAlign="start start" class="w-100"> <div fxLayout="row" fxLayoutAlign="start start" class="w-100">
<div fxLayout="row" fxLayoutAlign="start start" class="page-title-container pl-2"> <div fxLayout="row" fxLayoutAlign="start start" class="page-title-container pl-2">
<fa-icon class="mr-1" [icon]="card.icon"></fa-icon> <fa-icon class="mr-1" [icon]="card.icon" />
<span>{{card.title}}</span> <span>{{card.title}}</span>
</div> </div>
</div> </div>
@ -25,14 +25,14 @@
(card.id === 'feeRatesKW' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED) || (card.id === 'feeRatesKW' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED) ||
(card.id === 'onChainFeeEstimates' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED)" (card.id === 'onChainFeeEstimates' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED)"
mode="indeterminate" mode="indeterminate"
></mat-progress-bar> />
<div fxLayout="column" fxFlex="100" [ngSwitch]="card.id"> <div fxLayout="column" fxFlex="100" [ngSwitch]="card.id">
<rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information" [showColorFieldSeparately]="false"></rtl-cln-node-info> <rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information" [showColorFieldSeparately]="false" />
<rtl-cln-channel-status-info *ngSwitchCase="'status'" fxFlex="100" [channelsStatus]="channelsStatus" [errorMessage]="errorMessages[0] + ' ' + errorMessages[2]"></rtl-cln-channel-status-info> <rtl-cln-channel-status-info *ngSwitchCase="'status'" fxFlex="100" [channelsStatus]="channelsStatus" [errorMessage]="errorMessages[0] + ' ' + errorMessages[2]" />
<rtl-cln-fee-info *ngSwitchCase="'fee'" fxFlex="100" [fees]="fees" [errorMessage]="errorMessages[1] + ' ' + errorMessages[3] + ' ' + errorMessages[4]"></rtl-cln-fee-info> <rtl-cln-fee-info *ngSwitchCase="'fee'" fxFlex="100" [fees]="fees" [errorMessage]="errorMessages[1] + ' ' + errorMessages[3] + ' ' + errorMessages[4]" />
<rtl-cln-fee-rates *ngSwitchCase="'feeRatesKB'" class="h-100" [feeRates]="feeRatesPerKB" [feeRateStyle]="'KB'" [errorMessage]="errorMessages[5]"></rtl-cln-fee-rates> <rtl-cln-fee-rates *ngSwitchCase="'feeRatesKB'" class="h-100" [feeRates]="feeRatesPerKB" [feeRateStyle]="'KB'" [errorMessage]="errorMessages[5]" />
<rtl-cln-fee-rates *ngSwitchCase="'feeRatesKW'" class="h-100" [feeRates]="feeRatesPerKW" [feeRateStyle]="'KW'" [errorMessage]="errorMessages[6]"></rtl-cln-fee-rates> <rtl-cln-fee-rates *ngSwitchCase="'feeRatesKW'" class="h-100" [feeRates]="feeRatesPerKW" [feeRateStyle]="'KW'" [errorMessage]="errorMessages[6]" />
<rtl-cln-onchain-fee-estimates *ngSwitchCase="'onChainFeeEstimates'" class="h-100" [feeRates]="feeRatesPerKW" [errorMessage]="errorMessages[5]"></rtl-cln-onchain-fee-estimates> <rtl-cln-onchain-fee-estimates *ngSwitchCase="'onChainFeeEstimates'" class="h-100" [feeRates]="feeRatesPerKW" [errorMessage]="errorMessages[5]" />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
@ -45,7 +45,7 @@
<div fxLayout="column" fxLayoutAlign="stretch start" fxFlex="100" class="h-100"> <div fxLayout="column" fxLayoutAlign="stretch start" fxFlex="100" class="h-100">
<div fxLayout="row" fxLayoutAlign="start start" class="w-100"> <div fxLayout="row" fxLayoutAlign="start start" class="w-100">
<div fxLayout="row" fxLayoutAlign="start start" class="page-title-container pl-15px"> <div fxLayout="row" fxLayoutAlign="start start" class="page-title-container pl-15px">
<fa-icon class="mr-1" [icon]="card.icon"></fa-icon> <fa-icon class="mr-1" [icon]="card.icon" />
<span>{{card.title}}</span> <span>{{card.title}}</span>
</div> </div>
</div> </div>
@ -66,14 +66,14 @@
(card.id === 'feeRatesKW' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED) || (card.id === 'feeRatesKW' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED) ||
(card.id === 'onChainFeeEstimates' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED)" (card.id === 'onChainFeeEstimates' && apiCallStatusPerKW.status === apiCallStatusEnum.INITIATED)"
mode="indeterminate" mode="indeterminate"
></mat-progress-bar> />
<div fxLayout="column" fxFlex="100" [ngSwitch]="card.id"> <div fxLayout="column" fxFlex="100" [ngSwitch]="card.id">
<rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information" [showColorFieldSeparately]="false"></rtl-cln-node-info> <rtl-cln-node-info *ngSwitchCase="'node'" fxFlex="100" [information]="information" [showColorFieldSeparately]="false" />
<rtl-cln-channel-status-info *ngSwitchCase="'status'" fxFlex="100" [channelsStatus]="channelsStatus" [errorMessage]="errorMessages[0] + ' ' + errorMessages[2]"></rtl-cln-channel-status-info> <rtl-cln-channel-status-info *ngSwitchCase="'status'" fxFlex="100" [channelsStatus]="channelsStatus" [errorMessage]="errorMessages[0] + ' ' + errorMessages[2]" />
<rtl-cln-fee-info *ngSwitchCase="'fee'" fxFlex="100" [fees]="fees" [errorMessage]="errorMessages[1] + ' ' + errorMessages[3] + ' ' + errorMessages[4]"></rtl-cln-fee-info> <rtl-cln-fee-info *ngSwitchCase="'fee'" fxFlex="100" [fees]="fees" [errorMessage]="errorMessages[1] + ' ' + errorMessages[3] + ' ' + errorMessages[4]" />
<rtl-cln-fee-rates *ngSwitchCase="'feeRatesKB'" class="h-100" [feeRates]="feeRatesPerKB" [feeRateStyle]="'KB'" [errorMessage]="errorMessages[5]"></rtl-cln-fee-rates> <rtl-cln-fee-rates *ngSwitchCase="'feeRatesKB'" class="h-100" [feeRates]="feeRatesPerKB" [feeRateStyle]="'KB'" [errorMessage]="errorMessages[5]" />
<rtl-cln-fee-rates *ngSwitchCase="'feeRatesKW'" class="h-100" [feeRates]="feeRatesPerKW" [feeRateStyle]="'KW'" [errorMessage]="errorMessages[5]"></rtl-cln-fee-rates> <rtl-cln-fee-rates *ngSwitchCase="'feeRatesKW'" class="h-100" [feeRates]="feeRatesPerKW" [feeRateStyle]="'KW'" [errorMessage]="errorMessages[5]" />
<rtl-cln-onchain-fee-estimates *ngSwitchCase="'onChainFeeEstimates'" class="h-100" [feeRates]="feeRatesPerKW" [errorMessage]="errorMessages[5]"></rtl-cln-onchain-fee-estimates> <rtl-cln-onchain-fee-estimates *ngSwitchCase="'onChainFeeEstimates'" class="h-100" [feeRates]="feeRatesPerKW" [errorMessage]="errorMessages[5]" />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -18,7 +18,7 @@ import { getNewAddress } from '../../store/cln.actions';
export class CLNOnChainReceiveComponent { export class CLNOnChainReceiveComponent {
public addressTypes = ADDRESS_TYPES; public addressTypes = ADDRESS_TYPES;
public selectedAddressType = ADDRESS_TYPES[0]; public selectedAddressType = ADDRESS_TYPES[2];
public newAddress = ''; public newAddress = '';
constructor(private store: Store<RTLState>, private clnEffects: CLNEffects) { } constructor(private store: Store<RTLState>, private clnEffects: CLNEffects) { }

@ -43,7 +43,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div fxFlex="48" fxLayout="row" fxLayoutAlign="start center"> <div fxFlex="48" fxLayout="row" fxLayoutAlign="start center">
<mat-checkbox fxFlex="7" tabindex="5" color="primary" name="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}" [(ngModel)]="flgMinConf" (change)="flgMinConf ? selFeeRate=null : minConfValue=null"></mat-checkbox> <mat-checkbox fxFlex="7" tabindex="5" color="primary" name="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}" [(ngModel)]="flgMinConf" (change)="flgMinConf ? selFeeRate=null : minConfValue=null" />
<mat-form-field fxLayout="column" fxFlex="93"> <mat-form-field fxLayout="column" fxFlex="93">
<mat-label>Min Confirmation Blocks</mat-label> <mat-label>Min Confirmation Blocks</mat-label>
<input #blocks="ngModel" matInput type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="flgMinConf" [disabled]="!flgMinConf" [(ngModel)]="minConfValue"> <input #blocks="ngModel" matInput type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="flgMinConf" [disabled]="!flgMinConf" [(ngModel)]="minConfValue">
@ -77,7 +77,7 @@
</mat-expansion-panel> </mat-expansion-panel>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch"></div> <div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch"></div>
<div *ngIf="sendFundError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="sendFundError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span *ngIf="sendFundError !== ''">{{sendFundError}}</span> <span *ngIf="sendFundError !== ''">{{sendFundError}}</span>
</div> </div>
<div class="mt-2" fxLayout="row" fxFlex="100" fxLayoutAlign="end center"> <div class="mt-2" fxLayout="row" fxFlex="100" fxLayoutAlign="end center">
@ -134,7 +134,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div fxFlex="48" fxLayout="row" fxLayoutAlign="start center"> <div fxFlex="48" fxLayout="row" fxLayoutAlign="start center">
<mat-checkbox fxFlex="7" tabindex="5" color="primary" formControlName="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}"></mat-checkbox> <mat-checkbox fxFlex="7" tabindex="5" color="primary" formControlName="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}" />
<mat-form-field fxLayout="column" fxFlex="93"> <mat-form-field fxLayout="column" fxFlex="93">
<mat-label>Min Confirmation Blocks</mat-label> <mat-label>Min Confirmation Blocks</mat-label>
<input matInput formControlName="minConfValue" type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="sendFundFormGroup.controls.flgMinConf.value"> <input matInput formControlName="minConfValue" type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="sendFundFormGroup.controls.flgMinConf.value">
@ -153,11 +153,11 @@
<ng-template matStepLabel>{{confirmFormLabel}}</ng-template> <ng-template matStepLabel>{{confirmFormLabel}}</ng-template>
<div fxLayout="column"> <div fxLayout="column">
<div fxFlex="100" class="w-100 alert alert-warn"> <div fxFlex="100" class="w-100 alert alert-warn">
<fa-icon class="mt-1 mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mt-1 mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>You are about to sweep all funds from RTL. Are you sure?</span> <span>You are about to sweep all funds from RTL. Are you sure?</span>
</div> </div>
<div *ngIf="sendFundError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="sendFundError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span *ngIf="sendFundError !== ''">{{sendFundError}}</span> <span *ngIf="sendFundError !== ''">{{sendFundError}}</span>
</div> </div>
<div class="mt-2" fxLayout="row" fxLayoutAlign="start center" fxFlex="100"> <div class="mt-2" fxLayout="row" fxLayoutAlign="start center" fxFlex="100">

@ -1,30 +1,30 @@
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faChartPie"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faChartPie" />
<span class="page-title">On-chain Balance</span> <span class="page-title">On-chain Balance</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x mb-4"> <div fxLayout="column" class="padding-gap-x mb-4">
<mat-card> <mat-card>
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<rtl-currency-unit-converter [values]="balances"></rtl-currency-unit-converter> <rtl-currency-unit-converter [values]="balances" />
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faExchangeAlt"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faExchangeAlt" />
<span class="page-title">On-chain Transactions</span> <span class="page-title">On-chain Transactions</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x"> <div fxLayout="column" class="padding-gap-x">
<mat-card> <mat-card>
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel"> <nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel">
<div *ngFor="let link of links" role="tab" mat-tab-link class="mat-tab-label" [active]="activeLink === link?.link" [routerLink]="[link?.link, selectedTable?.name]" (click)="activeLink = link?.link">{{link?.name}}</div> <div *ngFor="let link of links" tabindex="1" role="tab" mat-tab-link class="mat-tab-label" [active]="activeLink === link?.link" [routerLink]="[link?.link, selectedTable?.name]" (click)="activeLink = link?.link">{{link?.name}}</div>
</nav> </nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel> <mat-tab-nav-panel #tabPanel />
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="mat-tab-body-wrapper"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="mat-tab-body-wrapper">
<router-outlet></router-outlet> <router-outlet />
</div> </div>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large">
<rtl-cln-utxo-tables fxLayout="row" fxFlex="100" [selectedTableIndex]="selectedTable?.id" (selectedTableIndexChange)="onSelectedTableIndexChanged($event)"></rtl-cln-utxo-tables> <rtl-cln-utxo-tables fxLayout="row" fxFlex="100" [selectedTableIndex]="selectedTable?.id" (selectedTableIndexChange)="onSelectedTableIndexChanged($event)" />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -4,13 +4,13 @@
<ng-template mat-tab-label> <ng-template mat-tab-label>
<span matBadgeOverlap="false" class="tab-badge" matBadgeColor="primary" matBadge="{{numUtxos}}">UTXOs</span> <span matBadgeOverlap="false" class="tab-badge" matBadgeColor="primary" matBadge="{{numUtxos}}">UTXOs</span>
</ng-template> </ng-template>
<rtl-cln-on-chain-utxos fxLayout="row" fxFlex="100" [numDustUTXOs]="numDustUtxos" [isDustUTXO]="false" [dustAmount]="DUST_AMOUNT"></rtl-cln-on-chain-utxos> <rtl-cln-on-chain-utxos fxLayout="row" fxFlex="100" [numDustUTXOs]="numDustUtxos" [isDustUTXO]="false" [dustAmount]="DUST_AMOUNT" />
</mat-tab> </mat-tab>
<mat-tab> <mat-tab>
<ng-template mat-tab-label> <ng-template mat-tab-label>
<span matBadgeOverlap="false" class="tab-badge" matBadge="{{numDustUtxos}}">Dust UTXOs</span> <span matBadgeOverlap="false" class="tab-badge" matBadge="{{numDustUtxos}}">Dust UTXOs</span>
</ng-template> </ng-template>
<rtl-cln-on-chain-utxos fxLayout="row" fxFlex="100" [numDustUTXOs]="numDustUtxos" [isDustUTXO]="true" [dustAmount]="DUST_AMOUNT"></rtl-cln-on-chain-utxos> <rtl-cln-on-chain-utxos fxLayout="row" fxFlex="100" [numDustUTXOs]="numDustUtxos" [isDustUTXO]="true" [dustAmount]="DUST_AMOUNT" />
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</div> </div>

@ -16,7 +16,7 @@
</div> </div>
<div fxLayout="row" fxLayoutAlign="start start"> <div fxLayout="row" fxLayoutAlign="start start">
<div class="table-container" fxFlex="100" [perfectScrollbar]> <div class="table-container" fxFlex="100" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="listUTXOs" [ngClass]="{'error-border': errorMessage !== ''}"> <table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="listUTXOs" [ngClass]="{'error-border': errorMessage !== ''}">
<ng-container matColumnDef="is_dust"> <ng-container matColumnDef="is_dust">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before" matTooltip="Dust/Nondust"></th> <th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before" matTooltip="Dust/Nondust"></th>
@ -84,7 +84,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -104,10 +104,10 @@
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
<mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>
</div> </div>
</div> </div>
<ng-template #emptySpace> <ng-template #emptySpace>
<mat-icon fxLayoutAlign="start center" color="warn" class="mr-1"></mat-icon> <mat-icon fxLayoutAlign="start center" color="warn" class="mr-1" />
</ng-template> </ng-template>

@ -10,11 +10,11 @@
<form fxLayout="column"> <form fxLayout="column">
<div fxLayout="column" class="bordered-box mb-1 p-2"> <div fxLayout="column" class="bordered-box mb-1 p-2">
<p fxLayoutAlign="start center" class="pb-1 word-break">Bump fee for transaction id: {{bumpFeeChannel?.funding_txid}} <p fxLayoutAlign="start center" class="pb-1 word-break">Bump fee for transaction id: {{bumpFeeChannel?.funding_txid}}
<fa-icon class="ml-1" matSuffix rtlClipboard matTooltip="Copy transaction ID" [icon]="faCopy" [payload]="bumpFeeChannel?.funding_txid" (copied)="onCopyID($event)"></fa-icon> <fa-icon class="ml-1" matSuffix rtlClipboard matTooltip="Copy transaction ID" [icon]="faCopy" [payload]="bumpFeeChannel?.funding_txid" (copied)="onCopyID($event)" />
</p> </p>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="alert alert-info"> <div fxFlex="100" class="alert alert-info">
<fa-icon class="mr-1 alert-icon" [icon]="faInfoCircle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faInfoCircle" />
<span fxLayout="column" fxFlex="100">Bumping fee on pending open channels is an advanced feature, attempt it only if you are familiar with the functionality of Bitcoin transactions. <span fxLayout="column" fxFlex="100">Bumping fee on pending open channels is an advanced feature, attempt it only if you are familiar with the functionality of Bitcoin transactions.
<div>Before attempting fee bump ensure the following:</div> <div>Before attempting fee bump ensure the following:</div>
<div class="pl-1">1: Use a Bitcoin block explorer to ensure that channel opening transaction is not confirmed.</div> <div class="pl-1">1: Use a Bitcoin block explorer to ensure that channel opening transaction is not confirmed.</div>
@ -39,7 +39,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="bumpFeeError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="bumpFeeError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>{{bumpFeeError}}</span> <span>{{bumpFeeError}}</span>
</div> </div>
</div> </div>

@ -2,7 +2,7 @@
<div fxFlex="100"> <div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header"> <mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start"> <div fxFlex="95" fxLayoutAlign="start start">
<fa-icon class="page-title-img mr-1" [icon]="faReceipt"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faReceipt" />
<span class="page-title">Channel Information</span> <span class="page-title">Channel Information</span>
</div> </div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center center" class="btn-close-x p-0" mat-button (click)="onClose()">X</button> <button tabindex="3" fxFlex="5" fxLayoutAlign="center center" class="btn-close-x p-0" mat-button (click)="onClose()">X</button>
@ -12,7 +12,7 @@
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="50"> <div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Short Channel ID</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Short Channel ID</h4>
<span class="foreground-secondary-text go-to-link" matTooltip="Go To Graph Lookup" (click)="onGoToLink()" > <span tabindex="4" class="foreground-secondary-text go-to-link" matTooltip="Go To Graph Lookup" (click)="onGoToLink()" >
{{channel.short_channel_id}} {{channel.short_channel_id}}
</span> </span>
</div> </div>
@ -21,21 +21,21 @@
<span class="foreground-secondary-text">{{channel.alias}}</span> <span class="foreground-secondary-text">{{channel.alias}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Channel ID</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Channel ID</h4>
<span class="foreground-secondary-text">{{channel.channel_id}}</span> <span class="foreground-secondary-text">{{channel.channel_id}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Peer Public Key</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Peer Public Key</h4>
<span class="foreground-secondary-text">{{channel.peer_id}}</span> <span class="foreground-secondary-text">{{channel.peer_id}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="33"> <div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">State</h4> <h4 fxLayoutAlign="start" class="font-bold-500">State</h4>
@ -50,7 +50,7 @@
<span class="overflow-wrap foreground-secondary-text">{{channel.private ? 'Yes' : 'No'}}</span> <span class="overflow-wrap foreground-secondary-text">{{channel.private ? 'Yes' : 'No'}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="33"> <div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Remote Balance (Sats)</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Remote Balance (Sats)</h4>
@ -65,7 +65,7 @@
<span class="overflow-wrap foreground-secondary-text">{{channel.total_msat / 1000 | number:'1.0-0'}}</span> <span class="overflow-wrap foreground-secondary-text">{{channel.total_msat / 1000 | number:'1.0-0'}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div *ngIf="showAdvanced"> <div *ngIf="showAdvanced">
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="50"> <div fxFlex="50">
@ -77,7 +77,7 @@
<span class="overflow-wrap foreground-secondary-text">{{channel.spendable_msat / 1000 | number:'1.0-0'}}</span> <span class="overflow-wrap foreground-secondary-text">{{channel.spendable_msat / 1000 | number:'1.0-0'}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="50"> <div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Their Reserve (Sats)</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Their Reserve (Sats)</h4>
@ -88,14 +88,14 @@
<span class="overflow-wrap foreground-secondary-text">{{channel.our_reserve_msat / 1000 | number:'1.0-2'}}</span> <span class="overflow-wrap foreground-secondary-text">{{channel.our_reserve_msat / 1000 | number:'1.0-2'}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Funding Transaction ID</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Funding Transaction ID</h4>
<span class="foreground-secondary-text">{{channel.funding_txid}}</span> <span class="foreground-secondary-text">{{channel.funding_txid}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1"></mat-divider> <mat-divider class="my-1" />
</div> </div>
<div fxLayout="row" fxLayoutAlign="end center" fxFlex="100" [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}"> <div fxLayout="row" fxLayoutAlign="end center" fxFlex="100" [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}">
<button mat-button color="primary" type="reset" tabindex="1" class="mr-1" (click)="onShowAdvanced()"> <button mat-button color="primary" type="reset" tabindex="1" class="mr-1" (click)="onShowAdvanced()">

@ -15,7 +15,7 @@
</div> </div>
</div> </div>
<div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]> <div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table fxFlex="100" matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="channels" [ngClass]="{'error-border': errorMessage !== ''}"> <table #table mat-table fxFlex="100" matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="channels" [ngClass]="{'error-border': errorMessage !== ''}">
<!-- Channel Group Row Start --> <!-- Channel Group Row Start -->
<ng-container matColumnDef="amount_msat"> <ng-container matColumnDef="amount_msat">
@ -113,7 +113,7 @@
<th *matHeaderCellDef mat-header-cell class="px-2"> <th *matHeaderCellDef mat-header-cell class="px-2">
<div class="bordered-box table-actions-select" fxLayoutAlign="end center"> <div class="bordered-box table-actions-select" fxLayoutAlign="end center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -142,5 +142,5 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>

@ -14,14 +14,14 @@
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<div fxLayout="row" fxLayoutAlign="start center" fxFlex="100" class="table-container w-100" [perfectScrollbar]> <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100" class="table-container w-100" [perfectScrollbar]>
<table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="channels" [ngClass]="{'error-border': errorMessage !== ''}"> <table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="channels" [ngClass]="{'error-border': errorMessage !== ''}">
<ng-container matColumnDef="private"> <ng-container matColumnDef="private">
<th *matHeaderCellDef mat-header-cell mat-sort-header matTooltip="Private"></th> <th *matHeaderCellDef mat-header-cell mat-sort-header matTooltip="Private"></th>
<td *matCellDef="let channel" mat-cell> <td *matCellDef="let channel" mat-cell>
<span *ngIf="channel.private" class="mr-1" matTooltip="Private" matTooltipPosition="right"><fa-icon [icon]="faEyeSlash"></fa-icon></span> <span *ngIf="channel.private" class="mr-1" matTooltip="Private" matTooltipPosition="right"><fa-icon [icon]="faEyeSlash" /></span>
<span *ngIf="!channel.private" class="mr-1" matTooltip="Public" matTooltipPosition="right"><fa-icon [icon]="faEye"></fa-icon></span> <span *ngIf="!channel.private" class="mr-1" matTooltip="Public" matTooltipPosition="right"><fa-icon [icon]="faEye" /></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="short_channel_id"> <ng-container matColumnDef="short_channel_id">
@ -104,14 +104,14 @@
<div fxLayout="row"> <div fxLayout="row">
<mat-hint fxFlex="100" fxLayoutAlign="center center" class="font-size-80">{{channel.balancedness || 0 | number}}</mat-hint> <mat-hint fxFlex="100" fxLayoutAlign="center center" class="font-size-80">{{channel.balancedness || 0 | number}}</mat-hint>
</div> </div>
<mat-progress-bar mode="determinate" value="{{channel.to_us_msat && channel.to_us_msat > 0 ? ((channel.to_us_msat/((channel.to_us_msat)+(channel.to_them_msat)))*100) : 0}}"></mat-progress-bar> <mat-progress-bar mode="determinate" value="{{channel.to_us_msat && channel.to_us_msat > 0 ? ((channel.to_us_msat/((channel.to_us_msat)+(channel.to_them_msat)))*100) : 0}}" />
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onChannelUpdate('all')">Update Fee Policy</mat-option> <mat-option (click)="onChannelUpdate('all')">Update Fee Policy</mat-option>
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
@ -120,7 +120,7 @@
<td *matCellDef="let channel" mat-cell fxLayoutAlign="end center"> <td *matCellDef="let channel" mat-cell fxLayoutAlign="end center">
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="2" class="mr-0"> <mat-select placeholder="Actions" tabindex="2" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onChannelClick(channel, $event)">View Info</mat-option> <mat-option (click)="onChannelClick(channel, $event)">View Info</mat-option>
<mat-option (click)="onViewRemotePolicy(channel)">View Remote Fee</mat-option> <mat-option (click)="onViewRemotePolicy(channel)">View Remote Fee</mat-option>
<mat-option (click)="onChannelUpdate(channel)">Update Fee Policy</mat-option> <mat-option (click)="onChannelUpdate(channel)">Update Fee Policy</mat-option>
@ -142,5 +142,5 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>

@ -68,7 +68,7 @@ export class CLNChannelOpenTableComponent implements OnInit, AfterViewInit, OnDe
} }
ngOnInit() { ngOnInit() {
if (window.history.state && window.history.state.filterColumn) { if (window.history.state && (window.history.state.filterColumn || window.history.state.filterValue)) {
this.selFilterBy = window.history.state.filterColumn || 'all'; this.selFilterBy = window.history.state.filterColumn || 'all';
this.selFilter = window.history.state.filterValue || ''; this.selFilter = window.history.state.filterValue || '';
} }

@ -14,14 +14,14 @@
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<div fxLayout="row" fxLayoutAlign="start center" fxFlex="100" class="table-container w-100" [perfectScrollbar]> <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100" class="table-container w-100" [perfectScrollbar]>
<table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="channels" [ngClass]="{'error-border': errorMessage !== ''}"> <table #table mat-table matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="channels" [ngClass]="{'error-border': errorMessage !== ''}">
<ng-container matColumnDef="private"> <ng-container matColumnDef="private">
<th *matHeaderCellDef mat-header-cell mat-sort-header matTooltip="Private"></th> <th *matHeaderCellDef mat-header-cell mat-sort-header matTooltip="Private"></th>
<td *matCellDef="let channel" mat-cell> <td *matCellDef="let channel" mat-cell>
<span *ngIf="channel.private" class="mr-1" matTooltip="Private" matTooltipPosition="right"><fa-icon [icon]="faEyeSlash"></fa-icon></span> <span *ngIf="channel.private" class="mr-1" matTooltip="Private" matTooltipPosition="right"><fa-icon [icon]="faEyeSlash" /></span>
<span *ngIf="!channel.private" class="mr-1" matTooltip="Public" matTooltipPosition="right"><fa-icon [icon]="faEye"></fa-icon></span> <span *ngIf="!channel.private" class="mr-1" matTooltip="Public" matTooltipPosition="right"><fa-icon [icon]="faEye" /></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="alias"> <ng-container matColumnDef="alias">
@ -98,7 +98,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -106,7 +106,7 @@
<td *matCellDef="let channel" mat-cell fxLayoutAlign="end center"> <td *matCellDef="let channel" mat-cell fxLayoutAlign="end center">
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="4" class="mr-0"> <mat-select placeholder="Actions" tabindex="4" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onChannelClick(channel, $event)">View Info</mat-option> <mat-option (click)="onChannelClick(channel, $event)">View Info</mat-option>
<mat-option *ngIf="(channel.state === 'CHANNELD_SHUTTING_DOWN' || channel.state === 'CLOSINGD_SIGEXCHANGE' || (!channel.connected && channel.state === 'CHANNELD_NORMAL'))" (click)="onChannelClose(channel)">Close Channel</mat-option> <mat-option *ngIf="(channel.state === 'CHANNELD_SHUTTING_DOWN' || channel.state === 'CLOSINGD_SIGEXCHANGE' || (!channel.connected && channel.state === 'CHANNELD_NORMAL'))" (click)="onChannelClose(channel)">Close Channel</mat-option>
<mat-option *ngIf="channel.state === 'CHANNELD_AWAITING_LOCKIN'" (click)="onBumpFee(channel)">Bump Fee</mat-option> <mat-option *ngIf="channel.state === 'CHANNELD_AWAITING_LOCKIN'" (click)="onBumpFee(channel)">Bump Fee</mat-option>
@ -127,5 +127,5 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>

@ -21,7 +21,7 @@
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large">
<router-outlet></router-outlet> <router-outlet />
</div> </div>
</div> </div>
</div> </div>

@ -19,7 +19,7 @@
<mat-error *ngIf="selectedPeer.errors?.notfound">Peer not found in the list.</mat-error> <mat-error *ngIf="selectedPeer.errors?.notfound">Peer not found in the list.</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<ng-container *ngTemplateOutlet="peerDetailsExpansionBlock"></ng-container> <ng-container *ngTemplateOutlet="peerDetailsExpansionBlock" />
<div fxLayout="column"> <div fxLayout="column">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between center"> <div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between center">
<mat-form-field fxLayout="column" fxFlex="70" fxLayoutAlign="start end"> <mat-form-field fxLayout="column" fxFlex="70" fxLayoutAlign="start end">
@ -58,7 +58,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div fxFlex="42" fxLayout="row" fxLayoutAlign="start center"> <div fxFlex="42" fxLayout="row" fxLayoutAlign="start center">
<mat-checkbox fxFlex="7" tabindex="5" color="primary" name="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}" [(ngModel)]="flgMinConf" (change)="flgMinConf ? selFeeRate=null : minConfValue=null"></mat-checkbox> <mat-checkbox fxFlex="7" tabindex="5" color="primary" name="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}" [(ngModel)]="flgMinConf" (change)="flgMinConf ? selFeeRate=null : minConfValue=null" />
<mat-form-field fxLayout="column" fxFlex="93"> <mat-form-field fxLayout="column" fxFlex="93">
<mat-label>Min Confirmation Blocks</mat-label> <mat-label>Min Confirmation Blocks</mat-label>
<input #blocks="ngModel" matInput type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="flgMinConf" [disabled]="!flgMinConf" [(ngModel)]="minConfValue"> <input #blocks="ngModel" matInput type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="flgMinConf" [disabled]="!flgMinConf" [(ngModel)]="minConfValue">
@ -83,7 +83,7 @@
</mat-expansion-panel> </mat-expansion-panel>
</div> </div>
<div *ngIf="channelConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="channelConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span *ngIf="channelConnectionError !== ''">{{channelConnectionError}}</span> <span *ngIf="channelConnectionError !== ''">{{channelConnectionError}}</span>
</div> </div>
<div class="mt-2" fxLayout="row" fxLayoutAlign="end center"> <div class="mt-2" fxLayout="row" fxLayoutAlign="end center">
@ -109,7 +109,7 @@
<span class="foreground-secondary-text">{{peer.id}}</span> <span class="foreground-secondary-text">{{peer.id}}</span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="50"> <div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Address</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Address</h4>

@ -18,7 +18,7 @@
<mat-error *ngIf="peerFormGroup.controls.peerAddress.errors?.required">Address is required.</mat-error> <mat-error *ngIf="peerFormGroup.controls.peerAddress.errors?.required">Address is required.</mat-error>
</mat-form-field> </mat-form-field>
<div *ngIf="peerConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="peerConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>{{peerConnectionError}}</span> <span>{{peerConnectionError}}</span>
</div> </div>
<div class="mt-2" fxLayout="row" fxLayoutAlign="start center" fxFlex="100"> <div class="mt-2" fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
@ -61,7 +61,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div fxFlex="45" fxLayout="row" fxLayoutAlign="start center"> <div fxFlex="45" fxLayout="row" fxLayoutAlign="start center">
<mat-checkbox fxFlex="7" tabindex="5" color="primary" formControlName="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}"></mat-checkbox> <mat-checkbox fxFlex="7" tabindex="5" color="primary" formControlName="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}" />
<mat-form-field fxLayout="column" fxFlex="93"> <mat-form-field fxLayout="column" fxFlex="93">
<mat-label>Min Confirmation Blocks</mat-label> <mat-label>Min Confirmation Blocks</mat-label>
<input matInput formControlName="minConfValue" type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="channelFormGroup.controls.flgMinConf.value"> <input matInput formControlName="minConfValue" type="number" name="blocks" tabindex="8" [step]="1" [min]="0" [required]="channelFormGroup.controls.flgMinConf.value">
@ -71,7 +71,7 @@
</div> </div>
</div> </div>
<div *ngIf="channelConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="channelConnectionError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>{{channelConnectionError}}</span> <span>{{channelConnectionError}}</span>
</div> </div>
<div class="mt-2" fxLayout="row" fxLayoutAlign="start center" fxFlex="100"> <div class="mt-2" fxLayout="row" fxLayoutAlign="start center" fxFlex="100">

@ -1,16 +1,16 @@
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faChartPie"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faChartPie" />
<span class="page-title">On-chain Balance</span> <span class="page-title">On-chain Balance</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x mb-4"> <div fxLayout="column" class="padding-gap-x mb-4">
<mat-card> <mat-card>
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<rtl-currency-unit-converter [values]="balances"></rtl-currency-unit-converter> <rtl-currency-unit-converter [values]="balances" />
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faUsers"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faUsers" />
<span class="page-title">Connections</span> <span class="page-title">Connections</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x"> <div fxLayout="column" class="padding-gap-x">
@ -29,7 +29,7 @@
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large">
<router-outlet></router-outlet> <router-outlet />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -5,7 +5,7 @@
<div fxLayout="column"> <div fxLayout="column">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container"> <div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"> <div fxFlex="70">
<fa-icon class="page-title-img mr-1" [icon]="faUsers"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faUsers" />
<span class="page-title">Connected Peers</span> <span class="page-title">Connected Peers</span>
</div> </div>
<div fxFlex.gt-xs="30" fxLayoutAlign.gt-xs="space-between center" fxLayout="row" fxLayoutAlign="space-between stretch"> <div fxFlex.gt-xs="30" fxLayoutAlign.gt-xs="space-between center" fxLayout="row" fxLayoutAlign="space-between stretch">
@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]> <div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table matSort class="overflow-x-hidden overflow-y-hidden" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="peers" [ngClass]="{'error-border': errorMessage !== ''}"> <table #table mat-table matSort class="overflow-x-hidden overflow-y-hidden" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="peers" [ngClass]="{'error-border': errorMessage !== ''}">
<ng-container matColumnDef="connected"> <ng-container matColumnDef="connected">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before" matTooltip="Connected"></th> <th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before" matTooltip="Connected"></th>
@ -59,7 +59,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -67,7 +67,7 @@
<td *matCellDef="let peer" mat-cell fxLayoutAlign="end center"> <td *matCellDef="let peer" mat-cell fxLayoutAlign="end center">
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onPeerClick(peer, $event)">View Info</mat-option> <mat-option (click)="onPeerClick(peer, $event)">View Info</mat-option>
<mat-option (click)="onOpenChannel(peer)">Open Channel</mat-option> <mat-option (click)="onOpenChannel(peer)">Open Channel</mat-option>
<mat-option *ngIf="peer.connected" (click)="onPeerDetach(peer)">Disconnect</mat-option> <mat-option *ngIf="peer.connected" (click)="onPeerDetach(peer)">Disconnect</mat-option>
@ -88,6 +88,6 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>
</div> </div>

@ -1,15 +1,15 @@
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faChartBar"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faChartBar" />
<span class="page-title">Reports</span> <span class="page-title">Reports</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x"> <div fxLayout="column" class="padding-gap-x">
<mat-card> <mat-card>
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel"> <nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel">
<div *ngFor="let link of links" role="tab" mat-tab-link class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div> <div *ngFor="let link of links" tabindex="1" role="tab" mat-tab-link class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div>
</nav> </nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel> <mat-tab-nav-panel #tabPanel />
<router-outlet></router-outlet> <router-outlet />
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>

@ -1,5 +1,5 @@
<div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x-large"> <div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x-large">
<rtl-horizontal-scroller (stepChanged)="onSelectionChange($event)"></rtl-horizontal-scroller> <rtl-horizontal-scroller (stepChanged)="onSelectionChange($event)" />
<div fxLayout="column" fxLayoutAlign="center center" class="padding-gap-x"> <div fxLayout="column" fxLayoutAlign="center center" class="padding-gap-x">
<mat-radio-group class="my-1" color="primary" name="selReportBy" fxFlex="100" fxLayoutAlign="start center" [(ngModel)]="selReportBy" (change)="onSelReportByChange()"> <mat-radio-group class="my-1" color="primary" name="selReportBy" fxFlex="100" fxLayoutAlign="start center" [(ngModel)]="selReportBy" (change)="onSelReportByChange()">
<span class="mr-2">Report By: </span> <span class="mr-2">Report By: </span>
@ -9,7 +9,7 @@
</div> </div>
<div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x"> <div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x">
<div *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" class="font-size-120 mt-1"> <div *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" class="font-size-120 mt-1">
<mat-progress-bar mode="indeterminate"></mat-progress-bar> <mat-progress-bar mode="indeterminate" />
<p>Getting Forwarding History...</p> <p>Getting Forwarding History...</p>
</div> </div>
<div *ngIf="apiCallStatus?.status === apiCallStatusEnum.ERROR" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" class="font-size-120 mt-1 error-border">{{errorMessage}}</div> <div *ngIf="apiCallStatus?.status === apiCallStatusEnum.ERROR" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" class="font-size-120 mt-1 error-border">{{errorMessage}}</div>
@ -42,7 +42,7 @@
</ngx-charts-bar-vertical> </ngx-charts-bar-vertical>
</div> </div>
<div class="mt-1"> <div class="mt-1">
<rtl-cln-forwarding-history *ngIf="filteredEventsBySelectedPeriod && filteredEventsBySelectedPeriod.length > 0" [pageId]="'reports'" [tableId]="'routing'" [eventsData]="filteredEventsBySelectedPeriod" [selFilter]="eventFilterValue"></rtl-cln-forwarding-history> <rtl-cln-forwarding-history *ngIf="filteredEventsBySelectedPeriod && filteredEventsBySelectedPeriod.length > 0" [pageId]="'reports'" [tableId]="'routing'" [eventsData]="filteredEventsBySelectedPeriod" [selFilter]="eventFilterValue" />
</div> </div>
</div> </div>
</div> </div>

@ -1,5 +1,5 @@
<div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x-large"> <div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x-large">
<rtl-horizontal-scroller (stepChanged)="onSelectionChange($event)"></rtl-horizontal-scroller> <rtl-horizontal-scroller (stepChanged)="onSelectionChange($event)" />
<div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x"> <div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="padding-gap-x">
<div *ngIf="transactionsNonZeroReportData.length > 0" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" class="font-size-120 font-bold-700 mt-1" [@fadeIn]="transactionsReportSummary"> <div *ngIf="transactionsNonZeroReportData.length > 0" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" class="font-size-120 font-bold-700 mt-1" [@fadeIn]="transactionsReportSummary">
<div *ngIf="transactionsReportSummary.paymentsSelectedPeriod" fxLayout="row" fxLayoutAlign="start stretch" fxFlex="100"> <div *ngIf="transactionsReportSummary.paymentsSelectedPeriod" fxLayout="row" fxLayoutAlign="start stretch" fxFlex="100">
@ -35,7 +35,7 @@
</ngx-charts-bar-vertical-2d> </ngx-charts-bar-vertical-2d>
</div> </div>
<div class="mt-1"> <div class="mt-1">
<rtl-transactions-report-table *ngIf="transactionsNonZeroReportData.length > 0" [displayedColumns]="displayedColumns" [tableSetting]="tableSetting" [dataList]="transactionsNonZeroReportData" [dataRange]="reportPeriod" [selFilter]="transactionFilterValue"></rtl-transactions-report-table> <rtl-transactions-report-table *ngIf="transactionsNonZeroReportData.length > 0" [displayedColumns]="displayedColumns" [tableSetting]="tableSetting" [dataList]="transactionsNonZeroReportData" [dataRange]="reportPeriod" [selFilter]="transactionFilterValue" />
</div> </div>
</div> </div>
</div> </div>

@ -2,7 +2,7 @@
<div *ngIf="errorMessage !== ''" class="p-2 error-border my-2">{{errorMessage}}</div> <div *ngIf="errorMessage !== ''" class="p-2 error-border my-2">{{errorMessage}}</div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start stretch" class="page-sub-title-container"> <div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="100" class="alert alert-warn mt-1"> <div fxFlex="100" class="alert alert-warn mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>Maximum 1,000 failed transactions only.</span> <span>Maximum 1,000 failed transactions only.</span>
</div> </div>
<div fxFlex="100"> <div fxFlex="100">
@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container" [perfectScrollbar]> <div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table fxFlex="100" matSort class="overflow-auto" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="failedForwardingEvents"> <table #table mat-table fxFlex="100" matSort class="overflow-auto" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="failedForwardingEvents">
<ng-container matColumnDef="received_time"> <ng-container matColumnDef="received_time">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Received Time</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Received Time</th>
@ -87,7 +87,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -108,5 +108,5 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator *ngIf="errorMessage === ''" class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator *ngIf="errorMessage === ''" class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>

@ -16,7 +16,7 @@
</div> </div>
</div> </div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container" [perfectScrollbar]> <div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table fxFlex="100" matSort class="overflow-auto" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="forwardingHistoryEvents"> <table #table mat-table fxFlex="100" matSort class="overflow-auto" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="forwardingHistoryEvents">
<ng-container matColumnDef="received_time"> <ng-container matColumnDef="received_time">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Received Time</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Received Time</th>
@ -89,7 +89,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -110,5 +110,5 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator *ngIf="errorMessage === ''" class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator *ngIf="errorMessage === ''" class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>

@ -59,6 +59,23 @@ export class CLNForwardingHistoryComponent implements OnInit, OnChanges, AfterVi
this.screenSize = this.commonService.getScreenSize(); this.screenSize = this.commonService.getScreenSize();
} }
ngOnChanges(changes: SimpleChanges) {
if (changes.eventsData) {
this.apiCallStatus = { status: APICallStatusEnum.COMPLETED, action: 'FetchForwardingHistory' };
this.eventsData = changes.eventsData.currentValue;
this.successfulEvents = this.eventsData;
this.totalForwardedTransactions = this.eventsData.length;
if (this.paginator) { this.paginator.firstPage(); }
if (!changes.eventsData.firstChange) {
this.loadForwardingEventsTable(this.successfulEvents);
}
}
if (changes.selFilter && !changes.selFilter.firstChange) {
this.selFilterBy = 'all';
this.applyFilter();
}
}
ngOnInit() { ngOnInit() {
this.store.select(clnPageSettings).pipe(takeUntil(this.unSubs[0])). this.store.select(clnPageSettings).pipe(takeUntil(this.unSubs[0])).
subscribe((settings: { pageSettings: PageSettings[], apiCallStatus: ApiCallStatusPayload }) => { subscribe((settings: { pageSettings: PageSettings[], apiCallStatus: ApiCallStatusPayload }) => {
@ -110,23 +127,6 @@ export class CLNForwardingHistoryComponent implements OnInit, OnChanges, AfterVi
}, 0); }, 0);
} }
ngOnChanges(changes: SimpleChanges) {
if (changes.eventsData) {
this.apiCallStatus = { status: APICallStatusEnum.COMPLETED, action: 'FetchForwardingHistory' };
this.eventsData = changes.eventsData.currentValue;
this.successfulEvents = this.eventsData;
this.totalForwardedTransactions = this.eventsData.length;
if (this.paginator) { this.paginator.firstPage(); }
if (!changes.eventsData.firstChange) {
this.loadForwardingEventsTable(this.successfulEvents);
}
}
if (changes.selFilter && !changes.selFilter.firstChange) {
this.selFilterBy = 'all';
this.applyFilter();
}
}
onForwardingEventClick(selFEvent: ForwardingEvent, event: any) { onForwardingEventClick(selFEvent: ForwardingEvent, event: any) {
const reorderedFHEvent = [ const reorderedFHEvent = [
[{ key: 'status', value: 'Settled', title: 'Status', width: 50, type: DataTypeEnum.STRING }, [{ key: 'status', value: 'Settled', title: 'Status', width: 50, type: DataTypeEnum.STRING },

@ -2,7 +2,7 @@
<div *ngIf="errorMessage !== ''" class="p-2 error-border my-2">{{errorMessage}}</div> <div *ngIf="errorMessage !== ''" class="p-2 error-border my-2">{{errorMessage}}</div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start stretch" class="page-sub-title-container"> <div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="100" class="alert alert-warn mt-1"> <div fxFlex="100" class="alert alert-warn mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>Maximum 1,000 local failed transactions only.</span> <span>Maximum 1,000 local failed transactions only.</span>
</div> </div>
<div fxFlex="100"> <div fxFlex="100">
@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container" [perfectScrollbar]> <div *ngIf="errorMessage === ''" fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table fxFlex="100" matSort class="overflow-auto" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="failedLocalForwardingEvents"> <table #table mat-table fxFlex="100" matSort class="overflow-auto" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="failedLocalForwardingEvents">
<ng-container matColumnDef="received_time"> <ng-container matColumnDef="received_time">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Received Time</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Received Time</th>
@ -72,7 +72,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -93,5 +93,5 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator *ngIf="errorMessage === ''" class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator *ngIf="errorMessage === ''" class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>

@ -8,7 +8,7 @@
</div> </div>
</div> </div>
<div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="table-container" [perfectScrollbar]> <div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #tableIn mat-table matSort class="overflow-auto incoming-table" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="routingPeersIncoming"> <table #tableIn mat-table matSort class="overflow-auto incoming-table" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="routingPeersIncoming">
<ng-container matColumnDef="channel_id"> <ng-container matColumnDef="channel_id">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Channel ID</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Channel ID</th>
@ -51,7 +51,7 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator #paginatorIn class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator #paginatorIn class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>
<div fxLayout="column" fxFlex="49" fxLayoutAlign="end stretch"> <div fxLayout="column" fxFlex="49" fxLayoutAlign="end stretch">
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize !== screenSizeEnum.LG}"> <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize !== screenSizeEnum.LG}">
@ -70,7 +70,7 @@
</div> </div>
</div> </div>
<div fxLayout="column" fxLayoutAlign="start end" fxFlex="100" class="table-container" [perfectScrollbar]> <div fxLayout="column" fxLayoutAlign="start end" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #tableOut mat-table matSort class="overflow-auto outgoing-table" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="routingPeersOutgoing"> <table #tableOut mat-table matSort class="overflow-auto outgoing-table" [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="routingPeersOutgoing">
<ng-container matColumnDef="channel_id"> <ng-container matColumnDef="channel_id">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Channel ID</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Channel ID</th>
@ -112,7 +112,7 @@
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
<mat-paginator #paginatorOut class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator #paginatorOut class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>
</div> </div>
</div> </div>

@ -59,6 +59,17 @@ export class CLNRoutingPeersComponent implements OnInit, OnChanges, AfterViewIni
this.screenSize = this.commonService.getScreenSize(); this.screenSize = this.commonService.getScreenSize();
} }
ngOnChanges(changes: SimpleChanges) {
if (changes.eventsData) {
this.apiCallStatus = { status: APICallStatusEnum.COMPLETED, action: 'FetchForwardingHistory' };
this.eventsData = changes.eventsData.currentValue;
this.successfulEvents = this.eventsData;
if (!changes.eventsData.firstChange) {
this.loadRoutingPeersTable(this.successfulEvents);
}
}
}
ngOnInit() { ngOnInit() {
this.store.pipe(take(1)).subscribe((state) => { this.store.pipe(take(1)).subscribe((state) => {
if (state.cln.apisCallStatus.FetchForwardingHistoryS.status === APICallStatusEnum.UN_INITIATED && !state.cln.forwardingHistory.listForwards?.length) { if (state.cln.apisCallStatus.FetchForwardingHistoryS.status === APICallStatusEnum.UN_INITIATED && !state.cln.forwardingHistory.listForwards?.length) {
@ -105,17 +116,6 @@ export class CLNRoutingPeersComponent implements OnInit, OnChanges, AfterViewIni
} }
} }
ngOnChanges(changes: SimpleChanges) {
if (changes.eventsData) {
this.apiCallStatus = { status: APICallStatusEnum.COMPLETED, action: 'FetchForwardingHistory' };
this.eventsData = changes.eventsData.currentValue;
this.successfulEvents = this.eventsData;
if (!changes.eventsData.firstChange) {
this.loadRoutingPeersTable(this.successfulEvents);
}
}
}
applyIncomingFilter() { applyIncomingFilter() {
this.routingPeersIncoming.filter = this.filterIn.toLowerCase(); this.routingPeersIncoming.filter = this.filterIn.toLowerCase();
} }

@ -1,6 +1,6 @@
<div fxLayout="column" class="mb-2"> <div fxLayout="column" class="mb-2">
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faMapSigns"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faMapSigns" />
<span class="page-title">Routing</span> <span class="page-title">Routing</span>
</div> </div>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start start" class="padding-gap-x"> <div fxLayout="row" fxFlex="100" fxLayoutAlign="start start" class="padding-gap-x">
@ -8,12 +8,12 @@
<mat-card-content fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch"> <mat-card-content fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<div fxLayout="row" fxFlex="100"> <div fxLayout="row" fxFlex="100">
<nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" fxFlex="100" [tabPanel]="tabPanel"> <nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" fxFlex="100" [tabPanel]="tabPanel">
<div *ngFor="let link of links" mat-tab-link role="tab" class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div> <div *ngFor="let link of links" tabindex="1" mat-tab-link role="tab" class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div>
</nav> </nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel> <mat-tab-nav-panel #tabPanel />
</div> </div>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch" class="padding-gap-x-large"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch" class="padding-gap-x-large">
<router-outlet></router-outlet> <router-outlet />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -1,16 +1,16 @@
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faUserCheck"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faUserCheck" />
<span class="page-title">Sign/Verify Message</span> <span class="page-title">Sign/Verify Message</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x"> <div fxLayout="column" class="padding-gap-x">
<mat-card> <mat-card>
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel"> <nav mat-tab-nav-bar mat-stretch-tabs="false" mat-align-tabs="start" [tabPanel]="tabPanel">
<div *ngFor="let link of links" mat-tab-link role="tab" class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div> <div *ngFor="let link of links" tabindex="1" mat-tab-link role="tab" class="mat-tab-label" [active]="activeLink === link.link" routerLink="{{link.link}}" (click)="activeLink = link.link">{{link.name}}</div>
</nav> </nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel> <mat-tab-nav-panel #tabPanel />
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="mat-tab-body-wrapper mb-2"> <div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="mat-tab-body-wrapper mb-2">
<router-outlet></router-outlet> <router-outlet />
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

@ -9,7 +9,7 @@
<button class="mr-1" mat-stroked-button color="primary" tabindex="2" type="reset" (click)="resetData()">Clear Field</button> <button class="mr-1" mat-stroked-button color="primary" tabindex="2" type="reset" (click)="resetData()">Clear Field</button>
<button mat-flat-button color="primary" tabindex="3" type="submit" (click)="onSign()">Sign</button> <button mat-flat-button color="primary" tabindex="3" type="submit" (click)="onSign()">Sign</button>
</div> </div>
<mat-divider class="my-2"></mat-divider> <mat-divider class="my-2" />
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start center"><p>Generated Signature</p></div> <div fxLayout="row" fxFlex="100" fxLayoutAlign="start center"><p>Generated Signature</p></div>
<div fxLayout="row" fxLayoutAlign="start center" class="signature-box bordered-box read-only">{{signature}}</div> <div fxLayout="row" fxLayoutAlign="start center" class="signature-box bordered-box read-only">{{signature}}</div>
<div fxLayout="row" class="mt-2"> <div fxLayout="row" class="mt-2">

@ -16,7 +16,7 @@
<button mat-flat-button color="primary" tabindex="4" type="submit" (click)="onVerify()">Verify</button> <button mat-flat-button color="primary" tabindex="4" type="submit" (click)="onVerify()">Verify</button>
</div> </div>
<div *ngIf="showVerifyStatus && verifyRes.verified" fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap"> <div *ngIf="showVerifyStatus && verifyRes.verified" fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap">
<mat-divider class="my-2"></mat-divider> <mat-divider class="my-2" />
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start center"> <div fxLayout="row" fxFlex="100" fxLayoutAlign="start center">
<p *ngIf="verifyRes.verified">Pubkey Used</p> <p *ngIf="verifyRes.verified">Pubkey Used</p>
</div> </div>

@ -7,11 +7,11 @@ import { GetInfo, Fees, Peer, Payment, QueryRoutes, Channel, FeeRates, Invoice,
GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, OfferInvoice, Offer, OfferBookmark, ListForwards, FetchListForwards } from '../../shared/models/clnModels'; GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, OfferInvoice, Offer, OfferBookmark, ListForwards, FetchListForwards } from '../../shared/models/clnModels';
import { PageSettings } from '../../shared/models/pageSettings'; import { PageSettings } from '../../shared/models/pageSettings';
export const updateCLAPICallStatus = createAction(CLNActions.UPDATE_API_CALL_STATUS_CLN, props<{ payload: ApiCallStatusPayload }>()); export const updateCLNAPICallStatus = createAction(CLNActions.UPDATE_API_CALL_STATUS_CLN, props<{ payload: ApiCallStatusPayload }>());
export const resetCLStore = createAction(CLNActions.RESET_CLN_STORE, props<{ payload: SelNodeChild | null }>()); export const resetCLNStore = createAction(CLNActions.RESET_CLN_STORE, props<{ payload: SelNodeChild | null }>());
export const setChildNodeSettingsCL = createAction(CLNActions.SET_CHILD_NODE_SETTINGS_CLN, props<{ payload: SelNodeChild }>()); export const setChildNodeSettingsCLN = createAction(CLNActions.SET_CHILD_NODE_SETTINGS_CLN, props<{ payload: SelNodeChild }>());
export const fetchPageSettings = createAction(CLNActions.FETCH_PAGE_SETTINGS_CLN); export const fetchPageSettings = createAction(CLNActions.FETCH_PAGE_SETTINGS_CLN);
@ -19,7 +19,7 @@ export const setPageSettings = createAction(CLNActions.SET_PAGE_SETTINGS_CLN, pr
export const savePageSettings = createAction(CLNActions.SAVE_PAGE_SETTINGS_CLN, props<{ payload: PageSettings[] }>()); export const savePageSettings = createAction(CLNActions.SAVE_PAGE_SETTINGS_CLN, props<{ payload: PageSettings[] }>());
export const fetchInfoCL = createAction(CLNActions.FETCH_INFO_CLN, props<{ payload: { loadPage: string } }>()); export const fetchInfoCLN = createAction(CLNActions.FETCH_INFO_CLN, props<{ payload: { loadPage: string } }>());
export const setInfo = createAction(CLNActions.SET_INFO_CLN, props<{ payload: GetInfo }>()); export const setInfo = createAction(CLNActions.SET_INFO_CLN, props<{ payload: GetInfo }>());

@ -19,9 +19,9 @@ import { closeAllDialogs, closeSpinner, logout, openAlert, openSnackBar, openSpi
import { RTLState } from '../../store/rtl.state'; import { RTLState } from '../../store/rtl.state';
import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance, import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance,
fetchPayments, fetchPeers, fetchUTXOs, setLookup, setPeers, setQueryRoutes, updateCLAPICallStatus, updateInvoice, setOfferInvoice, fetchPayments, fetchPeers, fetchUTXOs, setLookup, setPeers, setQueryRoutes, updateCLNAPICallStatus, updateInvoice, setOfferInvoice,
sendPaymentStatus, setForwardingHistory, fetchPageSettings } from './cln.actions'; sendPaymentStatus, setForwardingHistory } from './cln.actions';
import { allAPIsCallStatus, clnNodeInformation, nodeInfoAndBalance } from './cln.selector'; import { allAPIsCallStatus } from './cln.selector';
import { ApiCallsListCL } from '../../shared/models/apiCallsPayload'; import { ApiCallsListCL } from '../../shared/models/apiCallsPayload';
import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component'; import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component';
@ -30,7 +30,7 @@ export class CLNEffects implements OnDestroy {
CHILD_API_URL = API_URL + '/cln'; CHILD_API_URL = API_URL + '/cln';
API_VERION = ''; API_VERION = '';
NODE_VERISON = ''; CLN_VERISON = '';
private flgInitialized = false; private flgInitialized = false;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
@ -89,7 +89,7 @@ export class CLNEffects implements OnDestroy {
mergeMap((action: { type: string, payload: { loadPage: string } }) => { mergeMap((action: { type: string, payload: { loadPage: string } }) => {
this.flgInitialized = false; this.flgInitialized = false;
this.store.dispatch(setApiUrl({ payload: this.CHILD_API_URL })); this.store.dispatch(setApiUrl({ payload: this.CHILD_API_URL }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchInfo', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchInfo', status: APICallStatusEnum.INITIATED } }));
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.GET_NODE_INFO })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.GET_NODE_INFO }));
return this.httpClient.get<GetInfo>(this.CHILD_API_URL + API_END_POINTS.GETINFO_API). return this.httpClient.get<GetInfo>(this.CHILD_API_URL + API_END_POINTS.GETINFO_API).
pipe( pipe(
@ -97,13 +97,13 @@ export class CLNEffects implements OnDestroy {
map((info) => { map((info) => {
this.logger.info(info); this.logger.info(info);
this.API_VERION = info.api_version || ''; this.API_VERION = info.api_version || '';
this.NODE_VERISON = info.version || ''; this.CLN_VERISON = info.version || '';
if (info.chains && info.chains.length && info.chains[0] && if (info.chains && info.chains.length && info.chains[0] &&
(typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain') && info?.chains[0].chain && (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain') && info?.chains[0].chain &&
(info?.chains[0].chain.toLowerCase().indexOf('bitcoin') < 0 && info?.chains[0].chain.toLowerCase().indexOf('liquid') < 0) (info?.chains[0].chain.toLowerCase().indexOf('bitcoin') < 0 && info?.chains[0].chain.toLowerCase().indexOf('liquid') < 0)
) )
) { ) {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchInfo', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchInfo', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_NODE_INFO })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_NODE_INFO }));
this.store.dispatch(closeAllDialogs()); this.store.dispatch(closeAllDialogs());
setTimeout(() => { setTimeout(() => {
@ -122,7 +122,7 @@ export class CLNEffects implements OnDestroy {
}; };
} else { } else {
this.initializeRemainingData(info, action.payload.loadPage); this.initializeRemainingData(info, action.payload.loadPage);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchInfo', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchInfo', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_NODE_INFO })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_NODE_INFO }));
return { return {
type: CLNActions.SET_INFO_CLN, type: CLNActions.SET_INFO_CLN,
@ -144,12 +144,12 @@ export class CLNEffects implements OnDestroy {
fetchFeesCL = createEffect(() => this.actions.pipe( fetchFeesCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_FEES_CLN), ofType(CLNActions.FETCH_FEES_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchFees', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchFees', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get<Fees>(this.CHILD_API_URL + API_END_POINTS.FEES_API); return this.httpClient.get<Fees>(this.CHILD_API_URL + API_END_POINTS.FEES_API);
}), }),
map((fees) => { map((fees) => {
this.logger.info(fees); this.logger.info(fees);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchFees', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchFees', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_FEES_CLN, type: CLNActions.SET_FEES_CLN,
payload: fees ? fees : {} payload: fees ? fees : {}
@ -164,12 +164,12 @@ export class CLNEffects implements OnDestroy {
fetchFeeRatesCL = createEffect(() => this.actions.pipe( fetchFeeRatesCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_FEE_RATES_CLN), ofType(CLNActions.FETCH_FEE_RATES_CLN),
mergeMap((action: { type: string, payload: string }) => { mergeMap((action: { type: string, payload: string }) => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchFeeRates' + action.payload, status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchFeeRates' + action.payload, status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get<FeeRates>(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/feeRates/' + action.payload). return this.httpClient.get<FeeRates>(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/feeRates/' + action.payload).
pipe( pipe(
map((feeRates) => { map((feeRates) => {
this.logger.info(feeRates); this.logger.info(feeRates);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchFeeRates' + action.payload, status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchFeeRates' + action.payload, status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_FEE_RATES_CLN, type: CLNActions.SET_FEE_RATES_CLN,
payload: feeRates ? feeRates : {} payload: feeRates ? feeRates : {}
@ -186,12 +186,12 @@ export class CLNEffects implements OnDestroy {
fetchBalanceCL = createEffect(() => this.actions.pipe( fetchBalanceCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_BALANCE_CLN), ofType(CLNActions.FETCH_BALANCE_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchBalance', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchBalance', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get<Balance>(this.CHILD_API_URL + API_END_POINTS.BALANCE_API); return this.httpClient.get<Balance>(this.CHILD_API_URL + API_END_POINTS.BALANCE_API);
}), }),
map((balance) => { map((balance) => {
this.logger.info(balance); this.logger.info(balance);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchBalance', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchBalance', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_BALANCE_CLN, type: CLNActions.SET_BALANCE_CLN,
payload: balance ? balance : {} payload: balance ? balance : {}
@ -206,12 +206,12 @@ export class CLNEffects implements OnDestroy {
fetchLocalRemoteBalanceCL = createEffect(() => this.actions.pipe( fetchLocalRemoteBalanceCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_LOCAL_REMOTE_BALANCE_CLN), ofType(CLNActions.FETCH_LOCAL_REMOTE_BALANCE_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchLocalRemoteBalance', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchLocalRemoteBalance', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get<LocalRemoteBalance>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + '/localRemoteBalance'); return this.httpClient.get<LocalRemoteBalance>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + '/localRemoteBalance');
}), }),
map((lrBalance) => { map((lrBalance) => {
this.logger.info(lrBalance); this.logger.info(lrBalance);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchLocalRemoteBalance', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchLocalRemoteBalance', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_LOCAL_REMOTE_BALANCE_CLN, type: CLNActions.SET_LOCAL_REMOTE_BALANCE_CLN,
payload: lrBalance ? lrBalance : {} payload: lrBalance ? lrBalance : {}
@ -259,12 +259,12 @@ export class CLNEffects implements OnDestroy {
peersFetchCL = createEffect(() => this.actions.pipe( peersFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_PEERS_CLN), ofType(CLNActions.FETCH_PEERS_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPeers', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchPeers', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.PEERS_API). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.PEERS_API).
pipe( pipe(
map((peers: any) => { map((peers: any) => {
this.logger.info(peers); this.logger.info(peers);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPeers', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchPeers', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_PEERS_CLN, type: CLNActions.SET_PEERS_CLN,
payload: peers || [] payload: peers || []
@ -282,12 +282,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.SAVE_NEW_PEER_CLN), ofType(CLNActions.SAVE_NEW_PEER_CLN),
mergeMap((action: { type: string, payload: { id: string } }) => { mergeMap((action: { type: string, payload: { id: string } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.CONNECT_PEER })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.CONNECT_PEER }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewPeer', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewPeer', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post<Peer[]>(this.CHILD_API_URL + API_END_POINTS.PEERS_API, { id: action.payload.id }). return this.httpClient.post<Peer[]>(this.CHILD_API_URL + API_END_POINTS.PEERS_API, { id: action.payload.id }).
pipe( pipe(
map((postRes: Peer[]) => { map((postRes: Peer[]) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewPeer', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewPeer', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.CONNECT_PEER })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.CONNECT_PEER }));
this.store.dispatch(setPeers({ payload: (postRes || []) })); this.store.dispatch(setPeers({ payload: (postRes || []) }));
return { return {
@ -329,16 +329,16 @@ export class CLNEffects implements OnDestroy {
channelsFetchCL = createEffect(() => this.actions.pipe( channelsFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_CHANNELS_CLN), ofType(CLNActions.FETCH_CHANNELS_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.INITIATED } }));
const listChannelsEndpoint = const listChannelsEndpoint =
this.commonService.isVersionCompatible(this.NODE_VERISON, '23.02') && this.commonService.isVersionCompatible(this.CLN_VERISON, '23.02') &&
this.commonService.isVersionCompatible(this.API_VERION, '0.10.3') ? this.commonService.isVersionCompatible(this.API_VERION, '0.10.3') ?
'/listPeerChannels' : '/listChannels'; '/listPeerChannels' : '/listChannels';
return this.httpClient.get<Channel[]>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + listChannelsEndpoint); return this.httpClient.get<Channel[]>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + listChannelsEndpoint);
}), }),
map((channels: Channel[]) => { map((channels: Channel[]) => {
this.logger.info(channels); this.logger.info(channels);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.COMPLETED } }));
const sortedChannels = { activeChannels: <Channel[]>[], pendingChannels: <Channel[]>[], inactiveChannels: <Channel[]>[] }; const sortedChannels = { activeChannels: <Channel[]>[], pendingChannels: <Channel[]>[], inactiveChannels: <Channel[]>[] };
channels.forEach((channel) => { channels.forEach((channel) => {
if (channel.id) { channel.peer_id = channel.id; } if (channel.id) { channel.peer_id = channel.id; }
@ -368,7 +368,7 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.SAVE_NEW_CHANNEL_CLN), ofType(CLNActions.SAVE_NEW_CHANNEL_CLN),
mergeMap((action: { type: string, payload: SaveChannel }) => { mergeMap((action: { type: string, payload: SaveChannel }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.OPEN_CHANNEL })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.OPEN_CHANNEL }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewChannel', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewChannel', status: APICallStatusEnum.INITIATED } }));
const newPayload = { id: action.payload.peerId, satoshis: action.payload.satoshis, feeRate: action.payload.feeRate, announce: action.payload.announce }; const newPayload = { id: action.payload.peerId, satoshis: action.payload.satoshis, feeRate: action.payload.feeRate, announce: action.payload.announce };
if (action.payload.minconf) { newPayload['minconf'] = action.payload.minconf; } if (action.payload.minconf) { newPayload['minconf'] = action.payload.minconf; }
if (action.payload.utxos) { newPayload['utxos'] = action.payload.utxos; } if (action.payload.utxos) { newPayload['utxos'] = action.payload.utxos; }
@ -378,7 +378,7 @@ export class CLNEffects implements OnDestroy {
pipe( pipe(
map((postRes: any) => { map((postRes: any) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewChannel', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewChannel', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.OPEN_CHANNEL })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.OPEN_CHANNEL }));
this.store.dispatch(openSnackBar({ payload: 'Channel Added Successfully!' })); this.store.dispatch(openSnackBar({ payload: 'Channel Added Successfully!' }));
this.store.dispatch(fetchBalance()); this.store.dispatch(fetchBalance());
@ -450,12 +450,12 @@ export class CLNEffects implements OnDestroy {
paymentsFetchCL = createEffect(() => this.actions.pipe( paymentsFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_PAYMENTS_CLN), ofType(CLNActions.FETCH_PAYMENTS_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPayments', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchPayments', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get<Payment[]>(this.CHILD_API_URL + API_END_POINTS.PAYMENTS_API); return this.httpClient.get<Payment[]>(this.CHILD_API_URL + API_END_POINTS.PAYMENTS_API);
}), }),
map((payments) => { map((payments) => {
this.logger.info(payments); this.logger.info(payments);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPayments', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchPayments', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_PAYMENTS_CLN, type: CLNActions.SET_PAYMENTS_CLN,
payload: payments || [] payload: payments || []
@ -472,13 +472,13 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.FETCH_OFFER_INVOICE_CLN), ofType(CLNActions.FETCH_OFFER_INVOICE_CLN),
mergeMap((action: { type: string, payload: { offer: string, amount_msat?: string } }) => { mergeMap((action: { type: string, payload: { offer: string, amount_msat?: string } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.FETCH_INVOICE })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.FETCH_INVOICE }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchOfferInvoice', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchOfferInvoice', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/fetchOfferInvoice', action.payload). return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/fetchOfferInvoice', action.payload).
pipe( pipe(
map((fetchedInvoice: any) => { map((fetchedInvoice: any) => {
this.logger.info(fetchedInvoice); this.logger.info(fetchedInvoice);
setTimeout(() => { setTimeout(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchOfferInvoice', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchOfferInvoice', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.FETCH_INVOICE })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.FETCH_INVOICE }));
this.store.dispatch(setOfferInvoice({ payload: (fetchedInvoice ? fetchedInvoice : {}) })); this.store.dispatch(setOfferInvoice({ payload: (fetchedInvoice ? fetchedInvoice : {}) }));
}, 500); }, 500);
@ -507,11 +507,11 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.SEND_PAYMENT_CLN), ofType(CLNActions.SEND_PAYMENT_CLN),
mergeMap((action: { type: string, payload: SendPayment }) => { mergeMap((action: { type: string, payload: SendPayment }) => {
this.store.dispatch(openSpinner({ payload: action.payload.uiMessage })); this.store.dispatch(openSpinner({ payload: action.payload.uiMessage }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SendPayment', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SendPayment', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.PAYMENTS_API, action.payload).pipe( return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.PAYMENTS_API, action.payload).pipe(
map((sendRes: any) => { map((sendRes: any) => {
this.logger.info(sendRes); this.logger.info(sendRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SendPayment', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SendPayment', status: APICallStatusEnum.COMPLETED } }));
let snackBarMessageStr = 'Payment Sent Successfully!'; let snackBarMessageStr = 'Payment Sent Successfully!';
if (sendRes.saveToDBError) { if (sendRes.saveToDBError) {
snackBarMessageStr = 'Payment Sent Successfully but Offer Saving to Database Failed.'; snackBarMessageStr = 'Payment Sent Successfully but Offer Saving to Database Failed.';
@ -546,12 +546,12 @@ export class CLNEffects implements OnDestroy {
queryRoutesFetchCL = createEffect(() => this.actions.pipe( queryRoutesFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.GET_QUERY_ROUTES_CLN), ofType(CLNActions.GET_QUERY_ROUTES_CLN),
mergeMap((action: { type: string, payload: GetQueryRoutes }) => { mergeMap((action: { type: string, payload: GetQueryRoutes }) => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'GetQueryRoutes', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'GetQueryRoutes', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/getRoute/' + action.payload.destPubkey + '/' + action.payload.amount). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/getRoute/' + action.payload.destPubkey + '/' + action.payload.amount).
pipe( pipe(
map((qrRes: any) => { map((qrRes: any) => {
this.logger.info(qrRes); this.logger.info(qrRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'GetQueryRoutes', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'GetQueryRoutes', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_QUERY_ROUTES_CLN, type: CLNActions.SET_QUERY_ROUTES_CLN,
payload: qrRes payload: qrRes
@ -578,12 +578,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.PEER_LOOKUP_CLN), ofType(CLNActions.PEER_LOOKUP_CLN),
mergeMap((action: { type: string, payload: string }) => { mergeMap((action: { type: string, payload: string }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.SEARCHING_NODE })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.SEARCHING_NODE }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listNode/' + action.payload). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listNode/' + action.payload).
pipe( pipe(
map((resPeer) => { map((resPeer) => {
this.logger.info(resPeer); this.logger.info(resPeer);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.SEARCHING_NODE })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.SEARCHING_NODE }));
return { return {
type: CLNActions.SET_LOOKUP_CLN, type: CLNActions.SET_LOOKUP_CLN,
@ -602,12 +602,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.CHANNEL_LOOKUP_CLN), ofType(CLNActions.CHANNEL_LOOKUP_CLN),
mergeMap((action: { type: string, payload: ChannelLookup }) => { mergeMap((action: { type: string, payload: ChannelLookup }) => {
this.store.dispatch(openSpinner({ payload: action.payload.uiMessage })); this.store.dispatch(openSpinner({ payload: action.payload.uiMessage }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listChannel/' + action.payload.shortChannelID). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listChannel/' + action.payload.shortChannelID).
pipe( pipe(
map((resChannel) => { map((resChannel) => {
this.logger.info(resChannel); this.logger.info(resChannel);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: action.payload.uiMessage })); this.store.dispatch(closeSpinner({ payload: action.payload.uiMessage }));
return { return {
type: CLNActions.SET_LOOKUP_CLN, type: CLNActions.SET_LOOKUP_CLN,
@ -631,12 +631,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.INVOICE_LOOKUP_CLN), ofType(CLNActions.INVOICE_LOOKUP_CLN),
mergeMap((action: { type: string, payload: string }) => { mergeMap((action: { type: string, payload: string }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.SEARCHING_INVOICE })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.SEARCHING_INVOICE }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.INVOICES_API + '?label=' + action.payload). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.INVOICES_API + '?label=' + action.payload).
pipe( pipe(
map((resInvoice: any) => { map((resInvoice: any) => {
this.logger.info(resInvoice); this.logger.info(resInvoice);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.SEARCHING_INVOICE })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.SEARCHING_INVOICE }));
if (resInvoice.invoices && resInvoice.invoices.length && resInvoice.invoices.length > 0) { if (resInvoice.invoices && resInvoice.invoices.length && resInvoice.invoices.length > 0) {
this.store.dispatch(updateInvoice({ payload: resInvoice.invoices[0] })); this.store.dispatch(updateInvoice({ payload: resInvoice.invoices[0] }));
@ -670,12 +670,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.GET_FORWARDING_HISTORY_CLN), ofType(CLNActions.GET_FORWARDING_HISTORY_CLN),
mergeMap((action: { type: string, payload: { status: string } }) => { mergeMap((action: { type: string, payload: { status: string } }) => {
const statusInitial = action.payload.status.charAt(0).toUpperCase(); const statusInitial = action.payload.status.charAt(0).toUpperCase();
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchForwardingHistory' + statusInitial, status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchForwardingHistory' + statusInitial, status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + '/listForwards?status=' + action.payload.status). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + '/listForwards?status=' + action.payload.status).
pipe( pipe(
map((fhRes: any) => { map((fhRes: any) => {
this.logger.info(fhRes); this.logger.info(fhRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchForwardingHistory' + statusInitial, status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchForwardingHistory' + statusInitial, status: APICallStatusEnum.COMPLETED } }));
if (action.payload.status === CLNForwardingEventsStatusEnum.FAILED) { if (action.payload.status === CLNForwardingEventsStatusEnum.FAILED) {
this.store.dispatch(setForwardingHistory({ payload: { status: CLNForwardingEventsStatusEnum.FAILED, totalForwards: fhRes.length, listForwards: fhRes } })); this.store.dispatch(setForwardingHistory({ payload: { status: CLNForwardingEventsStatusEnum.FAILED, totalForwards: fhRes.length, listForwards: fhRes } }));
} else if (action.payload.status === CLNForwardingEventsStatusEnum.LOCAL_FAILED) { } else if (action.payload.status === CLNForwardingEventsStatusEnum.LOCAL_FAILED) {
@ -721,14 +721,14 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.SAVE_NEW_INVOICE_CLN), ofType(CLNActions.SAVE_NEW_INVOICE_CLN),
mergeMap((action: { type: string, payload: { amount: number, label: string, description: string, expiry: number, private: boolean } }) => { mergeMap((action: { type: string, payload: { amount: number, label: string, description: string, expiry: number, private: boolean } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.ADD_INVOICE })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.ADD_INVOICE }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewInvoice', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewInvoice', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.INVOICES_API, { return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.INVOICES_API, {
label: action.payload.label, amount: action.payload.amount, description: action.payload.description, expiry: action.payload.expiry, private: action.payload.private label: action.payload.label, amount: action.payload.amount, description: action.payload.description, expiry: action.payload.expiry, private: action.payload.private
}). }).
pipe( pipe(
map((postRes: Invoice) => { map((postRes: Invoice) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewInvoice', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewInvoice', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.ADD_INVOICE })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.ADD_INVOICE }));
postRes.amount_msat = action.payload.amount; postRes.amount_msat = action.payload.amount;
postRes.label = action.payload.label; postRes.label = action.payload.label;
@ -763,12 +763,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.SAVE_NEW_OFFER_CLN), ofType(CLNActions.SAVE_NEW_OFFER_CLN),
mergeMap((action: { type: string, payload: { amount: string, description: string, issuer: string } }) => { mergeMap((action: { type: string, payload: { amount: string, description: string, issuer: string } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.CREATE_OFFER })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.CREATE_OFFER }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewOffer', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewOffer', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.OFFERS_API, { return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.OFFERS_API, {
amount: action.payload.amount, description: action.payload.description, issuer: action.payload.issuer amount: action.payload.amount, description: action.payload.description, issuer: action.payload.issuer
}).pipe(map((postRes: Offer) => { }).pipe(map((postRes: Offer) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewOffer', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SaveNewOffer', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.CREATE_OFFER })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.CREATE_OFFER }));
setTimeout(() => { setTimeout(() => {
this.store.dispatch(openAlert({ this.store.dispatch(openAlert({
@ -796,7 +796,7 @@ export class CLNEffects implements OnDestroy {
invoicesFetchCL = createEffect(() => this.actions.pipe( invoicesFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_INVOICES_CLN), ofType(CLNActions.FETCH_INVOICES_CLN),
mergeMap((action: { type: string, payload: FetchInvoices }) => { mergeMap((action: { type: string, payload: FetchInvoices }) => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchInvoices', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchInvoices', status: APICallStatusEnum.INITIATED } }));
const num_max_invoices = (action.payload.num_max_invoices) ? action.payload.num_max_invoices : 1000000; const num_max_invoices = (action.payload.num_max_invoices) ? action.payload.num_max_invoices : 1000000;
const index_offset = (action.payload.index_offset) ? action.payload.index_offset : 0; const index_offset = (action.payload.index_offset) ? action.payload.index_offset : 0;
const reversed = (action.payload.reversed) ? action.payload.reversed : true; const reversed = (action.payload.reversed) ? action.payload.reversed : true;
@ -804,7 +804,7 @@ export class CLNEffects implements OnDestroy {
pipe( pipe(
map((res: ListInvoices) => { map((res: ListInvoices) => {
this.logger.info(res); this.logger.info(res);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchInvoices', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchInvoices', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_INVOICES_CLN, type: CLNActions.SET_INVOICES_CLN,
payload: res payload: res
@ -821,11 +821,11 @@ export class CLNEffects implements OnDestroy {
offersFetchCL = createEffect(() => this.actions.pipe( offersFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_OFFERS_CLN), ofType(CLNActions.FETCH_OFFERS_CLN),
mergeMap((action: { type: string, payload: any }) => { mergeMap((action: { type: string, payload: any }) => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchOffers', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchOffers', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.OFFERS_API). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.OFFERS_API).
pipe(map((res: any) => { pipe(map((res: any) => {
this.logger.info(res); this.logger.info(res);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchOffers', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchOffers', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_OFFERS_CLN, type: CLNActions.SET_OFFERS_CLN,
payload: res.offers ? res.offers : [] payload: res.offers ? res.offers : []
@ -841,11 +841,11 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.DISABLE_OFFER_CLN), ofType(CLNActions.DISABLE_OFFER_CLN),
mergeMap((action: { type: string, payload: { offer_id: string } }) => { mergeMap((action: { type: string, payload: { offer_id: string } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.DISABLE_OFFER })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.DISABLE_OFFER }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'DisableOffer', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'DisableOffer', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.delete(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/' + action.payload.offer_id). return this.httpClient.delete(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/' + action.payload.offer_id).
pipe(map((postRes: any) => { pipe(map((postRes: any) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'DisableOffer', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'DisableOffer', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.DISABLE_OFFER })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.DISABLE_OFFER }));
this.store.dispatch(openSnackBar({ payload: 'Offer Disabled Successfully!' })); this.store.dispatch(openSnackBar({ payload: 'Offer Disabled Successfully!' }));
return { return {
@ -862,11 +862,11 @@ export class CLNEffects implements OnDestroy {
offerBookmarksFetchCL = createEffect(() => this.actions.pipe( offerBookmarksFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_OFFER_BOOKMARKS_CLN), ofType(CLNActions.FETCH_OFFER_BOOKMARKS_CLN),
mergeMap((action: { type: string, payload: any }) => { mergeMap((action: { type: string, payload: any }) => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchOfferBookmarks', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchOfferBookmarks', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/offerbookmarks'). return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/offerbookmarks').
pipe(map((res: any) => { pipe(map((res: any) => {
this.logger.info(res); this.logger.info(res);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchOfferBookmarks', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchOfferBookmarks', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_OFFER_BOOKMARKS_CLN, type: CLNActions.SET_OFFER_BOOKMARKS_CLN,
payload: res || [] payload: res || []
@ -882,11 +882,11 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.DELETE_OFFER_BOOKMARK_CLN), ofType(CLNActions.DELETE_OFFER_BOOKMARK_CLN),
mergeMap((action: { type: string, payload: { bolt12: string } }) => { mergeMap((action: { type: string, payload: { bolt12: string } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.DELETE_OFFER_BOOKMARK })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.DELETE_OFFER_BOOKMARK }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'DeleteOfferBookmark', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'DeleteOfferBookmark', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.delete(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/offerbookmark/' + action.payload.bolt12). return this.httpClient.delete(this.CHILD_API_URL + API_END_POINTS.OFFERS_API + '/offerbookmark/' + action.payload.bolt12).
pipe(map((postRes: any) => { pipe(map((postRes: any) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'DeleteOfferBookmark', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'DeleteOfferBookmark', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.DELETE_OFFER_BOOKMARK })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.DELETE_OFFER_BOOKMARK }));
this.store.dispatch(openSnackBar({ payload: 'Offer Bookmark Deleted Successfully!' })); this.store.dispatch(openSnackBar({ payload: 'Offer Bookmark Deleted Successfully!' }));
return { return {
@ -904,12 +904,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.SET_CHANNEL_TRANSACTION_CLN), ofType(CLNActions.SET_CHANNEL_TRANSACTION_CLN),
mergeMap((action: { type: string, payload: OnChain }) => { mergeMap((action: { type: string, payload: OnChain }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.SEND_FUNDS })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.SEND_FUNDS }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SetChannelTransaction', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SetChannelTransaction', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.ON_CHAIN_API, action.payload). return this.httpClient.post(this.CHILD_API_URL + API_END_POINTS.ON_CHAIN_API, action.payload).
pipe( pipe(
map((postRes: any) => { map((postRes: any) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SetChannelTransaction', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SetChannelTransaction', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.SEND_FUNDS })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.SEND_FUNDS }));
this.store.dispatch(fetchBalance()); this.store.dispatch(fetchBalance());
this.store.dispatch(fetchUTXOs()); this.store.dispatch(fetchUTXOs());
@ -929,12 +929,12 @@ export class CLNEffects implements OnDestroy {
utxosFetch = createEffect(() => this.actions.pipe( utxosFetch = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_UTXOS_CLN), ofType(CLNActions.FETCH_UTXOS_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchUTXOs', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchUTXOs', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.ON_CHAIN_API + '/utxos'); return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.ON_CHAIN_API + '/utxos');
}), }),
map((utxos: any) => { map((utxos: any) => {
this.logger.info(utxos); this.logger.info(utxos);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchUTXOs', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchUTXOs', status: APICallStatusEnum.COMPLETED } }));
utxos.outputs.forEach((output) => { // For backward compatibility utxos.outputs.forEach((output) => { // For backward compatibility
if (output.value) { if (output.value) {
output.amount_msat = output.value; output.amount_msat = output.value;
@ -954,11 +954,11 @@ export class CLNEffects implements OnDestroy {
pageSettingsFetchCL = createEffect(() => this.actions.pipe( pageSettingsFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_PAGE_SETTINGS_CLN), ofType(CLNActions.FETCH_PAGE_SETTINGS_CLN),
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPageSettings', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchPageSettings', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(API_END_POINTS.PAGE_SETTINGS_API).pipe( return this.httpClient.get(API_END_POINTS.PAGE_SETTINGS_API).pipe(
map((pageSettings: any) => { map((pageSettings: any) => {
this.logger.info(pageSettings); this.logger.info(pageSettings);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPageSettings', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'FetchPageSettings', status: APICallStatusEnum.COMPLETED } }));
return { return {
type: CLNActions.SET_PAGE_SETTINGS_CLN, type: CLNActions.SET_PAGE_SETTINGS_CLN,
payload: pageSettings || [] payload: pageSettings || []
@ -976,12 +976,12 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.SAVE_PAGE_SETTINGS_CLN), ofType(CLNActions.SAVE_PAGE_SETTINGS_CLN),
mergeMap((action: { type: string, payload: any }) => { mergeMap((action: { type: string, payload: any }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.UPDATE_PAGE_SETTINGS })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.UPDATE_PAGE_SETTINGS }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SavePageSettings', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SavePageSettings', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(API_END_POINTS.PAGE_SETTINGS_API, action.payload). return this.httpClient.post(API_END_POINTS.PAGE_SETTINGS_API, action.payload).
pipe( pipe(
map((postRes: any) => { map((postRes: any) => {
this.logger.info(postRes); this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SavePageSettings', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'SavePageSettings', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.UPDATE_PAGE_SETTINGS })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.UPDATE_PAGE_SETTINGS }));
this.store.dispatch(openSnackBar({ payload: 'Page Layout Updated Successfully!' })); this.store.dispatch(openSnackBar({ payload: 'Page Layout Updated Successfully!' }));
return { return {
@ -1021,7 +1021,6 @@ export class CLNEffects implements OnDestroy {
newRoute = '/cln/home'; newRoute = '/cln/home';
} }
this.router.navigate([newRoute]); this.router.navigate([newRoute]);
this.store.dispatch(fetchPageSettings());
this.store.dispatch(fetchInvoices({ payload: { num_max_invoices: 1000000, index_offset: 0, reversed: true } })); this.store.dispatch(fetchInvoices({ payload: { num_max_invoices: 1000000, index_offset: 0, reversed: true } }));
this.store.dispatch(fetchFees()); this.store.dispatch(fetchFees());
this.store.dispatch(fetchChannels()); this.store.dispatch(fetchChannels());
@ -1044,7 +1043,7 @@ export class CLNEffects implements OnDestroy {
} else { } else {
this.store.dispatch(closeSpinner({ payload: uiMessage })); this.store.dispatch(closeSpinner({ payload: uiMessage }));
const errMsg = this.commonService.extractErrorMessage(err, genericErrorMessage); const errMsg = this.commonService.extractErrorMessage(err, genericErrorMessage);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: actionName, status: APICallStatusEnum.ERROR, statusCode: err.status.toString(), message: errMsg } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: actionName, status: APICallStatusEnum.ERROR, statusCode: err.status.toString(), message: errMsg } }));
} }
} }
@ -1068,7 +1067,7 @@ export class CLNEffects implements OnDestroy {
} }
} }
})); }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: actionName, status: APICallStatusEnum.ERROR, statusCode: err.status.toString(), message: errMsg, URL: errURL } })); this.store.dispatch(updateCLNAPICallStatus({ payload: { action: actionName, status: APICallStatusEnum.ERROR, statusCode: err.status.toString(), message: errMsg, URL: errURL } }));
} }
} }

@ -1,17 +1,17 @@
import { createReducer, on } from '@ngrx/store'; import { createReducer, on } from '@ngrx/store';
import { initCLNState } from './cln.state'; import { initCLNState } from './cln.state';
import { import {
addInvoice, addPeer, removeChannel, removePeer, resetCLStore, setBalance, setChannels, addInvoice, addPeer, removeChannel, removePeer, resetCLNStore, setBalance, setChannels,
setChildNodeSettingsCL, setFeeRates, setFees, setForwardingHistory, setChildNodeSettingsCLN, setFeeRates, setFees, setForwardingHistory,
setInfo, setInvoices, setLocalRemoteBalance, setOffers, addOffer, setPayments, setPeers, setUTXOs, setInfo, setInvoices, setLocalRemoteBalance, setOffers, addOffer, setPayments, setPeers, setUTXOs,
updateCLAPICallStatus, updateInvoice, updateOffer, setOfferBookmarks, addUpdateOfferBookmark, removeOfferBookmark, setPageSettings updateCLNAPICallStatus, updateInvoice, updateOffer, setOfferBookmarks, addUpdateOfferBookmark, removeOfferBookmark, setPageSettings
} from './cln.actions'; } from './cln.actions';
import { Channel, OfferBookmark } from '../../shared/models/clnModels'; import { Channel, OfferBookmark } from '../../shared/models/clnModels';
import { CLNForwardingEventsStatusEnum, CLN_DEFAULT_PAGE_SETTINGS } from '../../shared/services/consts-enums-functions'; import { CLNForwardingEventsStatusEnum, CLN_DEFAULT_PAGE_SETTINGS } from '../../shared/services/consts-enums-functions';
import { PageSettings } from '../../shared/models/pageSettings'; import { PageSettings } from '../../shared/models/pageSettings';
export const CLNReducer = createReducer(initCLNState, export const CLNReducer = createReducer(initCLNState,
on(updateCLAPICallStatus, (state, { payload }) => { on(updateCLNAPICallStatus, (state, { payload }) => {
const updatedApisCallStatus = JSON.parse(JSON.stringify(state.apisCallStatus)); const updatedApisCallStatus = JSON.parse(JSON.stringify(state.apisCallStatus));
if (payload.action) { if (payload.action) {
updatedApisCallStatus[payload.action] = { updatedApisCallStatus[payload.action] = {
@ -27,11 +27,11 @@ export const CLNReducer = createReducer(initCLNState,
apisCallStatus: updatedApisCallStatus apisCallStatus: updatedApisCallStatus
}; };
}), }),
on(setChildNodeSettingsCL, (state, { payload }) => ({ on(setChildNodeSettingsCLN, (state, { payload }) => ({
...state, ...state,
nodeSettings: payload nodeSettings: payload
})), })),
on(resetCLStore, (state, { payload }) => ({ on(resetCLNStore, (state, { payload }) => ({
...initCLNState, ...initCLNState,
nodeSettings: payload nodeSettings: payload
})), })),

@ -35,7 +35,7 @@
<mat-icon matTooltip="Include routing hints for private channels" matTooltipPosition="above" class="info-icon">info_outline</mat-icon> <mat-icon matTooltip="Include routing hints for private channels" matTooltipPosition="above" class="info-icon">info_outline</mat-icon>
</div> </div>
<div *ngIf="invoiceError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="invoiceError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span *ngIf="invoiceError !== ''">{{invoiceError}}</span> <span *ngIf="invoiceError !== ''">{{invoiceError}}</span>
</div> </div>
<div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center"> <div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center">

@ -1,12 +1,12 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch"> <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="35" class="modal-qr-code-container padding-gap-large" [fxLayoutAlign]="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== '')) ? 'center start' : 'center center'" [ngClass]="{'display-none': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}"> <div fxFlex="35" class="modal-qr-code-container padding-gap-large" [fxLayoutAlign]="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== '')) ? 'center start' : 'center center'" [ngClass]="{'display-none': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">
<qr-code *ngIf="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== ''))" [value]="invoice?.bolt11 || invoice?.bolt12" [size]="qrWidth" [errorCorrectionLevel]="'L'"></qr-code> <qr-code *ngIf="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== ''))" [value]="invoice?.bolt11 || invoice?.bolt12" [size]="qrWidth" [errorCorrectionLevel]="'L'" />
<span *ngIf="!invoice?.bolt11 && !invoice?.bolt12" class="font-size-300">N/A</span> <span *ngIf="!invoice?.bolt11 && !invoice?.bolt12" class="font-size-300">N/A</span>
</div> </div>
<div fxFlex="65"> <div fxFlex="65">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header"> <mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start"> <div fxFlex="95" fxLayoutAlign="start start">
<fa-icon class="page-title-img mr-1" [icon]="faReceipt"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faReceipt" />
<span class="page-title"> <span class="page-title">
{{screenSize === screenSizeEnum.XS ? (newlyAdded ? 'Created' : 'Invoice') : (newlyAdded ? 'Invoice Created' : 'Invoice Information')}} {{screenSize === screenSizeEnum.XS ? (newlyAdded ? 'Created' : 'Invoice') : (newlyAdded ? 'Invoice Created' : 'Invoice Information')}}
<span *ngIf="invoice?.status === 'paid'" class="dot green ml-1" matTooltip="Paid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="invoice?.status === 'paid'" class="dot green ml-1" matTooltip="Paid" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
@ -19,13 +19,13 @@
<mat-card-content class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}"> <mat-card-content class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column"> <div fxLayout="column">
<div fxFlex="30" class="modal-qr-code-container padding-gap" [fxLayoutAlign]="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== '')) ? 'center start' : 'center center'" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}"> <div fxFlex="30" class="modal-qr-code-container padding-gap" [fxLayoutAlign]="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== '')) ? 'center start' : 'center center'" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qr-code *ngIf="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== ''))" [value]="invoice?.bolt11 || invoice?.bolt12" [size]="qrWidth" [errorCorrectionLevel]="'L'"></qr-code> <qr-code *ngIf="((invoice?.bolt11 && invoice?.bolt11 !== '') || (invoice?.bolt12 && invoice?.bolt12 !== ''))" [value]="invoice?.bolt11 || invoice?.bolt12" [size]="qrWidth" [errorCorrectionLevel]="'L'" />
<span *ngIf="!invoice?.bolt11 && !invoice?.bolt12" class="font-size-120">QR Code Not Applicable</span> <span *ngIf="!invoice?.bolt11 && !invoice?.bolt12" class="font-size-120">QR Code Not Applicable</span>
</div> </div>
<mat-divider *ngIf="screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM" class="my-1"></mat-divider> <mat-divider *ngIf="screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM" class="my-1" />
<div *ngIf="invoice?.warning_capacity" fxLayout="row"> <div *ngIf="invoice?.warning_capacity" fxLayout="row">
<div fxFlex="100" class="alert alert-warn"> <div fxFlex="100" class="alert alert-warn">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>{{invoice?.warning_capacity}}</span> <span>{{invoice?.warning_capacity}}</span>
</div> </div>
</div> </div>
@ -50,12 +50,12 @@
</ng-container> </ng-container>
<ng-container *ngIf="invoice?.status !== 'paid'"> <ng-container *ngIf="invoice?.status !== 'paid'">
<span *ngIf="invoice?.status !== 'unpaid' || !flgVersionCompatible">-</span> <span *ngIf="invoice?.status !== 'unpaid' || !flgVersionCompatible">-</span>
<mat-spinner *ngIf="invoice?.status === 'unpaid' && flgVersionCompatible" [diameter]="20"></mat-spinner> <mat-spinner *ngIf="invoice?.status === 'unpaid' && flgVersionCompatible" [diameter]="20" />
</ng-container> </ng-container>
</span> </span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="50"> <div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Date Expiry</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Date Expiry</h4>
@ -66,14 +66,14 @@
<span class="foreground-secondary-text">{{((invoice?.paid_at * 1000) | date:'dd/MMM/y HH:mm') || '-'}}</span> <span class="foreground-secondary-text">{{((invoice?.paid_at * 1000) | date:'dd/MMM/y HH:mm') || '-'}}</span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Description</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Description</h4>
<span class="foreground-secondary-text">{{invoice?.description || '-'}}</span> <span class="foreground-secondary-text">{{invoice?.description || '-'}}</span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">{{ invoice?.bolt12 ? 'Bolt12' : (invoice?.bolt11 && !invoice.label.includes('keysend-')) ? 'Bolt11' : 'Keysend' }} Invoice</h4> <h4 fxLayoutAlign="start" class="font-bold-500">{{ invoice?.bolt12 ? 'Bolt12' : (invoice?.bolt11 && !invoice.label.includes('keysend-')) ? 'Bolt11' : 'Keysend' }} Invoice</h4>
@ -81,21 +81,21 @@
</div> </div>
</div> </div>
<div *ngIf="showAdvanced"> <div *ngIf="showAdvanced">
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Payment Hash</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Payment Hash</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice?.payment_hash}}</span> <span class="overflow-wrap foreground-secondary-text">{{invoice?.payment_hash}}</span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Label</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Label</h4>
<span class="overflow-wrap foreground-secondary-text">{{invoice?.label}}</span> <span class="overflow-wrap foreground-secondary-text">{{invoice?.label}}</span>
</div> </div>
</div> </div>
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1" />
</div> </div>
<div fxLayout="row" fxLayoutAlign="end center" [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}"> <div fxLayout="row" fxLayoutAlign="end center" [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}">
<button class="mr-1" mat-button color="primary" type="reset" tabindex="1" (click)="onShowAdvanced()"> <button class="mr-1" mat-button color="primary" type="reset" tabindex="1" (click)="onShowAdvanced()">

@ -22,7 +22,7 @@
<div *ngIf="calledFrom === 'transactions'" fxLayout="column" fxLayoutAlign="start stretch"> <div *ngIf="calledFrom === 'transactions'" fxLayout="column" fxLayoutAlign="start stretch">
<div fxLayout="column" fxLayoutAlign="start stretch" fxLayout.gt-sm="row wrap" class="page-sub-title-container mt-1"> <div fxLayout="column" fxLayoutAlign="start stretch" fxLayout.gt-sm="row wrap" class="page-sub-title-container mt-1">
<div fxFlex="70" fxLayoutAlign="start start" fxLayoutAlign.gt-sm="start center"> <div fxFlex="70" fxLayoutAlign="start start" fxLayoutAlign.gt-sm="start center">
<fa-icon class="page-title-img mr-1" [icon]="faHistory"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faHistory" />
<span class="page-title">Invoices History</span> <span class="page-title">Invoices History</span>
</div> </div>
<div fxFlex.gt-xs="30" fxLayoutAlign.gt-xs="space-between center" fxLayout="row" fxLayoutAlign="space-between stretch"> <div fxFlex.gt-xs="30" fxLayoutAlign.gt-xs="space-between center" fxLayout="row" fxLayoutAlign="space-between stretch">
@ -39,7 +39,7 @@
</div> </div>
</div> </div>
<div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]> <div fxLayout="column" fxFlex="100" class="table-container" [perfectScrollbar]>
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate" />
<table #table mat-table fxFlex="100" matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="invoices" [ngClass]="{'error-border': errorMessage !== ''}"> <table #table mat-table fxFlex="100" matSort [matSortActive]="tableSetting.sortBy" [matSortDirection]="tableSetting.sortOrder" [dataSource]="invoices" [ngClass]="{'error-border': errorMessage !== ''}">
<ng-container matColumnDef="status"> <ng-container matColumnDef="status">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before" matTooltip="Status"></th> <th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before" matTooltip="Status"></th>
@ -107,7 +107,7 @@
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0"> <mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option> <mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select> </mat-select>
</div> </div>
@ -115,7 +115,7 @@
<td *matCellDef="let invoice" mat-cell fxLayoutAlign="end center"> <td *matCellDef="let invoice" mat-cell fxLayoutAlign="end center">
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="4" class="mr-0"> <mat-select placeholder="Actions" tabindex="4" class="mr-0">
<mat-select-trigger></mat-select-trigger> <mat-select-trigger />
<mat-option (click)="onInvoiceClick(invoice)">View Info</mat-option> <mat-option (click)="onInvoiceClick(invoice)">View Info</mat-option>
<mat-option (click)="onRefreshInvoice(invoice)">Refresh</mat-option> <mat-option (click)="onRefreshInvoice(invoice)">Refresh</mat-option>
</mat-select> </mat-select>
@ -134,6 +134,6 @@
<tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr> <tr *matRowDef="let row; columns: displayedColumns;" mat-row></tr>
</table> </table>
</div> </div>
<mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true"></mat-paginator> <mat-paginator class="mb-1" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" />
</div> </div>
</div> </div>

@ -25,7 +25,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="offerError !== ''" fxFlex="100" class="alert alert-danger mt-1"> <div *ngIf="offerError !== ''" fxFlex="100" class="alert alert-danger mt-1">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle"></fa-icon> <fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span *ngIf="offerError !== ''">{{offerError}}</span> <span *ngIf="offerError !== ''">{{offerError}}</span>
</div> </div>
<div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center"> <div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center">

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save