mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
player filter by steamid
This commit is contained in:
parent
906c77c41e
commit
8fa199f735
5 changed files with 65 additions and 31 deletions
|
|
@ -3,22 +3,29 @@ import {ready} from "./ready";
|
||||||
import {FilterBar} from "./filterbar"
|
import {FilterBar} from "./filterbar"
|
||||||
import {Api} from "./api";
|
import {Api} from "./api";
|
||||||
|
|
||||||
|
let lastFilter = {
|
||||||
|
mode: "",
|
||||||
|
map: "",
|
||||||
|
players: []
|
||||||
|
};
|
||||||
|
|
||||||
ready(() => {
|
ready(() => {
|
||||||
const filterBar = document.getElementById('filter-bar');
|
const filterBar = document.getElementById('filter-bar');
|
||||||
const maps = filterBar.dataset.maps.split(",");
|
const maps = filterBar.dataset.maps.split(",");
|
||||||
const apiBase = filterBar.dataset.apiBase;
|
const apiBase = filterBar.dataset.apiBase;
|
||||||
const api = new Api(apiBase);
|
const api = new Api(apiBase);
|
||||||
const demoListBody = document.querySelector('.demolist tbody');
|
const demoListBody = document.querySelector('.demolist tbody');
|
||||||
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
render(() => <FilterBar maps={maps} api={api} onChange={onFilter.bind(null, api, demoListBody)}/>, filterBar);
|
lastFilter = {
|
||||||
|
mode: searchParams.get("mode") || "",
|
||||||
|
map: searchParams.get("map") || "",
|
||||||
|
players: (searchParams.get("players") || "").split(",")
|
||||||
|
};
|
||||||
|
|
||||||
|
render(() => <FilterBar maps={maps} api={api} initialFilter={lastFilter} onChange={onFilter.bind(null, api, demoListBody)}/>, filterBar);
|
||||||
});
|
});
|
||||||
|
|
||||||
let lastFilter = {
|
|
||||||
mode: "",
|
|
||||||
map: "",
|
|
||||||
players: []
|
|
||||||
};
|
|
||||||
|
|
||||||
const filterEq = (a, b) => {
|
const filterEq = (a, b) => {
|
||||||
return (a.mode || "") === (b.mode || "")
|
return (a.mode || "") === (b.mode || "")
|
||||||
&& (a.map || "") === (b.map || "")
|
&& (a.map || "") === (b.map || "")
|
||||||
|
|
@ -32,7 +39,7 @@ const onFilter = async (api, demoListBody, filter) => {
|
||||||
lastFilter = filter;
|
lastFilter = filter;
|
||||||
|
|
||||||
let queryParams = new URLSearchParams({
|
let queryParams = new URLSearchParams({
|
||||||
players: filter.players.map(player => player.id).join(','),
|
players: filter.players.map(player => player.steamid).join(','),
|
||||||
mode: (filter.mode || "").toLowerCase(),
|
mode: (filter.mode || "").toLowerCase(),
|
||||||
map: filter.map || "",
|
map: filter.map || "",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@ import {createEffect, createSignal} from "solid-js";
|
||||||
export interface FilterBarProps {
|
export interface FilterBarProps {
|
||||||
maps: string[],
|
maps: string[],
|
||||||
api: Api,
|
api: Api,
|
||||||
|
initialFilter: FilterSet,
|
||||||
onChange: (FilterSet) => void,
|
onChange: (FilterSet) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FilterBar = ({maps, api, onChange}: FilterBarProps) => {
|
export const FilterBar = ({maps, api, onChange, initialFilter}: FilterBarProps) => {
|
||||||
const modes = createOptions(["4v4", "6v6", "Highlander"]);
|
const modes = createOptions(["4v4", "6v6", "Highlander"]);
|
||||||
const mapOptions = createOptions(maps, {
|
const mapOptions = createOptions(maps, {
|
||||||
createable: true
|
createable: true
|
||||||
|
|
@ -16,14 +17,10 @@ export const FilterBar = ({maps, api, onChange}: FilterBarProps) => {
|
||||||
const playerOptions = createAsyncOptions(search => api.searchPlayer(search));
|
const playerOptions = createAsyncOptions(search => api.searchPlayer(search));
|
||||||
const playerFormat = player => player.name;
|
const playerFormat = player => player.name;
|
||||||
|
|
||||||
const [initialMode, setInitialMode] = createSignal("", {equals: false});
|
const [initialMode, setInitialMode] = createSignal(initialFilter.mode, {equals: false});
|
||||||
const [initialMap, setInitialMap] = createSignal("", {equals: false});
|
const [initialMap, setInitialMap] = createSignal(initialFilter.map, {equals: false});
|
||||||
|
|
||||||
const [filterSet, setFilterSet] = createSignal({
|
const [filterSet, setFilterSet] = createSignal(initialFilter);
|
||||||
mode: "",
|
|
||||||
map: "",
|
|
||||||
players: []
|
|
||||||
});
|
|
||||||
createEffect(() => onChange(filterSet()));
|
createEffect(() => onChange(filterSet()));
|
||||||
|
|
||||||
return <div class="filter-bar">
|
return <div class="filter-bar">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::data::chat::Chat;
|
use crate::data::chat::Chat;
|
||||||
use crate::data::player::Player;
|
use crate::data::player::Player;
|
||||||
use crate::data::schema::{ArrayAgg, CleanMapName, Demos, Players};
|
use crate::data::schema::{ArrayAgg, CleanMapName, Demos, Players, Users};
|
||||||
use crate::data::steam_id::SteamId;
|
use crate::data::steam_id::SteamId;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use maud::Render;
|
use maud::Render;
|
||||||
|
|
@ -180,15 +180,15 @@ impl ListDemo {
|
||||||
} else {
|
} else {
|
||||||
let mut query = Query::select();
|
let mut query = Query::select();
|
||||||
query
|
query
|
||||||
.column((Demos::Table, Demos::Id))
|
|
||||||
.column((Demos::Table, Demos::Name))
|
|
||||||
.columns([
|
.columns([
|
||||||
Demos::Map,
|
(Demos::Table, Demos::Id),
|
||||||
Demos::Red,
|
(Demos::Table, Demos::Name),
|
||||||
Demos::Blu,
|
(Demos::Table, Demos::Map),
|
||||||
Demos::Duration,
|
(Demos::Table, Demos::Red),
|
||||||
Demos::Server,
|
(Demos::Table, Demos::Blu),
|
||||||
Demos::CreatedAt,
|
(Demos::Table, Demos::Duration),
|
||||||
|
(Demos::Table, Demos::Server),
|
||||||
|
(Demos::Table, Demos::CreatedAt),
|
||||||
])
|
])
|
||||||
.expr_as(Expr::col(Demos::PlayerCount), Alias::new("player_count"))
|
.expr_as(Expr::col(Demos::PlayerCount), Alias::new("player_count"))
|
||||||
.from(Demos::Table)
|
.from(Demos::Table)
|
||||||
|
|
@ -375,7 +375,7 @@ pub struct Filter {
|
||||||
map: String,
|
map: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[serde(deserialize_with = "deserialize_array")]
|
#[serde(deserialize_with = "deserialize_array")]
|
||||||
players: Vec<i32>,
|
players: Vec<SteamId>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
before: Option<i32>,
|
before: Option<i32>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
@ -388,6 +388,9 @@ where
|
||||||
T: Deserialize<'de> + FromStr,
|
T: Deserialize<'de> + FromStr,
|
||||||
{
|
{
|
||||||
let s = <Cow<str>>::deserialize(deserializer)?;
|
let s = <Cow<str>>::deserialize(deserializer)?;
|
||||||
|
if s.is_empty() {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
Ok(s.split(",").map(T::from_str).flatten().collect())
|
Ok(s.split(",").map(T::from_str).flatten().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,7 +426,7 @@ impl Filter {
|
||||||
let mut player = self.players.iter();
|
let mut player = self.players.iter();
|
||||||
let mut players_arr = format!("array[{}", player.next().unwrap());
|
let mut players_arr = format!("array[{}", player.next().unwrap());
|
||||||
for player in player {
|
for player in player {
|
||||||
write!(&mut players_arr, ",{}", player).unwrap();
|
write!(&mut players_arr, r#","{}""#, player).unwrap();
|
||||||
}
|
}
|
||||||
players_arr.push_str("]");
|
players_arr.push_str("]");
|
||||||
|
|
||||||
|
|
@ -432,12 +435,16 @@ impl Filter {
|
||||||
Players::Table,
|
Players::Table,
|
||||||
Expr::col((Demos::Table, Demos::Id)).equals((Players::Table, Players::DemoId)),
|
Expr::col((Demos::Table, Demos::Id)).equals((Players::Table, Players::DemoId)),
|
||||||
)
|
)
|
||||||
.and_where(Expr::col(Players::UserId).is_in(self.players.clone()));
|
.inner_join(
|
||||||
|
Users::Table,
|
||||||
|
Expr::col((Users::Table, Users::Id)).equals((Players::Table, Players::UserId)),
|
||||||
|
)
|
||||||
|
.and_where(Expr::col(Users::SteamId).is_in(self.players.clone()));
|
||||||
query.group_by_col((Demos::Table, Players::Id));
|
query.group_by_col((Demos::Table, Players::Id));
|
||||||
query.and_having(
|
query.and_having(
|
||||||
Expr::cust(&players_arr).contained(
|
Expr::cust(&players_arr)
|
||||||
Func::cust(ArrayAgg).arg(Expr::col((Players::Table, Players::UserId))),
|
.cast_as(Alias::new("varchar[]"))
|
||||||
),
|
.contained(Func::cust(ArrayAgg).arg(Expr::col((Users::Table, Users::SteamId)))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,3 +92,19 @@ pub enum Players {
|
||||||
#[iden = "deaths"]
|
#[iden = "deaths"]
|
||||||
Deaths,
|
Deaths,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Iden)]
|
||||||
|
pub enum Users {
|
||||||
|
Table,
|
||||||
|
#[iden = "id"]
|
||||||
|
Id,
|
||||||
|
#[iden = "steamid"]
|
||||||
|
SteamId,
|
||||||
|
#[iden = "name"]
|
||||||
|
Name,
|
||||||
|
#[iden = "avatar"]
|
||||||
|
Avatar,
|
||||||
|
#[iden = "token"]
|
||||||
|
Token,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use maud::Render;
|
use maud::Render;
|
||||||
|
use sea_query::Value;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::database::HasValueRef;
|
use sqlx::database::HasValueRef;
|
||||||
use sqlx::error::BoxDynError;
|
use sqlx::error::BoxDynError;
|
||||||
|
|
@ -154,3 +155,9 @@ impl FromStr for SteamId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SteamId> for Value {
|
||||||
|
fn from(value: SteamId) -> Self {
|
||||||
|
Value::String(Some(Box::new(value.steamid64())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue