Files
ui/packages/ui-keyring/src/options/index.ts
T
Tarik Gul caa0ceea23 2025 (#822)
* 2025

* update License
2025-01-03 01:07:08 +02:00

151 lines
4.2 KiB
TypeScript

// Copyright 2017-2025 @polkadot/ui-keyring authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Subscription } from 'rxjs';
import type { SingleAddress } from '../observable/types.js';
import type { KeyringStruct } from '../types.js';
import type { KeyringOptionInstance, KeyringOptions, KeyringSectionOption, KeyringSectionOptions } from './types.js';
import { BehaviorSubject } from 'rxjs';
import { obervableAll } from '../observable/index.js';
let hasCalledInitOptions = false;
const sortByName = (a: SingleAddress, b: SingleAddress): number => {
const valueA = a.option.name;
const valueB = b.option.name;
return valueA.localeCompare(valueB);
};
const sortByCreated = (a: SingleAddress, b: SingleAddress): number => {
const valueA = a.json.meta.whenCreated || 0;
const valueB = b.json.meta.whenCreated || 0;
if (valueA < valueB) {
return 1;
}
if (valueA > valueB) {
return -1;
}
return 0;
};
export class KeyringOption implements KeyringOptionInstance {
#allSub: Subscription | null = null;
public readonly optionsSubject = new BehaviorSubject<KeyringOptions>(this.emptyOptions());
public createOptionHeader (name: string): KeyringSectionOption {
return {
key: `header-${name.toLowerCase()}`,
name,
value: null
};
}
public init (keyring: KeyringStruct): void {
if (hasCalledInitOptions) {
throw new Error('Unable to initialise options more than once');
}
this.#allSub = obervableAll.subscribe((): void => {
const opts = this.emptyOptions();
this.addAccounts(keyring, opts);
this.addAddresses(keyring, opts);
this.addContracts(keyring, opts);
opts.address = this.linkItems({ Addresses: opts.address, Recent: opts.recent });
opts.account = this.linkItems({ Accounts: opts.account, Development: opts.testing });
opts.contract = this.linkItems({ Contracts: opts.contract });
opts.all = ([] as KeyringSectionOptions).concat(opts.account, opts.address);
opts.allPlus = ([] as KeyringSectionOptions).concat(opts.account, opts.address, opts.contract);
this.optionsSubject.next(opts);
});
hasCalledInitOptions = true;
}
public clear (): void {
if (this.#allSub) {
this.#allSub.unsubscribe();
}
}
private linkItems (items: Record<string, KeyringSectionOptions>): KeyringSectionOptions {
return Object.keys(items).reduce((result, header): KeyringSectionOptions => {
const options = items[header];
return result.concat(
options.length
? [this.createOptionHeader(header)]
: [],
options
);
}, [] as KeyringSectionOptions);
}
private addAccounts (keyring: KeyringStruct, options: KeyringOptions): void {
const available = keyring.accounts.subject.getValue();
Object
.values(available)
.sort(sortByName)
.forEach(({ json: { meta: { isTesting = false } }, option }: SingleAddress): void => {
if (!isTesting) {
options.account.push(option);
} else {
options.testing.push(option);
}
});
}
private addAddresses (keyring: KeyringStruct, options: KeyringOptions): void {
const available = keyring.addresses.subject.getValue();
Object
.values(available)
.filter(({ json }: SingleAddress): boolean => !!json.meta.isRecent)
.sort(sortByCreated)
.forEach(({ option }: SingleAddress): void => {
options.recent.push(option);
});
Object
.values(available)
.filter(({ json }: SingleAddress): boolean => !json.meta.isRecent)
.sort(sortByName)
.forEach(({ option }: SingleAddress): void => {
options.address.push(option);
});
}
private addContracts (keyring: KeyringStruct, options: KeyringOptions): void {
const available = keyring.contracts.subject.getValue();
Object
.values(available)
.sort(sortByName)
.forEach(({ option }: SingleAddress): void => {
options.contract.push(option);
});
}
private emptyOptions (): KeyringOptions {
return {
account: [],
address: [],
all: [],
allPlus: [],
contract: [],
recent: [],
testing: []
};
}
}