diff --git a/data-service/api/transactions/interface.d.ts b/data-service/api/transactions/interface.d.ts index 5f6f447d1e..d7dd6379c8 100644 --- a/data-service/api/transactions/interface.d.ts +++ b/data-service/api/transactions/interface.d.ts @@ -344,7 +344,7 @@ export type TDataEntry = TDataEntryInteger | TDataEntryBoolean | TDataEntryBinar export interface TDataEntryInteger { type: 'integer'; key: string; - value: number; + value: number | BigNumber; } export interface TDataEntryBoolean { diff --git a/data-service/api/transactions/parse.ts b/data-service/api/transactions/parse.ts index 4a9f7d743e..015517bae9 100644 --- a/data-service/api/transactions/parse.ts +++ b/data-service/api/transactions/parse.ts @@ -33,6 +33,7 @@ import { factory, IFactory } from '../matcher/getOrders'; import { getSignatureApi } from '../../sign'; import { pipe } from 'ramda'; +const SCRIPT_INVOCATION_NUMBER = 16; const parseAttachment: (data: string | number) => Uint8Array = pipe( String, @@ -101,7 +102,7 @@ export function parseTx(transactions: Array, isUTX: boolean, isTokens? return parseScriptTx(transaction, hash, isUTX); case TRANSACTION_TYPE_NUMBER.SET_ASSET_SCRIPT: return parseAssetScript(transaction, hash, isUTX); - case 16: + case SCRIPT_INVOCATION_NUMBER: return parseInvocationTx(transaction, hash, isUTX); default: return transaction; @@ -127,6 +128,11 @@ export function getAssetsHashFromTx(transaction: T_API_TX, hash = Object.create( hash[normalizeAssetId(transaction.order1.assetPair.amountAsset)] = true; hash[normalizeAssetId(transaction.order1.assetPair.priceAsset)] = true; break; + case SCRIPT_INVOCATION_NUMBER: + transaction.payment.forEach(payment => { + hash[normalizeAssetId(payment.assetId)] = true; + }); + break; } return hash; } @@ -264,8 +270,16 @@ export function parseExchangeOrder(factory: IFactory, order: txApi.IExchangeOrde export function parseDataTx(tx: txApi.IData, assetsHash: IHash, isUTX: boolean): IData { const fee = new Money(tx.fee, assetsHash[WAVES_ID]); - const stringifiedData = JSON.stringify(tx.data, null, 4); - return { ...tx, stringifiedData, fee, isUTX }; + const data = tx.data.map((dataItem) => { + if (dataItem.type === 'integer') { + return { ...dataItem, value: new BigNumber(dataItem.value) }; + } else { + return dataItem; + } + }); + const txWithBigNumber = { ...tx, data }; + const stringifiedData = JSON.stringify(txWithBigNumber.data, null, 4); + return { ...txWithBigNumber, stringifiedData, fee, isUTX }; } export function parseInvocationTx(tx: txApi.IScriptInvocation, assetsHash: IHash, isUTX: boolean): IScriptInvocation { diff --git a/mocks/waves-client-config/master/config.json b/mocks/waves-client-config/master/config.json index cbad80d33d..4045a3603d 100644 --- a/mocks/waves-client-config/master/config.json +++ b/mocks/waves-client-config/master/config.json @@ -1,13 +1,15 @@ { "PERMISSIONS": { "CAN_TRANSFER_COINOMAT": [ - "BTC", - "ETH", - "LTC", - "ZEC", - "BCH", - "DASH", - "XMR" + "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS", + "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu", + "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk", + "BrjUWjndUanm5VsJkbUip8VRYy6LWJePtxya3FNv4TQa", + "zMFqXuoyrn5w17PFurTqxB7GsS71fp9dfk6XFwxbPCy", + "B3uGHFRpSUuGEDWjqB9LWWxafQj8VTvpMucEyoxzws5H", + "5WvPKSJXzVE2orvbkJ8wsQmmQKqTv9sGBPksV4adViw3", + "Ft8X1v1LTa1ABafufpaCWyVj8KkaxUWE6xBhW6sNFJck", + "Gtb1WRznfchDnTh37ezoDTJ4wcoKaRsKqKjJjy7nm2zU" ], "CAN_TRANSFER_TRANSACTION": true, "CAN_SET_ASSET_SCRIPT_TRANSACTION": true, @@ -57,5 +59,5 @@ ] } }, - "SERVICE_TEMPORARILY_UNAVAILABLE": true + "SERVICE_TEMPORARILY_UNAVAILABLE": false } diff --git a/mocks/waves-client-config/master/testnet.config.json b/mocks/waves-client-config/master/testnet.config.json new file mode 100644 index 0000000000..af47d7900c --- /dev/null +++ b/mocks/waves-client-config/master/testnet.config.json @@ -0,0 +1,53 @@ +{ + "PERMISSIONS": { + "CAN_TRANSFER_COINOMAT": [ + "DWgwcZTMhSvnyYCoWLRUXXSH1RSkzThXLJhww9gwkqdn", + "BrmjyAWT5jjr3Wpsiyivyvg5vDuzoX2s93WgiexXetB3", + "BNdAstuFogzSyN2rY3beJbnBYwYcu7RzTHFjW88g8roK", + "CFg2KQfkUgUVM2jFCMC5Xh8T8zrebvPc4HjHPfAugU1S", + "8HT8tXwrXAYqwm8XrZ2hywWWTUAXxobHB5DakVC1y6jn", + "DGgBtwVoXKAKKvV2ayUpSoPzTJxt7jo9KiXMJRzTH2ET", + "8oPbSCKFHkXBy1hCGSg9pJkSARE7zhTQTLpc8KZwdtr7", + "D6N2rAqWN6ZCWnCeNFWLGqqjS6nJLeK4m19XiuhdDenr", + "AsuWyM9MUUsMmWkK7jS48L3ky6gA1pxx7QtEYPbfLjAJ" + ], + "CAN_TRANSFER_TRANSACTION": true, + "CAN_SET_ASSET_SCRIPT_TRANSACTION": true, + "CAN_MASS_TRANSFER_TRANSACTION": true, + "CAN_CREATE_ALIAS_TRANSACTION": true, + "CAN_ISSUE_TRANSACTION": true, + "CAN_REISSUE_TRANSACTION": true, + "CAN_SET_SCRIPT_TRANSACTION": true, + "CAN_LEASE_TRANSACTION": true, + "CAN_CANCEL_LEASE_TRANSACTION": true, + "CAN_BURN_TRANSACTION": true, + "CAN_SPONSORSHIP_TRANSACTION": true, + "CAN_DATA_TRANSACTION": true, + "CAN_CREATE_ORDER": true, + "CAN_CANCEL_ORDER": true, + "CAN_PAIRING_WITH_MOBILE": true, + "CAN_ANY_TRANSACTION": true + }, + "NOTIFICATIONS": [], + "SETTINGS": { + "DEX": { + "WATCH_LIST_PAIRS": [ + "WAVES", + "AsuWyM9MUUsMmWkK7jS48L3ky6gA1pxx7QtEYPbfLjAJ", + "D6N2rAqWN6ZCWnCeNFWLGqqjS6nJLeK4m19XiuhdDenr", + "DWgwcZTMhSvnyYCoWLRUXXSH1RSkzThXLJhww9gwkqdn", + "BrmjyAWT5jjr3Wpsiyivyvg5vDuzoX2s93WgiexXetB3", + "BNdAstuFogzSyN2rY3beJbnBYwYcu7RzTHFjW88g8roK", + "CFg2KQfkUgUVM2jFCMC5Xh8T8zrebvPc4HjHPfAugU1S", + "8HT8tXwrXAYqwm8XrZ2hywWWTUAXxobHB5DakVC1y6jn", + "7itsmgdmomeTXvZzaaxqF3346h4FhciRoWceEw9asNV3", + "DGgBtwVoXKAKKvV2ayUpSoPzTJxt7jo9KiXMJRzTH2ET", + "FvKx3cerSVYGfXKFvUgp7koNuTAcLs8DmtmwRrFVCqJv", + "3P8gkhcLhFQvBkDzMnWeqqwvq3qxkpTNQPs4LUQ95tKD", + "8oPbSCKFHkXBy1hCGSg9pJkSARE7zhTQTLpc8KZwdtr7", + "6KSUNALdYEd1EVTE4dTcSHzNw1dA3Q6ieokSRVuEcALV" + ] + } + }, + "SERVICE_TEMPORARILY_UNAVAILABLE": false +} \ No newline at end of file diff --git a/package.json b/package.json index 4b1d3f880b..da1ede15b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "waves-client", - "version": "1.2.7", + "version": "1.2.8", "description": "The official client application for the Waves platform", "private": true, "repository": { diff --git a/server.ts b/server.ts index 2cfe1d9ad4..a5982a01de 100644 --- a/server.ts +++ b/server.ts @@ -1,7 +1,7 @@ import { createSecureServer } from 'http2'; import { createServer } from 'https'; import { route, parseArguments, stat, loadLocales } from './ts-scripts/utils'; -import { readFileSync, existsSync,mkdirSync } from 'fs'; +import { readFileSync, existsSync, mkdirSync } from 'fs'; import { serialize, parse as parserCookie } from 'cookie'; import { compile } from 'handlebars'; import { parse } from 'url'; @@ -73,7 +73,7 @@ function createMyServer(port) { console.log('Available urls:'); console.log(url); const cachePath = join(process.cwd(), '.cache-download'); - if (!existsSync(cachePath)){ + if (!existsSync(cachePath)) { mkdirSync(cachePath); } loadLocales(cachePath); @@ -141,13 +141,20 @@ function request(req, res) { } function wavesClientConfig(req, res, next) { - if (!req.url.includes('waves-client-config')) { + const parsedCookie = parseCookie(req.headers.cookie); + const connection: string | null = parsedCookie ? parsedCookie.connection : null; + + if (!req.url.includes('waves-client-config') || !connection) { next(); return null; } let response_json = { error: 'oops' }; - const path = join(__dirname, 'mocks/waves-client-config/master/config.json'); + const path = join( + __dirname, + `mocks/waves-client-config/master/${connection === 'mainnet' ? '' : 'testnet.'}config.json` + ); + if (fs.existsSync(path)) { response_json = JSON.parse(fs.readFileSync(path, 'utf8')) || ''; } diff --git a/src/img/icons/orderbook-to-spread-active.svg b/src/img/icons/orderbook-to-spread-active.svg new file mode 100644 index 0000000000..72e63883ba --- /dev/null +++ b/src/img/icons/orderbook-to-spread-active.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/modules/app/less/app-icons.less b/src/modules/app/less/app-icons.less index fc6afd7844..dcfe247b05 100644 --- a/src/modules/app/less/app-icons.less +++ b/src/modules/app/less/app-icons.less @@ -402,6 +402,13 @@ background-position: center center; } +.icon-dex-tospread-active { + display: inline-block; + background-repeat: no-repeat; + background-position: center center; + background-image: @orderbook-to-spread-icon-active; +} + .apple-store-btn, .google-play-btn { width: 135px; diff --git a/src/modules/app/services/DefaultSettings.js b/src/modules/app/services/DefaultSettings.js index 09ae614c1e..1d0c05a437 100644 --- a/src/modules/app/services/DefaultSettings.js +++ b/src/modules/app/services/DefaultSettings.js @@ -31,6 +31,7 @@ lastOpenVersion: '', whatsNewList: [], closedNotification: [], + dontShowSpam: true, withScam: false, scamListUrl: WavesApp.network.scamListUrl, logoutAfterMin: 5, diff --git a/src/modules/app/services/User.js b/src/modules/app/services/User.js index 4c4e34b6e5..360ff75aa3 100644 --- a/src/modules/app/services/User.js +++ b/src/modules/app/services/User.js @@ -2,6 +2,8 @@ (function () { 'use strict'; + const { equals } = require('ramda'); + /* global Mousetrap */ @@ -11,6 +13,7 @@ 'extraFee', 'networkError', 'changeScript', + 'setScamSignal', 'scam' ]; @@ -104,6 +107,10 @@ * @type {Signal} */ changeScript = new tsUtils.Signal(); + /** + * @type {Signal} + */ + setScamSignal = new tsUtils.Signal(); /** * @type {Record} */ @@ -174,7 +181,16 @@ setTimeout(() => { this._scriptInfoPoll = new Poll(() => this.updateScriptAccountData(), () => null, 10000); }, 30000); + }); + + } + + setScam(hash) { + if (!equals(hash, this.scam)) { + this.scam = hash; + this.setScamSignal.dispatch(); + } } /** @@ -341,7 +357,8 @@ hasBackup, lng: i18next.language, theme: themes.getDefaultTheme(), - candle: 'blue' + candle: 'blue', + dontShowSpam: true } }).then(() => { if (restore) { diff --git a/src/modules/app/services/waves/node/content/Assets.js b/src/modules/app/services/waves/node/content/Assets.js index 89bdf03606..91f3a121b9 100644 --- a/src/modules/app/services/waves/node/content/Assets.js +++ b/src/modules/app/services/waves/node/content/Assets.js @@ -3,7 +3,6 @@ 'use strict'; const entities = require('@waves/data-entities'); - const { equals } = require('ramda'); /** * @param {BaseNodeComponent} BaseNodeComponent @@ -21,9 +20,10 @@ constructor() { super(); user.onLogin().then(() => { - - if (!user.getSetting('withScam')) { + if (user.getSetting('scamListUrl')) { this.stopScam(); + } else { + this.giveMyScamBack(); } }); } @@ -133,9 +133,9 @@ } stopScam() { - if (this._pollScam) { - return null; - } + // if (this._pollScam) { + // return null; + // } /** * @type {Poll} * @private @@ -158,7 +158,8 @@ } }); return hash; - }); + }) + .catch(() => Object.create(null)); } /** @@ -166,9 +167,7 @@ * @private */ _setScamAssetList(hash) { - if (!equals(hash, user.scam)) { - user.scam = hash; - } + user.setScam(hash); } /** diff --git a/src/modules/dex/directives/dexBlock/DexBlock.js b/src/modules/dex/directives/dexBlock/DexBlock.js index 0e36211c44..77c561e3e5 100644 --- a/src/modules/dex/directives/dexBlock/DexBlock.js +++ b/src/modules/dex/directives/dexBlock/DexBlock.js @@ -99,7 +99,8 @@ block: '@', hasSearch: '@', canCollapse: '@', - analyticsText: '<' + analyticsText: '<', + isActiveScroll: '<' }, templateUrl: 'modules/dex/directives/dexBlock/dexBlock.html', transclude: true, diff --git a/src/modules/dex/directives/dexBlock/dexBlock.html b/src/modules/dex/directives/dexBlock/dexBlock.html index 87ab1c2ed2..4fdc74899f 100644 --- a/src/modules/dex/directives/dexBlock/dexBlock.html +++ b/src/modules/dex/directives/dexBlock/dexBlock.html @@ -18,7 +18,11 @@
-
+
+ +
diff --git a/src/modules/dex/directives/dexBlock/dexBlock.less b/src/modules/dex/directives/dexBlock/dexBlock.less index b48b2d93f7..ca81a2169d 100644 --- a/src/modules/dex/directives/dexBlock/dexBlock.less +++ b/src/modules/dex/directives/dexBlock/dexBlock.less @@ -59,6 +59,14 @@ w-dex-block { i.tospread:hover { background-color: @color-basic-100; } + + &.active { + cursor: default; + i.tospread { + background: @color-submit-400; + .icon-dex-tospread-active(); + } + } } .dex-block-content { diff --git a/src/modules/dex/directives/orderBook/OrderBook.js b/src/modules/dex/directives/orderBook/OrderBook.js index 6619fc1366..2182934157 100644 --- a/src/modules/dex/directives/orderBook/OrderBook.js +++ b/src/modules/dex/directives/orderBook/OrderBook.js @@ -107,6 +107,11 @@ * @private */ this._dom = null; + /** + * @type {boolean} + * @public + */ + this.isScrolled = false; this.receive(dexDataService.showSpread, () => { this._dom.$box.stop().animate({ scrollTop: this._getSpreadScrollPosition() }, 300); @@ -176,6 +181,11 @@ $lastPrice: { get: () => this._dom.$info.find(SECTIONS.LAST_PRICE) }, $spread: { get: () => this._dom.$info.find(SECTIONS.SPREAD) } }); + this._dom.$box.on('scroll', () => { + const scrollPos = this._dom.$box[0].scrollTop; + const spreadPos = this._getSpreadScrollPosition(); + this.isScrolled = Math.abs(scrollPos - spreadPos) >= 2; + }); } nothingFound() { @@ -470,6 +480,9 @@ angular.module('app.dex').component('wDexOrderBook', { templateUrl: 'modules/dex/directives/orderBook/orderBook.html', + bindings: { + isScrolled: '=' + }, controller }); })(); diff --git a/src/modules/dex/less/dex.less b/src/modules/dex/less/dex.less index 76e9f12041..6fee149461 100644 --- a/src/modules/dex/less/dex.less +++ b/src/modules/dex/less/dex.less @@ -426,7 +426,7 @@ body.dex, body.dex-demo { white-space: nowrap; .decimal-muted { - display: none; + color: @color-disabled-500; } } } diff --git a/src/modules/dex/templates/dex.html b/src/modules/dex/templates/dex.html index d9b0986fd3..8adb51e598 100644 --- a/src/modules/dex/templates/dex.html +++ b/src/modules/dex/templates/dex.html @@ -10,8 +10,9 @@ - + - +
+
+
+
diff --git a/src/modules/ui/directives/actions/actions.less b/src/modules/ui/directives/actions/actions.less index d4df55faa4..2e75d8105b 100644 --- a/src/modules/ui/directives/actions/actions.less +++ b/src/modules/ui/directives/actions/actions.less @@ -57,6 +57,10 @@ w-actions { height: 4px; border-radius: 100%; background-color: @color-basic-500; + + .spam & { + background-color: @color-basic-200; + } } } diff --git a/src/modules/ui/directives/transaction/Transaction.js b/src/modules/ui/directives/transaction/Transaction.js index 30e942f56e..839d41ab6a 100644 --- a/src/modules/ui/directives/transaction/Transaction.js +++ b/src/modules/ui/directives/transaction/Transaction.js @@ -8,22 +8,32 @@ * @param {INotification} notification * @param {Waves} waves * @param {User} user + * @param {$rootScope.Scope} $scope * @return {Transaction} */ const controller = function (Base, $filter, modalManager, notification, - waves, user) { + waves, user, $scope) { const { SIGN_TYPE } = require('@waves/signature-adapter'); class Transaction extends Base { $postLink() { this.typeName = this.transaction.typeName; + this.setScam(); + + this.receive(user.setScamSignal, () => { + this.setScam(); + $scope.$apply(); + }); + } + + setScam() { this.isScam = !!user.scam[this.transaction.assetId]; if (this.transaction.type === 7) { - this.isScamAmount = !!user.scam[this.transaction.amount.asset]; - this.isScamPrice = !!user.scam[this.transaction.price.asset]; + const isScamAmount = !!user.scam[this.transaction.amount.asset]; + const isScamPrice = !!user.scam[this.transaction.price.asset]; + this.isScam = this.isScam || isScamAmount || isScamPrice; } - } cancelLeasing() { @@ -115,7 +125,8 @@ 'modalManager', 'notification', 'waves', - 'user' + 'user', + '$scope' ]; angular.module('app.ui') diff --git a/src/modules/ui/directives/transaction/TransactionInfoRow.js b/src/modules/ui/directives/transaction/TransactionInfoRow.js index 342f4df15c..be9f5d2988 100644 --- a/src/modules/ui/directives/transaction/TransactionInfoRow.js +++ b/src/modules/ui/directives/transaction/TransactionInfoRow.js @@ -14,8 +14,14 @@ this.type = this.transaction.type; this.props = { ...this.transaction, - time: $filter('date')(this.transaction.timestamp, this.datePattern || 'HH:mm') + time: $filter('date')(this.transaction.timestamp, this.datePattern || 'HH:mm'), + isScam: this.isScam }; + + // TODO: delete setTimeout + setTimeout(() => { + this.props.isScam = this.isScam; + }, 0); } } @@ -30,7 +36,8 @@ angular.module('app.ui').component('wTransactionInfoRow', { bindings: { transaction: '<', - datePattern: '<' + datePattern: '<', + isScam: '<' }, templateUrl: 'modules/ui/directives/transaction/transaction-info-row.html', controller diff --git a/src/modules/ui/directives/transaction/transaction.html b/src/modules/ui/directives/transaction/transaction.html index 2c13d9aac0..837fd4701c 100644 --- a/src/modules/ui/directives/transaction/transaction.html +++ b/src/modules/ui/directives/transaction/transaction.html @@ -1,9 +1,10 @@ -
+
+ date-pattern="$ctrl.datePattern" + is-scam="$ctrl.isScam"> diff --git a/src/modules/ui/directives/transaction/transactions.less b/src/modules/ui/directives/transaction/transactions.less index bcbfaf085a..f20caf9d2b 100644 --- a/src/modules/ui/directives/transaction/transactions.less +++ b/src/modules/ui/directives/transaction/transactions.less @@ -206,7 +206,7 @@ w-transaction .transaction { .transaction-info { display: flex; flex-direction: row; - width: 100%; + width: ~'calc(100% - 88px)'; .full-width { width: 100%; @@ -220,18 +220,31 @@ w-transaction .transaction { .line { height: 50%; flex-basis: 50%; + box-sizing: border-box; + overflow: hidden; color: @color-basic-700; &:last-child { padding-right: @padding-main-layout * 4.4; text-align: right; + + .top { + word-break: break-all; + } } .top { - word-break: break-all; .spam-label { display: none; } + + .flex { + flex: 0; + + .ellipsis { + max-width: 120px; + } + } } .bottom { color: @color-basic-500; @@ -291,6 +304,11 @@ w-transaction .transaction { } } +.transaction-amounts { + max-width: 100%; + display: inline-block; +} + @media screen and (max-width: 960px) { .leasing w-transaction .transaction { .icon { diff --git a/src/modules/ui/directives/transaction/types/exchange/exchange.html b/src/modules/ui/directives/transaction/types/exchange/exchange.html index 3b0e09e39d..8371fe36a8 100644 --- a/src/modules/ui/directives/transaction/types/exchange/exchange.html +++ b/src/modules/ui/directives/transaction/types/exchange/exchange.html @@ -1,8 +1,11 @@
-
- +
+ + + {{$ctrl.getAssetName($ctrl.transaction.amount.asset)}} + {{$ctrl.amountAssetName}} { + this.isScam = this.props.isScam; + }, 0); + + // TODO: delete setTimeout + setTimeout(() => { + this.isScam = this.props.isScam; + }, 0); const TYPES = waves.node.transactions.TYPES; diff --git a/src/modules/ui/directives/transaction/types/mass-transfer/mass-transfer.html b/src/modules/ui/directives/transaction/types/mass-transfer/mass-transfer.html index 37bfadd522..a0b890420b 100644 --- a/src/modules/ui/directives/transaction/types/mass-transfer/mass-transfer.html +++ b/src/modules/ui/directives/transaction/types/mass-transfer/mass-transfer.html @@ -15,7 +15,7 @@
-
+
diff --git a/src/modules/ui/directives/transaction/types/transfer.html b/src/modules/ui/directives/transaction/types/transfer.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/modules/ui/directives/transaction/types/transfer/Transfer.js b/src/modules/ui/directives/transaction/types/transfer/Transfer.js index 7e585f3a4b..ae626e1532 100644 --- a/src/modules/ui/directives/transaction/types/transfer/Transfer.js +++ b/src/modules/ui/directives/transaction/types/transfer/Transfer.js @@ -1,38 +1,35 @@ (function () { 'use strict'; - angular.module('app.ui').component('wTransfer', { - bindings: { - props: '<' - }, - templateUrl: 'modules/ui/directives/transaction/types/transfer/transfer.html' - }); -})(); -(function () { - 'use strict'; - /** + * @param {typeof Base} Base * @param {User} user * @param {BaseAssetService} baseAssetService * @param {Waves} waves * @param {$rootScope.Scope} $scope + * @param {app.utils} utils * @return {Transfer} */ - const controller = function (user, baseAssetService, waves, $scope) { + const controller = function (Base, user, baseAssetService, waves, $scope, utils) { - class Transfer { + class Transfer extends Base { /** - * {object} + * @type object */ - props = null; + props = Object.create(null); $postLink() { this.typeName = this.props.typeName; this.time = this.props.time; this.address = this.props.shownAddress; + this.receive(utils.observe(this.props, 'isScam'), () => { + this.isScam = this.props.isScam; + utils.safeApply($scope); + }); + const TYPES = waves.node.transactions.TYPES; switch (this.typeName) { @@ -89,10 +86,12 @@ }; controller.$inject = [ + 'Base', 'user', 'baseAssetService', 'waves', - '$scope' + '$scope', + 'utils' ]; angular.module('app.ui').component('wTransferRow', { diff --git a/src/modules/ui/directives/transaction/types/transfer/transfer.html b/src/modules/ui/directives/transaction/types/transfer/transfer.html index 37bfadd522..a0b890420b 100644 --- a/src/modules/ui/directives/transaction/types/transfer/transfer.html +++ b/src/modules/ui/directives/transaction/types/transfer/transfer.html @@ -15,7 +15,7 @@
-
+
diff --git a/src/modules/ui/directives/transactionInfo/types/mass-transfer/header.html b/src/modules/ui/directives/transactionInfo/types/mass-transfer/header.html index 4dceece4a9..3fdacc0b98 100644 --- a/src/modules/ui/directives/transactionInfo/types/mass-transfer/header.html +++ b/src/modules/ui/directives/transactionInfo/types/mass-transfer/header.html @@ -7,7 +7,7 @@ class="status-label-min inactive" w-i18n="transaction.headers.suspicious">
-
+
≈ {{::$ctrl.mirrorBalance.toFormat()}} {{::$ctrl.mirrorBalance.asset.name}}
diff --git a/src/modules/ui/directives/transactionInfo/types/transfer/transfer-header.html b/src/modules/ui/directives/transactionInfo/types/transfer/transfer-header.html index 758eb90e1d..f3d31044bb 100644 --- a/src/modules/ui/directives/transactionInfo/types/transfer/transfer-header.html +++ b/src/modules/ui/directives/transactionInfo/types/transfer/transfer-header.html @@ -7,7 +7,7 @@ class="status-label-min inactive" w-i18n="transaction.headers.suspicious">
-
+
≈ {{::$ctrl.mirrorBalance.toFormat()}} {{::$ctrl.mirrorBalance.asset.name}}
diff --git a/src/modules/ui/directives/transactionList/TransactionList.js b/src/modules/ui/directives/transactionList/TransactionList.js index 293ee64c21..dda5ca7620 100644 --- a/src/modules/ui/directives/transactionList/TransactionList.js +++ b/src/modules/ui/directives/transactionList/TransactionList.js @@ -27,8 +27,16 @@ * @type {boolean} */ this.pending = false; + /** + * @type {boolean} + */ + this.dontShowSpam = user.getSetting('dontShowSpam'); + + this.syncSettings({ + dontShowSpam: 'dontShowSpam' + }); - this.observe('_transactions', this._onChangeTransactions); + this.observe(['_transactions', 'dontShowSpam'], this._onChangeTransactions); } $postLink() { @@ -39,7 +47,11 @@ * @private */ _onChangeTransactions() { - const transactions = (this._transactions || []); + let transactions = (this._transactions || []); + if (this.dontShowSpam) { + transactions = transactions.filter(this._filterSpam); + } + const hash = Object.create(null); const toDate = tsUtils.date('DD.MM.YYYY'); @@ -61,6 +73,16 @@ })); } + _filterSpam(transaction) { + const isScam = !!user.scam[transaction.assetId]; + let isScamAmount, isScamPrice; + if (transaction.type === 7) { + isScamAmount = !!user.scam[transaction.amount.asset]; + isScamPrice = !!user.scam[transaction.price.asset]; + } + return !(isScam || isScamAmount || isScamPrice); + } + } return new TransactionList(); diff --git a/src/modules/utils/modals/pinAsset/PinAssetCtrl.js b/src/modules/utils/modals/pinAsset/PinAssetCtrl.js index 29a772469b..388d0b5aba 100644 --- a/src/modules/utils/modals/pinAsset/PinAssetCtrl.js +++ b/src/modules/utils/modals/pinAsset/PinAssetCtrl.js @@ -32,6 +32,10 @@ const R = require('ramda'); * @type {boolean} */ this.withScam = null; + /** + * @type {boolean} + */ + this.dontShowSpam = null; /** * @type {Array} */ @@ -52,7 +56,8 @@ const R = require('ramda'); this.syncSettings({ pinnedAssetIdList: 'pinnedAssetIdList', spam: 'wallet.portfolio.spam', - withScam: 'withScam' + withScam: 'withScam', + dontShowSpam: 'dontShowSpam' }); this.observe('search', this._fillList); diff --git a/src/modules/utils/modals/sendAsset/components/singleSend/SingleSend.js b/src/modules/utils/modals/sendAsset/components/singleSend/SingleSend.js index afa1d235c6..1fabd92f54 100644 --- a/src/modules/utils/modals/sendAsset/components/singleSend/SingleSend.js +++ b/src/modules/utils/modals/sendAsset/components/singleSend/SingleSend.js @@ -21,6 +21,7 @@ * @param {$rootScope.Scope} $scope * @param {app.utils} utils * @param {IPollCreate} createPoll + * @param {ConfigService} configService * @param {IOuterBlockchains} outerBlockchains * @param {User} user * @param {GatewayService} gatewayService @@ -31,6 +32,7 @@ utils, createPoll, waves, + configService, outerBlockchains, user, gatewayService) { @@ -138,6 +140,15 @@ return this.toBankMode && this.termsLoadError; } + get isCoinomatAccepted() { + return configService + .get('PERMISSIONS.CAN_TRANSFER_COINOMAT').indexOf(this.balance.asset.id) !== -1; + } + + get isBankAccepted() { + return this.toBankMode ? this.isCoinomatAccepted : true; + } + get isBankPendingOrError() { return this.isBankError || this.isBankPending; } @@ -256,7 +267,6 @@ } $postLink() { - this.receive(utils.observe(this.tx, 'fee'), this._currentHasCommission, this); const onHasMoneyHash = () => { this.receive(utils.observe(this.state, 'toBankMode'), this._onChangeBankMode, this); @@ -272,6 +282,9 @@ this.receive(utils.observe(this.state, 'paymentId'), this._updateGatewayDetails, this); this.receive(utils.observe(this.tx, 'recipient'), this._updateGatewayDetails, this); + this.receive(utils.observe(this.state, 'paymentId'), this._updateGatewayPermisson, this); + this.receive(utils.observe(this.tx, 'recipient'), this._updateGatewayPermisson, this); + this.receive(utils.observe(this.tx, 'amount'), this._onChangeAmount, this); this.observe('gatewayDetails', this._updateWavesTxObject); @@ -280,6 +293,11 @@ this.receive(utils.observe(this.tx, 'attachment'), this._updateWavesTxObject, this); this.observe('mirror', this._onChangeAmountMirror); + + this._currentHasCommission(); + this._onChangeBaseAssets(); + this._updateGatewayDetails(); + this._updateGatewayPermisson(); }; if (!this.state.moneyHash) { this.receiveOnce(utils.observe(this.state, 'moneyHash'), onHasMoneyHash); @@ -461,6 +479,7 @@ } this._setMinAmount(); + this._updateGatewayPermisson(); } /** @@ -516,6 +535,7 @@ this.tx.amount = this.moneyHash[this.assetId].cloneWithTokens('0'); this.mirror = this.moneyHash[this.mirrorId].cloneWithTokens('0'); this._updateGatewayDetails(); + this._updateGatewayPermisson(); // analytics.push('Send', `Send.ChangeCurrency.${WavesApp.type}`, this.assetId); } @@ -662,6 +682,13 @@ return Promise.resolve(); } + /** + * @private + */ + _updateGatewayPermisson() { + this.gatewayDetailsError = !this.isCoinomatAccepted; + } + } return new SingleSend(); @@ -673,6 +700,7 @@ 'utils', 'createPoll', 'waves', + 'configService', 'outerBlockchains', 'user', 'gatewayService' diff --git a/src/modules/utils/modals/sendAsset/components/singleSend/single-send.html b/src/modules/utils/modals/sendAsset/components/singleSend/single-send.html index feba466053..2f8fab0874 100644 --- a/src/modules/utils/modals/sendAsset/components/singleSend/single-send.html +++ b/src/modules/utils/modals/sendAsset/components/singleSend/single-send.html @@ -58,18 +58,18 @@
+ ng-if="$ctrl.toBankMode && $ctrl.termsIsPending && !$ctrl.isLira && $ctrl.isBankAccepted">
-
+
-
+
@@ -99,17 +99,12 @@
-
+
- - -
@@ -143,7 +138,7 @@
-
@@ -243,7 +238,7 @@
-
+
-
+
-
{{$ctrl.balance.asset.name}}
+
{{$ctrl.balance.asset.name}}
- -  {{$ctrl.balance.asset.displayName}} + +  {{$ctrl.balance.asset.displayName}}
-
{{::option.asset.name}}
+
{{::option.asset.name}}
- -  {{::option.asset.displayName}} + +  {{::option.asset.displayName}}
diff --git a/src/modules/utils/modals/sendAsset/send.modal.less b/src/modules/utils/modals/sendAsset/send.modal.less index f75daafffe..b38ce647cf 100644 --- a/src/modules/utils/modals/sendAsset/send.modal.less +++ b/src/modules/utils/modals/sendAsset/send.modal.less @@ -110,6 +110,7 @@ md-dialog.modal-send { .plate-warning { &.server-error { margin-bottom: 30px; + justify-content: center; } } @@ -171,6 +172,7 @@ md-dialog.modal-send { .asset__name { margin-left: 10px; + max-width: 122px; } .flex-row { @@ -224,31 +226,19 @@ md-dialog.modal-send { &__balance { font-size: 15px; + display: flex; @media screen and (max-width: 540px) { font-size: 13px; } } - } - } - .input-like { - position: relative; - padding: 0 20px; - border-radius: @border-radius; - width: 100%; - display: flex; - flex-direction: row; - align-items: center; - overflow-x: hidden; - } + &__amount { + max-width: 100px; + } + } - w-select { .title { overflow-x: hidden; - - span { - white-space: nowrap; - } } .expanded { @@ -263,6 +253,17 @@ md-dialog.modal-send { } } + .input-like { + position: relative; + padding: 0 20px; + border-radius: @border-radius; + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + overflow-x: hidden; + } + .amount-wrap { display: flex; flex-direction: row; @@ -281,6 +282,10 @@ md-dialog.modal-send { w-balance { vertical-align: top; white-space: nowrap; + + &.asset__amount { + max-width: 100px; + } } w-balance-input { diff --git a/src/modules/utils/modals/settings/SettingsCtrl.js b/src/modules/utils/modals/settings/SettingsCtrl.js index 97f0e6143f..8390fa26d5 100644 --- a/src/modules/utils/modals/settings/SettingsCtrl.js +++ b/src/modules/utils/modals/settings/SettingsCtrl.js @@ -59,8 +59,9 @@ shownKey = false; node = ''; matcher = ''; + api = ''; scamListUrl = ''; - withScam = false; + dontShowSpam = true; theme = user.getSetting('theme'); candle = user.getSetting('candle'); templatePromise = $templateRequest('modules/utils/modals/settings/loader.html'); @@ -96,12 +97,14 @@ this.syncSettings({ node: 'network.node', matcher: 'network.matcher', + api: 'network.api', logoutAfterMin: 'logoutAfterMin', scamListUrl: 'scamListUrl', - withScam: 'withScam', + dontShowSpam: 'dontShowSpam', theme: 'theme', candle: 'candle', oracleWaves: 'oracleWaves' + }); this.assetsOracleTmp = this.oracleWaves; @@ -156,19 +159,23 @@ // user.changeCandle(this.candle); // }); - this.observe('withScam', () => { - const withScam = this.withScam; - if (withScam) { - waves.node.assets.giveMyScamBack(); - } else { - waves.node.assets.stopScam(); - } + this.observe('dontShowSpam', () => { + const dontShowSpam = this.dontShowSpam; + user.setSetting('dontShowSpam', dontShowSpam); + }); + + this.observe('scamListUrl', () => { + ds.config.setConfig({ + scamListUrl: this.scamListUrl + }); + waves.node.assets.stopScam(); }); - this.observe(['node', 'matcher'], () => { + this.observe(['node', 'matcher', 'api'], () => { ds.config.setConfig({ node: this.node, - matcher: this.matcher + matcher: this.matcher, + api: this.api }); }); @@ -213,9 +220,10 @@ setNetworkDefault() { this.node = WavesApp.network.node; this.matcher = WavesApp.network.matcher; - this.withScam = false; + this.dontShowSpam = true; this.scamListUrl = WavesApp.network.scamListUrl; this.oracleWaves = WavesApp.oracles.waves; + this.api = WavesApp.network.api; } showPairingWithMobile() { diff --git a/src/modules/utils/modals/settings/settings.html b/src/modules/utils/modals/settings/settings.html index b442ce0e5e..de0c3eb89e 100644 --- a/src/modules/utils/modals/settings/settings.html +++ b/src/modules/utils/modals/settings/settings.html @@ -252,6 +252,19 @@
+
+
+ + +
+
+ + +
+
+
+
+
@@ -262,14 +275,15 @@
+
- - + +
diff --git a/src/modules/utils/modals/settings/settings.less b/src/modules/utils/modals/settings/settings.less index 9831b78556..aad9716f82 100644 --- a/src/modules/utils/modals/settings/settings.less +++ b/src/modules/utils/modals/settings/settings.less @@ -255,6 +255,11 @@ md-dialog.settings-modal { } .asset-verification { + z-index: 3; + position: relative; + } + + .asset-api { z-index: 2; position: relative; } diff --git a/src/modules/utils/services/whatsNew.js b/src/modules/utils/services/whatsNew.js index 7465454588..4002de6ff0 100644 --- a/src/modules/utils/services/whatsNew.js +++ b/src/modules/utils/services/whatsNew.js @@ -39,7 +39,8 @@ '1.2.1', '1.2.2', '1.2.3', - '1.2.6' + '1.2.6', + '1.2.8' ]; /** diff --git a/src/modules/wallet/modules/portfolio/controllers/PortfolioCtrl.js b/src/modules/wallet/modules/portfolio/controllers/PortfolioCtrl.js index 742e438457..4719ade88f 100644 --- a/src/modules/wallet/modules/portfolio/controllers/PortfolioCtrl.js +++ b/src/modules/wallet/modules/portfolio/controllers/PortfolioCtrl.js @@ -81,6 +81,10 @@ * @type {boolean} */ this.pending = true; + /** + * @type {boolean} + */ + this.dontShowSpam = user.getSetting('dontShowSpam'); waves.node.assets.getAsset(this.mirrorId) .then((mirror) => { @@ -132,7 +136,8 @@ this.syncSettings({ pinned: 'pinnedAssetIdList', spam: 'wallet.portfolio.spam', - filter: 'wallet.portfolio.filter' + filter: 'wallet.portfolio.filter', + dontShowSpam: 'dontShowSpam' }); balanceWatcher.ready @@ -144,7 +149,7 @@ this.receive(balanceWatcher.change, onChange); this.receive(utils.observe(user, 'scam'), onChange); - this.observe(['pinned', 'spam'], onChange); + this.observe(['pinned', 'spam', 'dontShowSpam'], onChange); this._updateBalances(); }); @@ -310,16 +315,24 @@ }) .reduce((acc, item) => { const oracleData = ds.dataManager.getOraclesAssetData(item.asset.id); + const spam = item.isOnScamList || item.isSpam; - if (item.asset.sender === user.address) { - acc.my.push(item); - } if (oracleData && oracleData.status > 0) { acc.verified.push(item); } - if (item.isOnScamList || item.isSpam) { - acc.spam.push(item); + + if (spam) { + if (!this.dontShowSpam) { + if (item.asset.sender === user.address) { + acc.my.push(item); + } + acc.spam.push(item); + acc.active.push(item); + } } else { + if (item.asset.sender === user.address) { + acc.my.push(item); + } acc.active.push(item); } diff --git a/src/modules/wallet/modules/portfolio/directives/portfolioRow/PortfolioRow.js b/src/modules/wallet/modules/portfolio/directives/portfolioRow/PortfolioRow.js index 9fe35de7d4..f29adb8c48 100644 --- a/src/modules/wallet/modules/portfolio/directives/portfolioRow/PortfolioRow.js +++ b/src/modules/wallet/modules/portfolio/directives/portfolioRow/PortfolioRow.js @@ -83,7 +83,8 @@ SPONSORSHIP_EDIT: 'js-action-button-sponsorship_edit', SPONSORSHIP_STOP: 'js-action-button-cancel-sponsorship', SET_ASSET_SCRIPT: 'js-action-button-set-asset-script' - } + }, + SUSPICIOUS_LABEL: 'js-suspicious-label' }; const ds = require('data-service'); @@ -249,8 +250,7 @@ canShowToggleSpam: this._canShowToggleSpam(), canSponsored: this._isMyAsset, canPayFee, - canStopSponsored, - isSpam: this.balance.isOnScamList + canStopSponsored }); this.node.innerHTML = html; @@ -260,7 +260,8 @@ set: (value) => { if (this.balance.asset.id !== value.asset.id || !this.balance.available.getTokens().eq(value.available.getTokens()) || - !this.balance.inOrders.getTokens().eq(value.inOrders.getTokens()) + !this.balance.inOrders.getTokens().eq(value.inOrders.getTokens()) || + this.balance.isOnScamList !== value.isOnScamList ) { balance = value; this._onUpdateBalance(); @@ -334,6 +335,21 @@ this._initSpamState(); const balance = this.balance; + + if (balance.isOnScamList) { + this.node.querySelector(`.${SELECTORS.CHANGE_24}`).innerHTML = '—'; + this.node.querySelector(`.${SELECTORS.BASE_ASSET_BALANCE}`).innerHTML = '—'; + this.node.querySelector(`.${SELECTORS.EXCHANGE_RATE}`).innerHTML = '—'; + this.node.querySelector(`.${SELECTORS.SUSPICIOUS_LABEL}`).classList.remove('hidden'); + + return null; + } else { + const suspiciousSelector = this.node.querySelector(`.${SELECTORS.SUSPICIOUS_LABEL}`); + if (suspiciousSelector) { + suspiciousSelector.classList.add('hidden'); + } + } + const baseAssetId = this.user.getSetting('baseAssetId'); if (baseAssetId === balance.asset.id) { @@ -347,6 +363,14 @@ return null; } + if (balance.isOnScamList) { + this.node.querySelector(`.${SELECTORS.CHANGE_24}`).innerHTML = '—'; + this.node.querySelector(`.${SELECTORS.BASE_ASSET_BALANCE}`).innerHTML = '—'; + this.node.querySelector(`.${SELECTORS.EXCHANGE_RATE}`).innerHTML = '—'; + + return null; + } + this.waves.utils.getChange(balance.asset.id, baseAssetId) .then(change24 => { const change24Node = this.node.querySelector(`.${SELECTORS.CHANGE_24}`); @@ -565,10 +589,11 @@ this.node.querySelector(`.${SELECTORS.BUTTONS.TOGGLE_SPAM}`), this.node.querySelector(`.${SELECTORS.ACTION_BUTTONS.TOGGLE_SPAM}`) ]; - elements.forEach(toggleSpam => { - toggleSpam.classList.toggle('icon-hide', !isSpam); - toggleSpam.classList.toggle('icon-show', isSpam); + if (toggleSpam) { + toggleSpam.classList.toggle('icon-hide', !isSpam); + toggleSpam.classList.toggle('icon-show', isSpam); + } }); } diff --git a/src/modules/wallet/modules/portfolio/directives/portfolioRow/portfolio-row.less b/src/modules/wallet/modules/portfolio/directives/portfolioRow/portfolio-row.less index 087ae0f72d..a96b6988f5 100644 --- a/src/modules/wallet/modules/portfolio/directives/portfolioRow/portfolio-row.less +++ b/src/modules/wallet/modules/portfolio/directives/portfolioRow/portfolio-row.less @@ -4,23 +4,27 @@ w-portfolio-row { display: flex; width: 100%; - .asset { - &__logo { - position: relative; - left: 0; + .asset { + &__logo { + position: relative; + left: 0; - .marker { - display: none; - position: absolute; - bottom: calc(50% ~'- 16px'); + .marker { + display: none; + position: absolute; + bottom: calc(50% ~'- 16px'); - &.smart-asset, - &.sponsored-asset { - display: block; - } + &.smart-asset, + &.sponsored-asset { + display: block; } } + + .spam &, .spam & .marker { + background-color: @color-basic-200 !important; + } } + } .asset { &__logo { @@ -71,4 +75,9 @@ w-portfolio-row { } } } -} \ No newline at end of file + + .spam & { + color: @color-basic-500; + } + +} diff --git a/src/modules/wallet/modules/portfolio/directives/portfolioRow/row.hbs b/src/modules/wallet/modules/portfolio/directives/portfolioRow/row.hbs index ce14d5e700..d196585b47 100644 --- a/src/modules/wallet/modules/portfolio/directives/portfolioRow/row.hbs +++ b/src/modules/wallet/modules/portfolio/directives/portfolioRow/row.hbs @@ -22,9 +22,7 @@ {{#if isTokenomica}} {{/if}} - {{#if isSpam}} - - {{/if}} +
diff --git a/src/modules/wallet/modules/portfolio/less/portfolio.less b/src/modules/wallet/modules/portfolio/less/portfolio.less index 5912921b41..f1e52eda5c 100644 --- a/src/modules/wallet/modules/portfolio/less/portfolio.less +++ b/src/modules/wallet/modules/portfolio/less/portfolio.less @@ -128,6 +128,16 @@ i.toggler { display: none; } + + &.spam { + .smart-table__cell:last-child { + .cell { + span.icon svg { + fill: @color-basic-200; + } + } + } + } } .z-top { diff --git a/src/modules/wallet/modules/portfolio/templates/portfolio.html b/src/modules/wallet/modules/portfolio/templates/portfolio.html index 8fef20a9a5..910bb1fb01 100644 --- a/src/modules/wallet/modules/portfolio/templates/portfolio.html +++ b/src/modules/wallet/modules/portfolio/templates/portfolio.html @@ -39,7 +39,7 @@ w-i18n-ns="app.wallet.portfolio" params="{count: $ctrl.details.verified.length || 0}"> - + @@ -55,7 +55,7 @@ header-info="$ctrl.tableHeaders"> - + diff --git a/src/modules/wallet/modules/transactions/controllers/TransactionsCtrl.js b/src/modules/wallet/modules/transactions/controllers/TransactionsCtrl.js index f37efdf629..81b90f8a6f 100644 --- a/src/modules/wallet/modules/transactions/controllers/TransactionsCtrl.js +++ b/src/modules/wallet/modules/transactions/controllers/TransactionsCtrl.js @@ -82,7 +82,10 @@ } - allTransactions = allTransactions.concat(transactions.filter(el => !user.scam[el.assetId])); + if (user.getSetting('dontShowSpam')) { + transactions = transactions.filter(el => !user.scam[el.assetId]); + } + allTransactions = allTransactions.concat(transactions); if (transactions.length < MAX_LIMIT || allTransactions.length > maxTransactions) { return { allTransactions, downloadError }; diff --git a/src/themeConfig/black/icons.less b/src/themeConfig/black/icons.less index 7208be0ff6..086a024445 100644 --- a/src/themeConfig/black/icons.less +++ b/src/themeConfig/black/icons.less @@ -11,6 +11,7 @@ @dex-toggle-icon: url(/img/icons/dark/dex-toggle.svg); @dex-copybalance-icon: url(/img/icons/dark/dex-copy-icon.svg); @orderbook-to-spread-icon: url(/img/icons/dark/orderbook-to-spread.svg); +@orderbook-to-spread-icon-active: url(/img/icons/orderbook-to-spread-active.svg); @arrow-orderbook-top-icon: url(/img/icons/dark/arrow-orderbook-top.svg); @arrow-orderbook-down-icon: url(/img/icons/dark/arrow-orderbook-down.svg); @empty-icon: url(/img/icons/dark/icon-empty.svg); diff --git a/src/themeConfig/default/icons.less b/src/themeConfig/default/icons.less index ed567f703b..8d4ad72f2f 100644 --- a/src/themeConfig/default/icons.less +++ b/src/themeConfig/default/icons.less @@ -11,6 +11,7 @@ @dex-toggle-icon: url(/img/icons/dex-toggle.svg); @dex-copybalance-icon: url(/img/icons/dex-copy-icon.svg); @orderbook-to-spread-icon: url(/img/icons/orderbook-to-spread.svg); +@orderbook-to-spread-icon-active: url(/img/icons/orderbook-to-spread-active.svg); @arrow-orderbook-top-icon: url(/img/icons/arrow-orderbook-top.svg); @arrow-orderbook-down-icon: url(/img/icons/arrow-orderbook-down.svg); @empty-icon: url(/img/icons/icon-empty.svg);