Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: Bin order tables by rate. #1090

Merged
merged 9 commits into from
Jul 20, 2021
Merged

ui: Bin order tables by rate. #1090

merged 9 commits into from
Jul 20, 2021

Conversation

martonp
Copy link
Contributor

@martonp martonp commented May 14, 2021

This PR updates the order tables on the market UI. Instead of displaying each individual order's quantity and rate on a separate row, the total quantity available at each rate will be displayed. Also, as discussed in matrix, epoch orders will be binned along with all other orders, and the check mark will no longer be displayed.

Closes #945.

Copy link
Member

@JoeGruffins JoeGruffins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks perfect to me.

@chappjc
Copy link
Member

chappjc commented Jun 8, 2021

Appears to work as indented.

However, we should be aware that while this is a UX improvement to some, it actually hides some important information that I hope we can strive to reveal again, perhaps in a future PR.

Take the following simnet buy side entirely comprising my own orders:

image

Another party just sees the Buy Orders table and has no idea if the 20 DCR best bid is one order or two. This may be an important factor in the user deciding if the transaction will be maximally efficient if they decide to sell. Even if the stars align and those maker orders do get batched by the taker/seller's redeem txn, that redeem is still larger than it would have been if there were just one match instead of two. Plus they still need to make two contracts for the two countparties.

Then consider the 30 DCR at 0.003945. If a user's sell fills 20 DCR at that price level, what would they match against? They would need to see the unbinned orders sorted by time stamp (as before) to know what to expect (assuming no other takers got to those bids first).

@martonp
Copy link
Contributor Author

martonp commented Jun 9, 2021

@chappjc There could be a little pop up that shows up when you hover over each row that contains this information. I may be wrong, but I don’t think people would be so concerned with this if the lot size is set properly and the transaction fees are negligible compared to the order. It definitely can’t hurt to have it there though.

Copy link
Member

@buck54321 buck54321 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good for a first pass. I do want to separate epoch orders from booked orders.

As far as the UI question, I think a good first approach would just be to label the quantity of orders in the bin. e.g.

image

You could do that in a separate PR too.

