Page Settings

Page Settings
pull/1127/head
ShahanaFarooqui 2 years ago
parent 8c4443a873
commit a72f00a97b

@ -108,7 +108,7 @@ export const postPayment = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Payment Sent', data: body });
if (req.body.paymentType === 'OFFER') {
if (req.body.saveToDB && req.body.bolt12) {
const offerToUpdate = { bolt12: req.body.bolt12, amountmSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
const offerToUpdate = { bolt12: req.body.bolt12, amountMSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
if (req.body.vendor) {
offerToUpdate['vendor'] = req.body.vendor;
}
@ -116,7 +116,7 @@ export const postPayment = (req, res, next) => {
offerToUpdate['description'] = req.body.description;
}
return databaseService.update(req.session.selectedNode, CollectionsEnum.OFFERS, offerToUpdate, CollectionFieldsEnum.BOLT12, req.body.bolt12).then((updatedOffer) => {
logger.log({ level: 'DEBUG', fileName: 'Offer', msg: 'Offer Updated', data: updatedOffer });
logger.log({ level: 'DEBUG', fileName: 'Payments', msg: 'Offer Updated', data: updatedOffer });
return res.status(201).json({ paymentResponse: body, saveToDBResponse: updatedOffer });
}).catch((errDB) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB update error', error: errDB });

@ -0,0 +1,27 @@
import { Database } from '../../utils/database.js';
import { Logger } from '../../utils/logger.js';
import { Common } from '../../utils/common.js';
import { CollectionsEnum } from '../../models/database.model.js';
const logger = Logger;
const common = Common;
const databaseService = Database;
export const getPageSettings = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Getting Page Settings..' });
databaseService.find(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS).then((settings) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Page Settings Received', data: settings });
res.status(200).json(settings);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const savePageSettings = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Saving Page Settings..' });
return databaseService.insert(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS, req.updatedSettings).then((insertedSettings) => {
logger.log({ level: 'DEBUG', fileName: 'Page Settings', msg: 'Page Settings Updated', data: insertedSettings });
return res.status(201).json(true);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Update Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};

@ -1,20 +1,15 @@
export var CollectionsEnum;
(function (CollectionsEnum) {
CollectionsEnum["OFFERS"] = "Offers";
})(CollectionsEnum || (CollectionsEnum = {}));
export var OfferFieldsEnum;
(function (OfferFieldsEnum) {
OfferFieldsEnum["BOLT12"] = "bolt12";
OfferFieldsEnum["AMOUNTMSAT"] = "amountmSat";
OfferFieldsEnum["AMOUNTMSAT"] = "amountMSat";
OfferFieldsEnum["TITLE"] = "title";
OfferFieldsEnum["VENDOR"] = "vendor";
OfferFieldsEnum["DESCRIPTION"] = "description";
})(OfferFieldsEnum || (OfferFieldsEnum = {}));
export const CollectionFieldsEnum = Object.assign({}, OfferFieldsEnum);
export class Offer {
constructor(bolt12, amountmSat, title, vendor, description, lastUpdatedAt) {
constructor(bolt12, amountMSat, title, vendor, description, lastUpdatedAt) {
this.bolt12 = bolt12;
this.amountmSat = amountmSat;
this.amountMSat = amountMSat;
this.title = title;
this.vendor = vendor;
this.description = description;
@ -23,16 +18,76 @@ export class Offer {
}
export const validateOffer = (documentToValidate) => {
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.BOLT12)) {
return ({ isValid: false, error: CollectionFieldsEnum.BOLT12 + 'is mandatory.' });
return ({ isValid: false, error: CollectionFieldsEnum.BOLT12 + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.AMOUNTMSAT)) {
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'is mandatory.' });
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TITLE)) {
return ({ isValid: false, error: CollectionFieldsEnum.TITLE + 'is mandatory.' });
return ({ isValid: false, error: CollectionFieldsEnum.TITLE + ' is mandatory.' });
}
if ((typeof documentToValidate[CollectionFieldsEnum.AMOUNTMSAT] !== 'number')) {
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'should be a number.' });
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + ' should be a number.' });
}
return ({ isValid: true });
};
export var SortOrderEnum;
(function (SortOrderEnum) {
SortOrderEnum["ASCENDING"] = "Ascending";
SortOrderEnum["DESCENDING"] = "Descending";
})(SortOrderEnum || (SortOrderEnum = {}));
export var PageSettingsFieldsEnum;
(function (PageSettingsFieldsEnum) {
PageSettingsFieldsEnum["PAYMENTS"] = "payments";
PageSettingsFieldsEnum["INVOICES"] = "invoices";
PageSettingsFieldsEnum["TABLES"] = "tables";
})(PageSettingsFieldsEnum || (PageSettingsFieldsEnum = {}));
export var TableSettingsFieldsEnum;
(function (TableSettingsFieldsEnum) {
TableSettingsFieldsEnum["TABLE_ID"] = "tableId";
TableSettingsFieldsEnum["RECORDS_PER_PAGE"] = "recordsPerPage";
TableSettingsFieldsEnum["SORT_BY"] = "sortBy";
TableSettingsFieldsEnum["SORT_ORDER"] = "sortOrder";
TableSettingsFieldsEnum["SHOW_COLUMNS"] = "showColumns";
})(TableSettingsFieldsEnum || (TableSettingsFieldsEnum = {}));
export class TableSetting {
constructor(tableId, recordsPerPage, sortBy, sortOrder, showColumns) {
this.tableId = tableId;
this.recordsPerPage = recordsPerPage;
this.sortBy = sortBy;
this.sortOrder = sortOrder;
this.showColumns = showColumns;
}
}
export class PageSettings {
constructor(pages) {
this.pages = pages;
}
}
export const validatePageSettings = (documentToValidate) => {
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.PAYMENTS)) {
return ({ isValid: false, error: CollectionFieldsEnum.PAYMENTS + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.INVOICES)) {
return ({ isValid: false, error: CollectionFieldsEnum.INVOICES + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TABLES)) {
return ({ isValid: false, error: CollectionFieldsEnum.TABLES + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TABLE_ID)) {
return ({ isValid: false, error: CollectionFieldsEnum.TABLE_ID + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.SHOW_COLUMNS)) {
return ({ isValid: false, error: CollectionFieldsEnum.SHOW_COLUMNS + ' is mandatory.' });
}
if (documentToValidate[CollectionFieldsEnum.SHOW_COLUMNS].length < 3) {
return ({ isValid: false, error: CollectionFieldsEnum.SHOW_COLUMNS + ' should have at least 2 fields.' });
}
return ({ isValid: true });
};
export var CollectionsEnum;
(function (CollectionsEnum) {
CollectionsEnum["OFFERS"] = "Offers";
CollectionsEnum["PAGE_SETTINGS"] = "PageSettings";
})(CollectionsEnum || (CollectionsEnum = {}));
export const CollectionFieldsEnum = Object.assign(Object.assign(Object.assign({}, OfferFieldsEnum), PageSettingsFieldsEnum), TableSettingsFieldsEnum);

@ -4,12 +4,14 @@ import authenticateRoutes from './authenticate.js';
import boltzRoutes from './boltz.js';
import loopRoutes from './loop.js';
import RTLConfRoutes from './RTLConf.js';
import pageSettingsRoutes from './pageSettings.js';
const router = Router();
const sharedRoutes = [
{ path: '/authenticate', route: authenticateRoutes },
{ path: '/boltz', route: boltzRoutes },
{ path: '/loop', route: loopRoutes },
{ path: '/conf', route: RTLConfRoutes }
{ path: '/conf', route: RTLConfRoutes },
{ path: '/pagesettings', route: pageSettingsRoutes }
];
sharedRoutes.forEach((route) => {
router.use(route.path, route.route);

@ -0,0 +1,8 @@
import exprs from 'express';
const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js';
import { getPageSettings, savePageSettings } from '../../controllers/shared/pageSettings.js';
const router = Router();
router.get('/', isAuthenticated, getPageSettings);
router.post('/', isAuthenticated, savePageSettings);
export default router;

@ -95,11 +95,11 @@ export const postPayment = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Payment Sent', data: body });
if (req.body.paymentType === 'OFFER') {
if (req.body.saveToDB && req.body.bolt12) {
const offerToUpdate: Offer = { bolt12: req.body.bolt12, amountmSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
const offerToUpdate: Offer = { bolt12: req.body.bolt12, amountMSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
if (req.body.vendor) { offerToUpdate['vendor'] = req.body.vendor; }
if (req.body.description) { offerToUpdate['description'] = req.body.description; }
return databaseService.update(req.session.selectedNode, CollectionsEnum.OFFERS, offerToUpdate, CollectionFieldsEnum.BOLT12, req.body.bolt12).then((updatedOffer) => {
logger.log({ level: 'DEBUG', fileName: 'Offer', msg: 'Offer Updated', data: updatedOffer });
logger.log({ level: 'DEBUG', fileName: 'Payments', msg: 'Offer Updated', data: updatedOffer });
return res.status(201).json({ paymentResponse: body, saveToDBResponse: updatedOffer });
}).catch((errDB) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB update error', error: errDB });

@ -0,0 +1,30 @@
import { Database, DatabaseService } from '../../utils/database.js';
import { Logger, LoggerService } from '../../utils/logger.js';
import { Common, CommonService } from '../../utils/common.js';
import { CollectionsEnum, PageSettings } from '../../models/database.model.js';
const logger: LoggerService = Logger;
const common: CommonService = Common;
const databaseService: DatabaseService = Database;
export const getPageSettings = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Getting Page Settings..' });
databaseService.find(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS).then((settings: PageSettings) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Page Settings Received', data: settings });
res.status(200).json(settings);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const savePageSettings = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Saving Page Settings..' });
return databaseService.insert(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS, req.updatedSettings).then((insertedSettings) => {
logger.log({ level: 'DEBUG', fileName: 'Page Settings', msg: 'Page Settings Updated', data: insertedSettings });
return res.status(201).json(true);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Update Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};

@ -1,26 +1,16 @@
export enum CollectionsEnum {
OFFERS = 'Offers'
}
export type Collections = {
Offers: Offer[];
}
export enum OfferFieldsEnum {
BOLT12 = 'bolt12',
AMOUNTMSAT = 'amountmSat',
AMOUNTMSAT = 'amountMSat',
TITLE = 'title',
VENDOR = 'vendor',
DESCRIPTION = 'description'
}
export const CollectionFieldsEnum = { ...OfferFieldsEnum };
export class Offer {
constructor(
public bolt12: string,
public amountmSat: number,
public amountMSat: number,
public title: string,
public vendor?: string,
public description?: string,
@ -31,16 +21,92 @@ export class Offer {
export const validateOffer = (documentToValidate): any => {
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.BOLT12)) {
return ({ isValid: false, error: CollectionFieldsEnum.BOLT12 + 'is mandatory.' });
return ({ isValid: false, error: CollectionFieldsEnum.BOLT12 + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.AMOUNTMSAT)) {
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'is mandatory.' });
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TITLE)) {
return ({ isValid: false, error: CollectionFieldsEnum.TITLE + 'is mandatory.' });
return ({ isValid: false, error: CollectionFieldsEnum.TITLE + ' is mandatory.' });
}
if ((typeof documentToValidate[CollectionFieldsEnum.AMOUNTMSAT] !== 'number')) {
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'should be a number.' });
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + ' should be a number.' });
}
return ({ isValid: true });
};
export enum SortOrderEnum {
ASCENDING = 'Ascending',
DESCENDING = 'Descending'
}
export enum PageSettingsFieldsEnum {
PAYMENTS = 'payments',
INVOICES = 'invoices',
TABLES = 'tables'
}
export enum TableSettingsFieldsEnum {
TABLE_ID = 'tableId',
RECORDS_PER_PAGE = 'recordsPerPage',
SORT_BY = 'sortBy',
SORT_ORDER = 'sortOrder',
SHOW_COLUMNS = 'showColumns'
}
export class TableSetting {
constructor(
public tableId: string,
public recordsPerPage?: number,
public sortBy?: string,
public sortOrder?: SortOrderEnum,
public showColumns?: any[]
) { }
}
export class PageSettings {
constructor(
public pages: {
payments: { tables: TableSetting[] };
invoices: { tables: TableSetting[] };
}
) { }
}
export const validatePageSettings = (documentToValidate): any => {
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.PAYMENTS)) {
return ({ isValid: false, error: CollectionFieldsEnum.PAYMENTS + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.INVOICES)) {
return ({ isValid: false, error: CollectionFieldsEnum.INVOICES + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TABLES)) {
return ({ isValid: false, error: CollectionFieldsEnum.TABLES + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TABLE_ID)) {
return ({ isValid: false, error: CollectionFieldsEnum.TABLE_ID + ' is mandatory.' });
}
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.SHOW_COLUMNS)) {
return ({ isValid: false, error: CollectionFieldsEnum.SHOW_COLUMNS + ' is mandatory.' });
}
if (documentToValidate[CollectionFieldsEnum.SHOW_COLUMNS].length < 3) {
return ({ isValid: false, error: CollectionFieldsEnum.SHOW_COLUMNS + ' should have at least 2 fields.' });
}
return ({ isValid: true });
};
export enum CollectionsEnum {
OFFERS = 'Offers',
PAGE_SETTINGS = 'PageSettings'
}
export type Collections = {
Offers: Offer[];
PageSettings: PageSettings;
}
export const CollectionFieldsEnum = { ...OfferFieldsEnum, ...PageSettingsFieldsEnum, ...TableSettingsFieldsEnum };

@ -4,6 +4,7 @@ import authenticateRoutes from './authenticate.js';
import boltzRoutes from './boltz.js';
import loopRoutes from './loop.js';
import RTLConfRoutes from './RTLConf.js';
import pageSettingsRoutes from './pageSettings.js';
const router = Router();
@ -11,7 +12,8 @@ const sharedRoutes = [
{ path: '/authenticate', route: authenticateRoutes },
{ path: '/boltz', route: boltzRoutes },
{ path: '/loop', route: loopRoutes },
{ path: '/conf', route: RTLConfRoutes }
{ path: '/conf', route: RTLConfRoutes },
{ path: '/pagesettings', route: pageSettingsRoutes }
];
sharedRoutes.forEach((route) => {

@ -0,0 +1,11 @@
import exprs from 'express';
const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js';
import { getPageSettings, savePageSettings } from '../../controllers/shared/pageSettings.js';
const router = Router();
router.get('/', isAuthenticated, getPageSettings);
router.post('/', isAuthenticated, savePageSettings);
export default router;

@ -4,6 +4,7 @@ import { CLNActions } from '../../shared/services/consts-enums-functions';
import { ApiCallStatusPayload } from '../../shared/models/apiCallsPayload';
import { SelNodeChild } from '../../shared/models/RTLconfig';
import { GetInfo, Fees, Peer, Payment, QueryRoutes, Channel, FeeRates, Invoice, ListInvoices, OnChain, UTXO, SaveChannel, GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, OfferInvoice, Offer, OfferBookmark, ListForwards, FetchListForwards, LocalFailedEvent, ForwardingEvent } from '../../shared/models/clnModels';
import { PageSettingsCLN } from '../../shared/models/pageSettings';
export const updateCLAPICallStatus = createAction(CLNActions.UPDATE_API_CALL_STATUS_CLN, props<{ payload: ApiCallStatusPayload }>());
@ -11,6 +12,12 @@ export const resetCLStore = createAction(CLNActions.RESET_CLN_STORE, props<{ pay
export const setChildNodeSettingsCL = createAction(CLNActions.SET_CHILD_NODE_SETTINGS_CLN, props<{ payload: SelNodeChild }>());
export const fetchPageSettingsCL = createAction(CLNActions.FETCH_PAGE_SETTINGS_CLN);
export const setPageSettings = createAction(CLNActions.SET_PAGE_SETTINGS_CLN, props<{ payload: PageSettingsCLN }>());
export const savePageSettings = createAction(CLNActions.SAVE_PAGE_SETTINGS_CLN, props<{ payload: PageSettingsCLN }>());
export const fetchInfoCL = createAction(CLNActions.FETCH_INFO_CLN, props<{ payload: { loadPage: string } }>());
export const setInfo = createAction(CLNActions.SET_INFO_CLN, props<{ payload: GetInfo }>());

@ -14,13 +14,13 @@ import { SessionService } from '../../shared/services/session.service';
import { WebSocketClientService } from '../../shared/services/web-socket.service';
import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component';
import { CLNInvoiceInformationComponent } from '../transactions/invoices/invoice-information-modal/invoice-information.component';
import { GetInfo, Fees, Balance, LocalRemoteBalance, Payment, FeeRates, ListInvoices, Invoice, Peer, OnChain, QueryRoutes, SaveChannel, GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, FetchInvoices, Channel, OfferInvoice, Offer, ListForwards, FetchListForwards, ForwardingEvent, LocalFailedEvent } from '../../shared/models/clnModels';
import { GetInfo, Fees, Balance, LocalRemoteBalance, Payment, FeeRates, ListInvoices, Invoice, Peer, OnChain, QueryRoutes, SaveChannel, GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, FetchInvoices, Channel, OfferInvoice, Offer } from '../../shared/models/clnModels';
import { AlertTypeEnum, APICallStatusEnum, UI_MESSAGES, CLNWSEventTypeEnum, CLNActions, RTLActions, CLNForwardingEventsStatusEnum } from '../../shared/services/consts-enums-functions';
import { closeAllDialogs, closeSpinner, logout, openAlert, openSnackBar, openSpinner, setApiUrl, setNodeData } from '../../store/rtl.actions';
import { RTLState } from '../../store/rtl.state';
import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance, fetchPayments, fetchPeers, fetchUTXOs, getForwardingHistory, setLookup, setPeers, setQueryRoutes, updateCLAPICallStatus, updateInvoice, setOfferInvoice, sendPaymentStatus, setForwardingHistory } from './cln.actions';
import { allAPIsCallStatus, clnNodeInformation } from './cln.selector';
import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance, fetchPayments, fetchPeers, fetchUTXOs, setLookup, setPeers, setQueryRoutes, updateCLAPICallStatus, updateInvoice, setOfferInvoice, sendPaymentStatus, setForwardingHistory, fetchPageSettingsCL } from './cln.actions';
import { allAPIsCallStatus } from './cln.selector';
import { ApiCallsListCL } from '../../shared/models/apiCallsPayload';
import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component';
@ -934,6 +934,51 @@ export class CLNEffects implements OnDestroy {
})
));
pageSettingsFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_PAGE_SETTINGS_CLN),
mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPageSettings', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(environment.PAGE_SETTINGS_API).pipe(
map((pageSettings: any) => {
this.logger.info(pageSettings);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchPageSettings', status: APICallStatusEnum.COMPLETED } }));
return {
type: CLNActions.SET_PAGE_SETTINGS_CLN,
payload: pageSettings
};
}),
catchError((err: any) => {
this.handleErrorWithoutAlert('FetchPageSettings', UI_MESSAGES.NO_SPINNER, 'Fetching Page Settings Failed.', err);
return of({ type: RTLActions.VOID });
})
);
})
));
savePageSettingsCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.SAVE_PAGE_SETTINGS_CLN),
mergeMap((action: { type: string, payload: any }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.UPDATE_PAGE_SETTINGS }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SavePageSettings', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(environment.PAGE_SETTINGS_API, action.payload).
pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SavePageSettings', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.UPDATE_PAGE_SETTINGS }));
return {
type: CLNActions.SET_PAGE_SETTINGS_CLN,
payload: postRes
};
}),
catchError((err: any) => {
this.handleErrorWithoutAlert('SavePageSettings', UI_MESSAGES.UPDATE_PAGE_SETTINGS, 'Page Settings Update Failed.', err);
return of({ type: RTLActions.VOID });
})
);
})
));
initializeRemainingData(info: any, landingPage: string) {
this.sessionService.setItem('clUnlocked', 'true');
const node_data = {
@ -958,6 +1003,7 @@ export class CLNEffects implements OnDestroy {
newRoute = '/cln/home';
}
this.router.navigate([newRoute]);
this.store.dispatch(fetchPageSettingsCL());
this.store.dispatch(fetchInvoices({ payload: { num_max_invoices: 1000000, index_offset: 0, reversed: true } }));
this.store.dispatch(fetchFees());
this.store.dispatch(fetchChannels());

@ -4,10 +4,11 @@ import {
addInvoice, addPeer, removeChannel, removePeer, resetCLStore, setBalance, setChannels,
setChildNodeSettingsCL, setFeeRates, setFees, setForwardingHistory,
setInfo, setInvoices, setLocalRemoteBalance, setOffers, addOffer, setPayments, setPeers, setUTXOs,
updateCLAPICallStatus, updateInvoice, updateOffer, setOfferBookmarks, addUpdateOfferBookmark, removeOfferBookmark
updateCLAPICallStatus, updateInvoice, updateOffer, setOfferBookmarks, addUpdateOfferBookmark, removeOfferBookmark, setPageSettings
} from './cln.actions';
import { Channel, OfferBookmark } from '../../shared/models/clnModels';
import { CLNForwardingEventsStatusEnum } from '../../shared/services/consts-enums-functions';
import { CLNForwardingEventsStatusEnum, CLN_DEFAULT_PAGE_SETTINGS } from '../../shared/services/consts-enums-functions';
import { PageSettingsCLN } from '../../shared/models/pageSettings';
export const CLNReducer = createReducer(initCLNState,
on(updateCLAPICallStatus, (state, { payload }) => {
@ -195,7 +196,7 @@ export const CLNReducer = createReducer(initCLNState,
} else {
const updatedOffer = { ...newOfferBMs[offerBMExistsIdx] };
updatedOffer.title = payload.title;
updatedOffer.amountmSat = payload.amountmSat;
updatedOffer.amountMSat = payload.amountMSat;
updatedOffer.lastUpdatedAt = payload.lastUpdatedAt;
updatedOffer.description = payload.description;
updatedOffer.vendor = payload.vendor;
@ -216,6 +217,16 @@ export const CLNReducer = createReducer(initCLNState,
...state,
offersBookmarks: modifiedOfferBookmarks
};
}),
on(setPageSettings, (state, { payload }) => {
const sortedPageSettings = Object.keys(CLN_DEFAULT_PAGE_SETTINGS).reduce((acc, page) => {
acc[page] = (payload && payload.hasOwnProperty(page)) ? payload[page] : CLN_DEFAULT_PAGE_SETTINGS[page];
return acc;
}, {});
return {
...state,
pageSettings: sortedPageSettings
};
})
);

@ -4,6 +4,7 @@ import { CLNState } from './cln.state';
export const clnState = createFeatureSelector<CLNState>('cln');
export const clnNodeSettings = createSelector(clnState, (state: CLNState) => state.nodeSettings);
export const clnPageSettings = createSelector(clnState, (state: CLNState) => ({ pageSettings: state.pageSettings, apiCallStatus: state.apisCallStatus.FetchPageSettings }));
export const clnNodeInformation = createSelector(clnState, (state: CLNState) => state.information);
export const apiCallStatusNodeInfo = createSelector(clnState, (state: CLNState) => state.apisCallStatus.FetchInfo);
export const allAPIsCallStatus = createSelector(clnState, (state: CLNState) => state.apisCallStatus);

@ -1,11 +1,13 @@
import { SelNodeChild } from '../../shared/models/RTLconfig';
import { APICallStatusEnum, UserPersonaEnum } from '../../shared/services/consts-enums-functions';
import { APICallStatusEnum, CLN_DEFAULT_PAGE_SETTINGS, UserPersonaEnum } from '../../shared/services/consts-enums-functions';
import { GetInfo, Fees, Balance, LocalRemoteBalance, Peer, Payment, Channel, FeeRates, ListInvoices, UTXO, Offer, OfferBookmark, ListForwards } from '../../shared/models/clnModels';
import { ApiCallsListCL } from '../../shared/models/apiCallsPayload';
import { PageSettingsCLN } from '../../shared/models/pageSettings';
export interface CLNState {
apisCallStatus: ApiCallsListCL;
nodeSettings: SelNodeChild | null;
pageSettings: PageSettingsCLN;
information: GetInfo;
fees: Fees;
feeRatesPerKB: FeeRates;
@ -28,6 +30,7 @@ export interface CLNState {
export const initCLNState: CLNState = {
apisCallStatus: {
FetchPageSettings: { status: APICallStatusEnum.UN_INITIATED },
FetchInfo: { status: APICallStatusEnum.UN_INITIATED },
FetchInvoices: { status: APICallStatusEnum.UN_INITIATED },
FetchFees: { status: APICallStatusEnum.UN_INITIATED },
@ -46,6 +49,7 @@ export const initCLNState: CLNState = {
FetchOfferBookmarks: { status: APICallStatusEnum.UN_INITIATED }
},
nodeSettings: { userPersona: UserPersonaEnum.OPERATOR, selCurrencyUnit: 'USD', fiatConversion: false, channelBackupPath: '', currencyUnits: [], enableOffers: false, enablePeerswap: false },
pageSettings: CLN_DEFAULT_PAGE_SETTINGS,
information: {},
fees: {},
feeRatesPerKB: {},

@ -25,9 +25,9 @@
</div>
</td>
</ng-container>
<ng-container matColumnDef="amountmSat">
<ng-container matColumnDef="amountMSat">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before" class="pr-2"> Amount (Sats) </th>
<td mat-cell *matCellDef="let offersbookmark" class="pr-2"><span fxLayoutAlign="end center">{{(offersbookmark.amountmSat === 0) ? 'Open' : (offersbookmark.amountmSat / 1000) | number}}</span></td>
<td mat-cell *matCellDef="let offersbookmark" class="pr-2"><span fxLayoutAlign="end center">{{(offersbookmark.amountMSat === 0) ? 'Open' : (offersbookmark.amountMSat / 1000) | number}}</span></td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Description </th>

@ -52,16 +52,16 @@ export class CLNOfferBookmarksTableComponent implements OnInit, AfterViewInit, O
this.screenSize = this.commonService.getScreenSize();
if (this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false;
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountmSat', 'actions'];
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountMSat', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.SM) {
this.flgSticky = false;
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountmSat', 'actions'];
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountMSat', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountmSat', 'description', 'actions'];
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountMSat', 'description', 'actions'];
} else {
this.flgSticky = true;
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountmSat', 'description', 'actions'];
this.displayedColumns = ['lastUpdatedAt', 'title', 'amountMSat', 'description', 'actions'];
}
}

@ -4,36 +4,36 @@
<fa-icon [icon]="faPenRuler" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Page Settings</span>
</div>
<mat-expansion-panel fxLayout="column" class="flat-expansion-panel mt-1" expanded="true" *ngFor="let page of pageSettings">
<mat-expansion-panel fxLayout="column" class="flat-expansion-panel mt-1" expanded="true" *ngFor="let page of pageSettings | keyvalue">
<mat-expansion-panel-header>
<mat-panel-title>{{page.pageId | titlecase}}</mat-panel-title>
<mat-panel-title>{{page.key | titlecase}}</mat-panel-title>
</mat-expansion-panel-header>
<div fxLayout="column" fxLayoutAlign="start stretch" *ngFor="let table of page.tables">
<div fxLayout="column" fxLayoutAlign="start stretch" *ngFor="let table of page.value.tables">
<div fxLayout="row" fxLayoutAlign="space-between center" class="mt-1">
<mat-form-field fxFlex="10">
<mat-select [(ngModel)]="table.recordsPerPage" placeholder="Records/Page" name="{{page.pageId}}-page-size-options" tabindex="1">
<mat-select [(ngModel)]="table.recordsPerPage" placeholder="Records/Page" name="{{table.tableId}}-page-size-options" tabindex="1" required>
<mat-option *ngFor="let pageSizeOption of pageSizeOptions" [value]="pageSizeOption">
{{pageSizeOption}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="10">
<mat-select [(ngModel)]="table.sortBy" placeholder="Sort By" name="{{page.pageId}}-sort-by" tabindex="2">
<mat-option *ngFor="let field of table.fieldsDef" [value]="field">
<mat-select [(ngModel)]="table.sortBy" placeholder="Sort By" name="{{table.tableId}}-sort-by" tabindex="2" required>
<mat-option *ngFor="let field of table.showColumns" [value]="field">
{{field | camelcaseWithReplace:'_'}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="10">
<mat-select [(ngModel)]="table.sortOrder" placeholder="Sort Order" name="{{page.pageId}}-sort-order" tabindex="3">
<mat-select [(ngModel)]="table.sortOrder" placeholder="Sort Order" name="{{table.tableId}}-sort-order" tabindex="3" required>
<mat-option *ngFor="let so of sortOrders" [value]="so">
{{so}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="68">
<mat-select [(ngModel)]="table.showColumns" placeholder="Show Columns" name="{{page.pageId}}-show-columns" tabindex="4" multiple>
<mat-option *ngFor="let field of table.fieldsDef" [value]="field">
<mat-select [(ngModel)]="table.showColumns" (selectionChange)="onShowColumnsChange(table)" placeholder="Show Columns" name="{{table.tableId}}-show-columns" tabindex="4" multiple required>
<mat-option *ngFor="let field of tableFieldsDef[table.tableId]" [value]="field" [disabled]="table.showColumns.length < 3 && table.showColumns.includes(field)">
{{field | camelcaseWithReplace:'_'}}
</mat-option>
</mat-select>

@ -4,17 +4,12 @@ import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { faPenRuler } from '@fortawesome/free-solid-svg-icons';
import { PAGE_SIZE_OPTIONS, ScreenSizeEnum, UI_MESSAGES, SORT_ORDERS } from '../../../services/consts-enums-functions';
import { ConfigSettingsNode } from '../../../models/RTLconfig';
import { CLN_TABLE_FIELDS_DEF, PAGE_SIZE_OPTIONS, ScreenSizeEnum, SORT_ORDERS } from '../../../services/consts-enums-functions';
import { LoggerService } from '../../../services/logger.service';
import { CommonService } from '../../../services/common.service';
import { RTLState } from '../../../../store/rtl.state';
import { saveSettings } from '../../../../store/rtl.actions';
import { setChildNodeSettingsECL } from '../../../../eclair/store/ecl.actions';
import { setChildNodeSettingsCL } from '../../../../cln/store/cln.actions';
import { setChildNodeSettingsLND } from '../../../../lnd/store/lnd.actions';
import { rootSelectedNode } from '../../../../store/rtl.selector';
import { RTL_PAGE_SETTINGS } from '../../../models/pageSettings';
import { TableSetting, PageSettingsCLN } from '../../../models/pageSettings';
import { clnPageSettings } from '../../../../cln/store/cln.selector';
@Component({
selector: 'rtl-page-settings',
@ -24,11 +19,11 @@ import { RTL_PAGE_SETTINGS } from '../../../models/pageSettings';
export class PageSettingsComponent implements OnInit, OnDestroy {
public faPenRuler = faPenRuler;
public selNode: ConfigSettingsNode | any;
public screenSize = '';
public screenSizeEnum = ScreenSizeEnum;
public pageSizeOptions = PAGE_SIZE_OPTIONS;
public pageSettings = null;
public pageSettings: PageSettingsCLN | null = null;
public tableFieldsDef = CLN_TABLE_FIELDS_DEF;
public sortOrders = SORT_ORDERS;
unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
@ -37,14 +32,18 @@ export class PageSettingsComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.select(rootSelectedNode).pipe(takeUntil(this.unSubs[0])).subscribe((selNode) => {
this.selNode = selNode;
this.pageSettings = RTL_PAGE_SETTINGS[this.selNode.lnImplementation.toUpperCase()].sort((x, y) => ((x.seq < y.seq) ? -1 : ((x.seq > y.seq) ? 1 : 0)));
this.logger.info(selNode);
this.logger.warn(this.pageSettings);
this.store.select(clnPageSettings).pipe(takeUntil(this.unSubs[0])).subscribe((settings) => {
this.pageSettings = settings.pageSettings;
this.logger.info(settings);
});
}
onShowColumnsChange(table: TableSetting) {
if (table.showColumns && !table.showColumns.includes(table.sortBy)) {
table.sortBy = table.showColumns[0];
}
}
onUpdatePageSettings() {
// if (this.selNode.settings.fiatConversion && !this.selNode.settings.currencyUnit) {
// return true;

@ -48,6 +48,7 @@ export interface ApiCallsListCL {
FetchBalance: ApiCallStatusPayload;
FetchLocalRemoteBalance: ApiCallStatusPayload;
// Non-initial calls
FetchPageSettings: ApiCallStatusPayload;
FetchInvoices: ApiCallStatusPayload;
FetchFeeRatesperkb: ApiCallStatusPayload;
FetchFeeRatesperkw: ApiCallStatusPayload;

@ -103,7 +103,7 @@ export interface Offer {
export interface OfferBookmark {
lastUpdatedAt?: string;
bolt12?: string;
amountmSat?: number;
amountMSat?: number;
title?: string;
vendor?: string;
description?: string;

@ -7,39 +7,13 @@ export class TableSetting {
sortBy?: string;
sortOrder?: SortOrderEnum;
showColumns?: any[];
fieldsDef?: any[];
}
export class NodePageSettings {
export class PageSettingsCLN {
seq: number;
pageId: string;
tables: TableSetting[];
payments?: { seq?: number, tables?: TableSetting[] };
invoices?: { seq?: number, tables?: TableSetting[] };
utxos?: { seq?: number, tables?: TableSetting[] };
}
export class RTLPageSettings {
LND?: NodePageSettings[];
CLN?: NodePageSettings[];
ECL?: NodePageSettings[];
}
export const RTL_PAGE_SETTINGS: RTLPageSettings = {
LND: [],
CLN: [
{ seq: 1, pageId: 'payments', tables: [{
tableId: 'payments', recordsPerPage: 25, sortBy: 'created_at', sortOrder: SortOrderEnum.DESCENDING,
showColumns: ['created_at', 'type', 'payment_hash', 'msatoshi_sent', 'msatoshi'],
fieldsDef: ['created_at', 'type', 'payment_hash', 'msatoshi_sent', 'msatoshi', 'amount_msat', 'amount_sent_msat', 'destination', 'status', 'memo']
}] },
{ seq: 2, pageId: 'invoices', tables: [{
tableId: 'invoices', recordsPerPage: 10, sortBy: 'expires_at', sortOrder: SortOrderEnum.ASCENDING,
showColumns: ['expires_at', 'paid_at', 'type', 'description', 'msatoshi', 'msatoshi_received'],
fieldsDef: ['expires_at', 'paid_at', 'type', 'description', 'msatoshi', 'msatoshi_received', 'label', 'payment_hash', 'amount_msat', 'status', 'amount_received_msat']
}] }
],
ECL: []
};

@ -1,4 +1,5 @@
import { MatPaginatorIntl } from '@angular/material/paginator';
import { PageSettingsCLN } from '../models/pageSettings';
export function getPaginatorLabel(field: string) {
const appPaginator = new MatPaginatorIntl();
@ -323,6 +324,9 @@ export const UI_MESSAGES = {
GET_FUNDER_POLICY: 'Getting Or Updating Funder Policy...',
GET_LIST_CONFIGS: 'Getting Configurations List...',
LIST_NETWORK_NODES: 'Getting Network Nodes List...',
GET_PAGE_SETTINGS: 'Getting Page Settings...',
SET_PAGE_SETTINGS: 'Setting Page Settings...',
UPDATE_PAGE_SETTINGS: 'Updating Page Settings...',
LOG_OUT: 'Logging Out...'
};
@ -456,6 +460,9 @@ export enum CLNActions {
RESET_CLN_STORE = 'RESET_CLN_STORE',
UPDATE_API_CALL_STATUS_CLN = 'UPDATE_API_CALL_STATUS_CLN',
SET_CHILD_NODE_SETTINGS_CLN = 'SET_CHILD_NODE_SETTINGS_CLN',
FETCH_PAGE_SETTINGS_CLN = 'FETCH_PAGE_SETTINGS_CLN',
SET_PAGE_SETTINGS_CLN = 'SET_PAGE_SETTINGS_CLN',
SAVE_PAGE_SETTINGS_CLN = 'SAVE_PAGE_SETTINGS_CLN',
FETCH_INFO_CLN = 'FETCH_INFO_CL_CLN',
SET_INFO_CLN = 'SET_INFO_CLN',
FETCH_FEES_CLN = 'FETCH_FEES_CLN',
@ -666,3 +673,19 @@ export enum SortOrderEnum {
}
export const SORT_ORDERS = ['Ascending', 'Descending'];
export const CLN_DEFAULT_PAGE_SETTINGS: PageSettingsCLN = {
payments: { seq: 1, tables: [{ tableId: 'payments', recordsPerPage: 10, sortBy: 'created_at', sortOrder: SortOrderEnum.DESCENDING,
showColumns: ['created_at', 'type', 'payment_hash', 'msatoshi_sent', 'msatoshi'] }] },
invoices: { seq: 2, tables: [{ tableId: 'invoices', recordsPerPage: 10, sortBy: 'expires_at', sortOrder: SortOrderEnum.DESCENDING,
showColumns: ['expires_at', 'paid_at', 'type', 'description', 'msatoshi', 'msatoshi_received'] }] },
utxos: { seq: 3, tables: [{ tableId: 'utxos', recordsPerPage: 10, sortBy: 'expires_at', sortOrder: SortOrderEnum.DESCENDING,
showColumns: ['expires_at', 'paid_at', 'type', 'description', 'msatoshi', 'msatoshi_received'] }] }
};
export const CLN_TABLE_FIELDS_DEF = {
payments: ['created_at', 'type', 'payment_hash', 'msatoshi_sent', 'msatoshi', 'amount_msat', 'amount_sent_msat', 'destination', 'status', 'memo'],
invoices: ['expires_at', 'paid_at', 'type', 'description', 'msatoshi', 'msatoshi_received', 'label', 'payment_hash', 'amount_msat', 'status', 'amount_received_msat'],
utxos: ['expires_at', 'paid_at', 'type', 'description', 'msatoshi', 'msatoshi_received', 'label', 'payment_hash', 'amount_msat', 'status', 'amount_received_msat']
};

@ -5,6 +5,7 @@ export const environment = {
isDebugMode: false,
AUTHENTICATE_API: API_URL + '/authenticate',
CONF_API: API_URL + '/conf',
PAGE_SETTINGS_API: API_URL + '/pagesettings',
BALANCE_API: '/balance',
FEES_API: '/fees',
PEERS_API: '/peers',

@ -5,6 +5,7 @@ export const environment = {
isDebugMode: true,
AUTHENTICATE_API: API_URL + '/authenticate',
CONF_API: API_URL + '/conf',
PAGE_SETTINGS_API: API_URL + '/pagesettings',
BALANCE_API: '/balance',
FEES_API: '/fees',
PEERS_API: '/peers',

Loading…
Cancel
Save