Skip to content

Commit

Permalink
Merge pull request #829 from rainlanguage/2024-09-03-order-filtering-…
Browse files Browse the repository at this point in the history
…by-watchlist

Order filtering by watchlist
  • Loading branch information
hardyjosh authored Sep 6, 2024
2 parents fc74c9a + bfb438f commit 8262193
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 24 deletions.
19 changes: 17 additions & 2 deletions crates/cli/src/commands/order/list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
execute::Execute,
subgraph::{CliPaginationArgs, CliSubgraphArgs},
subgraph::{CliFilterArgs, CliPaginationArgs, CliSubgraphArgs},
};
use anyhow::Result;
use clap::Args;
Expand All @@ -19,6 +19,9 @@ pub struct CliOrderListArgs {

#[clap(flatten)]
pub subgraph_args: CliSubgraphArgs,

#[clap(flatten)]
pub filter_args: CliFilterArgs,
}

impl Execute for CliOrderListArgs {
Expand All @@ -42,7 +45,10 @@ impl Execute for CliOrderListArgs {
subgraph_args
.to_subgraph_client()
.await?
.orders_list(self.pagination_args.clone().into())
.orders_list(
self.filter_args.clone().into(),
self.pagination_args.clone().into(),
)
.await?
.into_iter()
.map(|o| o.try_into())
Expand Down Expand Up @@ -112,6 +118,9 @@ mod tests {
page_size: 25,
page: 1,
},
filter_args: CliFilterArgs {
owners: vec!["addr1".to_string()],
},
};

// should succeed
Expand All @@ -135,6 +144,9 @@ mod tests {
page_size: 25,
page: 1,
},
filter_args: CliFilterArgs {
owners: vec!["addr1".to_string()],
},
};

// should succeed
Expand All @@ -158,6 +170,9 @@ mod tests {
page_size: 25,
page: 1,
},
filter_args: CliFilterArgs {
owners: vec!["addr1".to_string()],
},
};

// should error
Expand Down
23 changes: 22 additions & 1 deletion crates/cli/src/subgraph.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use clap::Args;
use rain_orderbook_common::subgraph::SubgraphArgs;
use rain_orderbook_subgraph_client::PaginationArgs;
use rain_orderbook_subgraph_client::{
types::common::{Bytes, OrdersListFilterArgs},
PaginationArgs,
};

#[derive(Args, Clone)]
pub struct CliSubgraphArgs {
Expand Down Expand Up @@ -57,3 +60,21 @@ impl From<CliPaginationArgs> for PaginationArgs {
}
}
}

#[derive(Args, Clone)]
pub struct CliFilterArgs {
#[arg(
long,
help = "Filter orders by owner addresses (comma-separated)",
value_delimiter = ','
)]
pub owners: Vec<String>,
}