Comment on lines 1494 to 1505
if (row && row.getRate() === 0) row = row.nextSibling
while (row) {
if ((order.rate < row.order.rate) === order.sell) {
if (order.rate === row.getRate()) {
row.insertOrder(order)
return
} else if ((order.rate < row.getRate()) === order.sell) {
const tr = this.orderTableRow([order], cssClass)
tbody.insertBefore(tr, row)
return
}
row = row.nextSibling
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to figure out a way to separate epoch queue orders and booked orders and create a row for each.

Comment on lines 1613 to 1617
if (!tr.orderBin.length) {
tr.remove()
} else {
tr.updateQty()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be two lines

Comment on lines 1624 to 1628
if (!tr.orderBin.length) {
tr.remove()
} else {
tr.updateQty()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be two lines.

@martonp
Copy link
Contributor Author

martonp commented Jun 20, 2021

@buck54321 I've added a new column that shows the number of orders, let me know what you think. Also the epoch and non-epoch orders are now in separate rows.

This reverts commit ac7d1f0.
@chappjc chappjc self-requested a review July 5, 2021 16:09
Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@buck54321 I've added a new column that shows the number of orders, let me know what you think. Also the epoch and non-epoch orders are now in separate rows.

I think it uses a bit too much space. Just a number and no bulky column header like @buck54321 showed would be fine IMO. Here's what I see now:

image

But it gets a little glitchy at various window widths, putting "# Orders" on two rows, and often creating a horizontal scroll bar:

image

Otherwise, it works as intended. There's a separate row for epoch orders, and when booked, it merges that with the booked orders row and updates the # Orders count. No issues in browser JS console. Overall nice work, but I don't think the column header adds much, possibly even the separate column is unnecessary if the number is just after the quantity in the same column with appropriate styling. Like buck suggested, but perhaps with a tweaked styling:

image

@martonp
Copy link
Contributor Author

martonp commented Jul 6, 2021

@chappjc I've updated it. This definitely looks better. I thought it would be confusing to just have a number there without a column header, but I added a tooltip which explains what the number means.

Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it. Nice work!

image

@buck54321 LGTM, some frontend changes since your last review though.

Copy link
Member

@buck54321 buck54321 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff. I've made a few more suggestions to round things out.

Comment on lines 1581 to 1582
qtyDiv.innerText = qty.toFixed(8)
ordersDiv.innerText = tr.orderBin.length
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's only show the qtyDiv when there is more than one order.

@@ -427,6 +427,12 @@ table.balance-table button:hover {
}
}

div.numorders {
color: white;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No white text, please. Inherited color will work fine once you get the background colors adjusted.

@@ -24,6 +24,11 @@ body.dark {
}
}

div.numorders {
background-color: rgb(25, 25, 180);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's darken this up quite a bit. Maybe like a #141488.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could test out one of our primary colors: https://decred.org/brand/

Keep the hue / rgb ratio and tweak the brightness? If that clashes with the rest of the DEX scheme, no biggie.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screen Shot 2021-07-08 at 12 28 08 PM
Screen Shot 2021-07-08 at 12 28 21 PM

The first one is a lighter version of the dark blue primary color and the second is @buck54321 's suggestion. Very similar, but I think @buck54321 's suggestion is a closer match to the dex logo, which doesn't seem to be using any of the Decred colors.

Copy link
Member

@chappjc chappjc Jul 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k, no sweat. Just wanted to try to keep us on-brand if possible, but best to stay internally consistent with other dex styles unless we rework the whole scheme.

But honestly, I like the top one you showed best. If you guys think it looks funny, we should go with the matching one.

Comment on lines 433 to 434
border-radius: 3px;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The coloring is a little bright. It should blend in and match existing styles more closely.

image

To do that, I added line-height: 1; padding: 1px; here, and then removed the px-1 class and added the align-items-center class to the wrapper div. You might want to play with font-size: 0.9em too, but the font-size is already pretty small here so I'm not sure we want to push it.

@@ -427,6 +427,12 @@ table.balance-table button:hover {
}
}

div.numorders {
color: white;
background-color: rgb(94, 94, 130);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's lighten this up quite a bit. Maybe like a #c5c5e6

Comment on lines 1614 to 1649
tr.insertOrder = (order) => {
tr.orderBin.push(order)
updateQtyTD()
}
tr.updateOrderQty = (token, qty) => {
for (let i = 0; i < tr.orderBin.length; i++) {
if (tr.orderBin[i].token === token) {
tr.orderBin[i].qty = qty
updateQtyTD()
return true
}
}
return false
}
tr.removeOrder = (token) => {
const index = tr.orderBin.findIndex(order => order.token === token)
if (index < 0) return false
tr.orderBin.splice(index, 1)
if (!tr.orderBin.length) tr.remove()
else updateQtyTD()
return true
}
tr.removeEpochOrders = (newEpoch) => {
tr.orderBin = tr.orderBin.filter((order) => {
return !(order.epoch && order.epoch !== newEpoch)
})
if (!tr.orderBin.length) tr.remove()
else updateQtyTD()
}
tr.getRate = () => {
return tr.orderBin[0].rate
}
tr.getEpoch = () => {
return tr.orderBin[0].epoch
}
tr.compare = (order) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good stuff, and it makes the semantics of updating these rows really clean, but once we're adding seven new functions as custom properties to an td element, that's a big clue to me that we should just write a custom class to manage the element and make these class methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a manager class that has a reference to the td element the td element has a reference to the manager class. It's definitely a lot cleaner.

Comment on lines 1578 to 1579
const mainDiv = qtyTD.children[0]
const [qtyDiv, ordersDiv] = mainDiv.children
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try using the data-tmpl/Doc.tmplElement system used throughout, and assigning these elements as properties of the custom class mentioned in my other comment.

Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving latest changes.

Copy link
Member

@buck54321 buck54321 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I place two identical orders in quick succession, the epoch orders are not binned.

image

Then, when the epoch expires, and the orders are booked, they are properly grouped, but the epoch check mark is still displayed.

image

return this.sell
}

compare (order) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I try to doc all methods, but this method in particular could use a docstring.

bins.push(currEpochBin)
return bins.filter(bin => bin.length > 0)
}

/* loadTables loads the order book side into its table. */
loadTableSide (sell) {
const bookSide = sell ? this.book.sells : this.book.buys
const tbody = sell ? this.page.sellRows : this.page.buyRows
const cssClass = sell ? 'sellcolor' : 'buycolor'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cssClass is unused outside of OrderTableRowManager (via orderTableRow). I'd recommend moving this cssClass stuff into the OrderTableRowManager constructor, and just passing the sell boolean as an argument instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call.

@martonp
Copy link
Contributor Author

martonp commented Jul 10, 2021

@buck54321 The bug is fixed now.

@chappjc chappjc merged commit f7086ab into decred:master Jul 20, 2021
@martonp martonp deleted the binOrderTable branch December 20, 2022 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ui: markets view order book tables should bin by rate
4 participants