impl From<CliFilterArgs> for OrdersListFilterArgs {
fn from(val: CliFilterArgs) -> Self {
Self {
owners: val.owners.into_iter().map(Bytes).collect(),
}
}
}
31 changes: 22 additions & 9 deletions crates/subgraph/src/orderbook_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,26 @@ impl OrderbookSubgraphClient {
/// Fetch all orders, paginated
pub async fn orders_list(
&self,
filter_args: OrdersListFilterArgs,
pagination_args: PaginationArgs,
) -> Result<Vec<Order>, OrderbookSubgraphClientError> {
let pagination_variables = Self::parse_pagination_args(pagination_args);

let variables = OrdersListQueryVariables {
first: pagination_variables.first,
skip: pagination_variables.skip,
filters: if filter_args.owners.is_empty() {
None
} else {
Some(OrdersListQueryFilters {
owner_in: filter_args.owners,
})
},
};

let data = self
.query::<OrdersListQuery, PaginationQueryVariables>(PaginationQueryVariables {
first: pagination_variables.first,
skip: pagination_variables.skip,
})
.query::<OrdersListQuery, OrdersListQueryVariables>(variables)
.await?;

Ok(data.orders)
}

Expand All @@ -89,10 +99,13 @@ impl OrderbookSubgraphClient {

loop {
let page_data = self
.orders_list(PaginationArgs {
page,
page_size: ALL_PAGES_QUERY_PAGE_SIZE,
})
.orders_list(
OrdersListFilterArgs { owners: vec![] },
PaginationArgs {
page,
page_size: ALL_PAGES_QUERY_PAGE_SIZE,
},
)
.await?;
if page_data.is_empty() {
break;
Expand Down
24 changes: 23 additions & 1 deletion crates/subgraph/src/types/common.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::schema;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;

#[derive(cynic::QueryVariables, Debug, Clone)]
Expand All @@ -8,13 +8,35 @@ pub struct IdQueryVariables<'a> {
pub id: &'a cynic::Id,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrdersListFilterArgs {
pub owners: Vec<Bytes>,
}

#[derive(cynic::QueryVariables, Debug, Clone)]
#[typeshare]
pub struct PaginationQueryVariables {
pub first: Option<i32>,
pub skip: Option<i32>,
}

#[derive(cynic::InputObject, Debug, Clone)]
#[cynic(graphql_type = "Order_filter")]
#[typeshare]
pub struct OrdersListQueryFilters {
#[cynic(rename = "owner_in")]
pub owner_in: Vec<Bytes>,
}

#[derive(cynic::QueryVariables, Debug, Clone)]
#[typeshare]
pub struct OrdersListQueryVariables {
pub first: Option<i32>,
pub skip: Option<i32>,
#[cynic(rename = "filters")]
pub filters: Option<OrdersListQueryFilters>,
}

#[derive(cynic::QueryVariables, Debug, Clone)]
#[typeshare]
pub struct PaginationWithIdQueryVariables {
Expand Down
4 changes: 2 additions & 2 deletions crates/subgraph/src/types/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ pub struct BatchOrderDetailQuery {
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Query", variables = "PaginationQueryVariables")]
#[cynic(graphql_type = "Query", variables = "OrdersListQueryVariables")]
#[typeshare]
pub struct OrdersListQuery {
#[arguments(orderBy: "timestampAdded", orderDirection: "desc", skip: $skip, first: $first)]
#[arguments(orderBy: "timestampAdded", orderDirection: "desc", skip: $skip, first: $first, where: $filters)]
pub orders: Vec<Order>,
}

Expand Down
3 changes: 2 additions & 1 deletion crates/subgraph/tests/orders_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use rain_orderbook_subgraph_client::types::order::OrdersListQuery;
fn orders_query_gql_output() {
use cynic::QueryBuilder;

let request_body = OrdersListQuery::build(PaginationQueryVariables {
let request_body = OrdersListQuery::build(OrdersListQueryVariables {
skip: Some(0),
first: Some(10),
filters: None,
});

assert_snapshot!(request_body.query);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
source: crates/subgraph/tests/orders_test.rs
expression: request_body.query
---
query OrdersListQuery($first: Int, $skip: Int) {
orders(orderBy: timestampAdded, orderDirection: desc, skip: $skip, first: $first) {
query OrdersListQuery($first: Int, $skip: Int, $filters: Order_filter) {
orders(orderBy: timestampAdded, orderDirection: desc, skip: $skip, first: $first, where: $filters) {
id
orderBytes
orderHash
Expand Down
3 changes: 2 additions & 1 deletion tauri-app/src-tauri/src/commands/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ use tauri::AppHandle;
#[tauri::command]
pub async fn orders_list(
subgraph_args: SubgraphArgs,
filter_args: OrdersListFilterArgs,
pagination_args: PaginationArgs,
) -> CommandResult<Vec<Order>> {
let orders = subgraph_args
.to_subgraph_client()
.await?
.orders_list(pagination_args)
.orders_list(filter_args, pagination_args)
.await?;
Ok(orders)
}
Expand Down
2 changes: 2 additions & 0 deletions tauri-app/src/lib/components/ListViewOrderbookSelector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { isEmpty } from 'lodash';
import DropdownActiveNetwork from './DropdownActiveNetwork.svelte';
import DropdownActiveOrderbook from './DropdownActiveOrderbook.svelte';
import DropdownOrderListWatchlist from './dropdown/DropdownOrderListWatchlist.svelte';
import { settings } from '$lib/stores/settings';
import { Alert } from 'flowbite-svelte';
</script>
Expand All @@ -12,6 +13,7 @@
>No networks added to <a class="underline" href="/settings">settings</a></Alert
>
{:else}
<DropdownOrderListWatchlist />
<DropdownActiveNetwork />
<DropdownActiveOrderbook />
{/if}
Expand Down
85 changes: 85 additions & 0 deletions tauri-app/src/lib/components/dropdown/DropdownCheckbox.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { Button, Dropdown, Label, Checkbox } from 'flowbite-svelte';
import { ChevronDownSolid } from 'flowbite-svelte-icons';
import { isEmpty } from 'lodash';
const dispatch = createEventDispatcher();
export let options: Record<string, string> = {};
export let value: Record<string, string> = {};
export let label: string = 'Select items';
export let allLabel: string = 'All items';
export let emptyMessage: string = 'No items available';
$: selectedCount = Object.keys(value).length;
$: allSelected = selectedCount === Object.keys(options).length;
$: buttonText =
selectedCount === 0
? 'Select items'
: allSelected
? allLabel
: `${selectedCount} item${selectedCount > 1 ? 's' : ''}`;
function updateValue(newValue: Record<string, string>) {
value = newValue;
dispatch('change', value);
}
function toggleAll() {
updateValue(allSelected ? {} : { ...options });
}
function toggleItem(key: string) {
const newValue = { ...value };
if (key in newValue) {
delete newValue[key];
} else {
newValue[key] = options[key];
}
updateValue(newValue);
}
</script>

<Label>{label}</Label>
<div>
<Button
color="alternative"
class="flex w-full justify-between overflow-hidden pl-2 pr-0 text-left"
data-testid="dropdown-checkbox-button"
>
<div class="w-[90px] overflow-hidden text-ellipsis whitespace-nowrap">
{buttonText}
</div>
<ChevronDownSolid class="mx-2 h-3 w-3 text-black dark:text-white" />
</Button>

<Dropdown class="w-full min-w-72 py-0" data-testid="dropdown-checkbox">
{#if isEmpty(options)}
<div class="ml-2 w-full rounded-lg p-3">{emptyMessage}</div>
{:else if Object.keys(options).length > 1}
<Checkbox
data-testid="dropdown-checkbox-option"
class="w-full rounded-lg p-3 hover:bg-gray-100 dark:hover:bg-gray-600"
on:click={toggleAll}
checked={allSelected}
>
<div class="ml-2">{allLabel}</div>
</Checkbox>
{/if}

{#each Object.entries(options) as [key, optionValue]}
<Checkbox
data-testid="dropdown-checkbox-option"
class="w-full rounded-lg p-3 hover:bg-gray-100 dark:hover:bg-gray-600"
on:click={() => toggleItem(key)}
checked={key in value}
>
<div class="ml-2">
<div class="text-sm font-medium">{key}</div>
<div class="text-xs text-gray-500">{optionValue}</div>
</div>
</Checkbox>
{/each}
</Dropdown>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import { watchlist, activeWatchlistItems } from '$lib/stores/settings';
import DropdownCheckbox from './DropdownCheckbox.svelte';
$: options = $watchlist;
</script>

<DropdownCheckbox
{options}
bind:value={$activeWatchlistItems}
label="Watchlist"
allLabel="All addresses"
emptyMessage="No watchlist added"
/>
Loading

0 comments on commit 8262193

Please sign in to comment.