forked from Kieran/snort
Bugfixes
This commit is contained in:
parent
e8519daa47
commit
8c7fbed191
@ -6,7 +6,8 @@
|
||||
"scripts": {
|
||||
"build": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-react build && yarn workspace @snort/app build",
|
||||
"start": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/system-react build && yarn workspace @snort/app start",
|
||||
"test": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/app test && yarn workspace @snort/system test"
|
||||
"test": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/app test && yarn workspace @snort/system test",
|
||||
"pre:commit": "yarn workspace @snort/app intl-extract && yarn workspace @snort/app intl-compile && yarn prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20230307.0",
|
||||
|
@ -14,6 +14,7 @@
|
||||
"@snort/system-query": "workspace:*",
|
||||
"@snort/system-react": "workspace:*",
|
||||
"@szhsin/react-menu": "^3.3.1",
|
||||
"@types/use-sync-external-store": "^0.0.4",
|
||||
"@void-cat/api": "^1.0.4",
|
||||
"debug": "^4.3.4",
|
||||
"dexie": "^3.2.4",
|
||||
@ -30,6 +31,7 @@
|
||||
"react-textarea-autosize": "^8.4.0",
|
||||
"react-twitter-embed": "^4.0.4",
|
||||
"use-long-press": "^2.0.3",
|
||||
"use-sync-external-store": "^1.2.0",
|
||||
"uuid": "^9.0.0",
|
||||
"workbox-core": "^6.4.2",
|
||||
"workbox-precaching": "^7.0.0",
|
||||
|
@ -81,8 +81,8 @@ export default function CashuNuts({ token }: { token: string }) {
|
||||
x2="7.11501"
|
||||
y2="6.7213"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||
<stop stopColor="white" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_1976_19241"
|
||||
@ -91,8 +91,8 @@ export default function CashuNuts({ token }: { token: string }) {
|
||||
x2="7.11501"
|
||||
y2="32.2311"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||
<stop stopColor="white" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_1976_19241"
|
||||
@ -101,8 +101,8 @@ export default function CashuNuts({ token }: { token: string }) {
|
||||
x2="22.2658"
|
||||
y2="19.4576"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||
<stop stopColor="white" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import "./Modal.css";
|
||||
import { ReactNode } from "react";
|
||||
import { ReactNode, useEffect } from "react";
|
||||
|
||||
export interface ModalProps {
|
||||
id: string;
|
||||
@ -9,6 +9,11 @@ export interface ModalProps {
|
||||
}
|
||||
|
||||
export default function Modal(props: ModalProps) {
|
||||
useEffect(() => {
|
||||
document.body.classList.add("scroll-lock");
|
||||
return () => document.body.classList.remove("scroll-lock");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={`modal${props.className ? ` ${props.className}` : ""}`} onClick={props.onClose}>
|
||||
<div className="modal-body" onClick={e => e.stopPropagation()}>
|
||||
|
@ -52,7 +52,7 @@ export default function NoteFooter(props: NoteFooterProps) {
|
||||
const author = useUserProfile(ev.pubkey);
|
||||
const interactionCache = useInteractionCache(publicKey, ev.id);
|
||||
const publisher = useEventPublisher();
|
||||
const note = useNoteCreator();
|
||||
const note = useNoteCreator(n => ({ show: n.show, replyTo: n.replyTo, update: n.update }));
|
||||
const willRenderNoteCreator = note.show && note.replyTo?.id === ev.id;
|
||||
const [tip, setTip] = useState(false);
|
||||
const [zapping, setZapping] = useState(false);
|
||||
@ -263,7 +263,7 @@ export default function NoteFooter(props: NoteFooterProps) {
|
||||
{tipButton()}
|
||||
{powIcon()}
|
||||
</div>
|
||||
{willRenderNoteCreator && <NoteCreator />}
|
||||
{willRenderNoteCreator && <NoteCreator key={`note-creator-${ev.id}`} />}
|
||||
<SendSats targets={getZapTarget()} onClose={() => setTip(false)} show={tip} note={ev.id} allocatePool={true} />
|
||||
</div>
|
||||
<ZapsSummary zaps={zaps} />
|
||||
|
@ -68,7 +68,10 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
||||
}
|
||||
|
||||
getSessions() {
|
||||
return [...this.#accounts.values()].map(v => unwrap(v.publicKey));
|
||||
return [...this.#accounts.values()].map(v => ({
|
||||
pubkey: unwrap(v.publicKey),
|
||||
id: v.id,
|
||||
}));
|
||||
}
|
||||
|
||||
allSubscriptions() {
|
||||
|
@ -25,19 +25,12 @@ import { LoginUnlock } from "Element/PinPrompt";
|
||||
|
||||
export default function Layout() {
|
||||
const location = useLocation();
|
||||
const note = useNoteCreator();
|
||||
const isReplyNoteCreatorShowing = note.replyTo && note.show;
|
||||
const [pageClass, setPageClass] = useState("page");
|
||||
|
||||
useLoginFeed();
|
||||
useTheme();
|
||||
useLoginRelays();
|
||||
|
||||
const shouldHideNoteCreator = useMemo(() => {
|
||||
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/e", "/subscribe"];
|
||||
return isReplyNoteCreatorShowing || hideOn.some(a => location.pathname.startsWith(a));
|
||||
}, [location, isReplyNoteCreatorShowing]);
|
||||
|
||||
const shouldHideHeader = useMemo(() => {
|
||||
const hideOn = ["/login", "/new"];
|
||||
return hideOn.some(a => location.pathname.startsWith(a));
|
||||
@ -63,21 +56,7 @@ export default function Layout() {
|
||||
</header>
|
||||
)}
|
||||
<Outlet />
|
||||
{!shouldHideNoteCreator && (
|
||||
<>
|
||||
<button
|
||||
className="primary note-create-button"
|
||||
onClick={() =>
|
||||
note.update(v => {
|
||||
v.replyTo = undefined;
|
||||
v.show = true;
|
||||
})
|
||||
}>
|
||||
<Icon name="plus" size={16} />
|
||||
</button>
|
||||
<NoteCreator />
|
||||
</>
|
||||
)}
|
||||
<NoteCreatorButton />
|
||||
<Toaster />
|
||||
</div>
|
||||
<LoginUnlock />
|
||||
@ -85,6 +64,34 @@ export default function Layout() {
|
||||
);
|
||||
}
|
||||
|
||||
const NoteCreatorButton = () => {
|
||||
const location = useLocation();
|
||||
const { show, replyTo, update } = useNoteCreator(v => ({ show: v.show, replyTo: v.replyTo, update: v.update }));
|
||||
|
||||
const shouldHideNoteCreator = useMemo(() => {
|
||||
const isReplyNoteCreatorShowing = replyTo && show;
|
||||
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/e", "/subscribe"];
|
||||
return isReplyNoteCreatorShowing || hideOn.some(a => location.pathname.startsWith(a));
|
||||
}, [location]);
|
||||
|
||||
if (shouldHideNoteCreator) return;
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="primary note-create-button"
|
||||
onClick={() =>
|
||||
update(v => {
|
||||
v.replyTo = undefined;
|
||||
v.show = true;
|
||||
})
|
||||
}>
|
||||
<Icon name="plus" size={16} />
|
||||
</button>
|
||||
<NoteCreator key="global-note-creator" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const AccountHeader = () => {
|
||||
const navigate = useNavigate();
|
||||
const { formatMessage } = useIntl();
|
||||
|
@ -1,57 +1,32 @@
|
||||
import { useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import ProfilePreview from "Element/ProfilePreview";
|
||||
import { LoginStore } from "Login";
|
||||
import useLoginHandler from "Hooks/useLoginHandler";
|
||||
import AsyncButton from "Element/AsyncButton";
|
||||
import { getActiveSubscriptions } from "Subscription";
|
||||
|
||||
export default function AccountsPage() {
|
||||
const { formatMessage } = useIntl();
|
||||
const [key, setKey] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const loginHandler = useLoginHandler();
|
||||
const logins = LoginStore.getSessions();
|
||||
const sub = getActiveSubscriptions(LoginStore.allSubscriptions());
|
||||
|
||||
async function doLogin() {
|
||||
try {
|
||||
setError("");
|
||||
await loginHandler.doLogin(key);
|
||||
setKey("");
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
setError(e.message);
|
||||
} else {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown login error",
|
||||
}),
|
||||
);
|
||||
}
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex-column g12">
|
||||
<h3>
|
||||
<FormattedMessage defaultMessage="Logins" />
|
||||
</h3>
|
||||
{logins.map(a => (
|
||||
<div className="card flex" key={a}>
|
||||
<div className="card flex" key={a.id}>
|
||||
<ProfilePreview
|
||||
pubkey={a}
|
||||
pubkey={a.pubkey}
|
||||
options={{
|
||||
about: false,
|
||||
}}
|
||||
actions={
|
||||
<div className="f-1">
|
||||
<button className="mb10" onClick={() => LoginStore.switchAccount(a)}>
|
||||
<button className="mb10" onClick={() => LoginStore.switchAccount(a.id)}>
|
||||
<FormattedMessage defaultMessage="Switch" />
|
||||
</button>
|
||||
<button onClick={() => LoginStore.removeSession(a)}>
|
||||
<button onClick={() => LoginStore.removeSession(a.id)}>
|
||||
<FormattedMessage defaultMessage="Logout" />
|
||||
</button>
|
||||
</div>
|
||||
@ -61,27 +36,12 @@ export default function AccountsPage() {
|
||||
))}
|
||||
|
||||
{sub && (
|
||||
<>
|
||||
<h3>
|
||||
<Link to={"/login"}>
|
||||
<button type="button">
|
||||
<FormattedMessage defaultMessage="Add Account" />
|
||||
</h3>
|
||||
<div className="flex">
|
||||
<input
|
||||
dir="auto"
|
||||
type="text"
|
||||
placeholder={formatMessage({
|
||||
defaultMessage: "nsec, npub, nip-05, hex, mnemonic",
|
||||
})}
|
||||
className="f-grow mr10"
|
||||
onChange={e => setKey(e.target.value)}
|
||||
/>
|
||||
<AsyncButton onClick={() => doLogin()}>
|
||||
<FormattedMessage defaultMessage="Login" />
|
||||
</AsyncButton>
|
||||
</div>
|
||||
</>
|
||||
</button>
|
||||
</Link>
|
||||
)}
|
||||
{error && <b className="error">{error}</b>}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { ExternalStore } from "@snort/shared";
|
||||
import { NostrEvent, TaggedNostrEvent } from "@snort/system";
|
||||
import { ZapTarget } from "Zapper";
|
||||
import { useSyncExternalStore } from "react";
|
||||
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector";
|
||||
|
||||
interface NoteCreatorDataSnapshot {
|
||||
show: boolean;
|
||||
@ -33,11 +34,11 @@ class NoteCreatorStore extends ExternalStore<NoteCreatorDataSnapshot> {
|
||||
advanced: false,
|
||||
reset: () => {
|
||||
this.#reset(this.#data);
|
||||
this.notifyChange();
|
||||
this.notifyChange(this.#data);
|
||||
},
|
||||
update: (fn: (v: NoteCreatorDataSnapshot) => void) => {
|
||||
fn(this.#data);
|
||||
this.notifyChange();
|
||||
this.notifyChange(this.#data);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -65,8 +66,7 @@ class NoteCreatorStore extends ExternalStore<NoteCreatorDataSnapshot> {
|
||||
},
|
||||
update: (fn: (v: NoteCreatorDataSnapshot) => void) => {
|
||||
fn(this.#data);
|
||||
console.debug(this.#data);
|
||||
this.notifyChange();
|
||||
this.notifyChange(this.#data);
|
||||
},
|
||||
} as NoteCreatorDataSnapshot;
|
||||
return sn;
|
||||
@ -75,9 +75,20 @@ class NoteCreatorStore extends ExternalStore<NoteCreatorDataSnapshot> {
|
||||
|
||||
const NoteCreatorState = new NoteCreatorStore();
|
||||
|
||||
export function useNoteCreator() {
|
||||
return useSyncExternalStore(
|
||||
export function useNoteCreator<T extends object = NoteCreatorDataSnapshot>(
|
||||
selector?: (v: NoteCreatorDataSnapshot) => T,
|
||||
) {
|
||||
if (selector) {
|
||||
return useSyncExternalStoreWithSelector<NoteCreatorDataSnapshot, T>(
|
||||
c => NoteCreatorState.hook(c),
|
||||
() => NoteCreatorState.snapshot(),
|
||||
undefined,
|
||||
selector,
|
||||
);
|
||||
} else {
|
||||
return useSyncExternalStore<T>(
|
||||
c => NoteCreatorState.hook(c),
|
||||
() => NoteCreatorState.snapshot() as T,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import { preload, RelayMetrics, UserCache, UserRelays } from "Cache";
|
||||
import { LoginStore } from "Login";
|
||||
import { SnortDeckLayout } from "Pages/DeckLayout";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const WasmQueryOptimizer = {
|
||||
expandFilter: (f: ReqFilter) => {
|
||||
return expand_filter(f) as Array<FlatReqFilter>;
|
||||
@ -61,7 +60,7 @@ export const System = new NostrSystem({
|
||||
relayCache: UserRelays,
|
||||
profileCache: UserCache,
|
||||
relayMetrics: RelayMetrics,
|
||||
//queryOptimizer: WasmQueryOptimizer,
|
||||
queryOptimizer: WasmQueryOptimizer,
|
||||
authHandler: async (c, r) => {
|
||||
const { id } = LoginStore.snapshot();
|
||||
const pub = LoginStore.getPublisher(id);
|
||||
|
@ -35,9 +35,7 @@ export abstract class ExternalStore<TSnapshot> {
|
||||
protected notifyChange(sn?: TSnapshot) {
|
||||
this.#changed = true;
|
||||
if (this.#hooks.length > 0) {
|
||||
queueMicrotask(() => {
|
||||
this.#hooks.forEach(h => h.fn(sn));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -39,6 +41,8 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
|
Binary file not shown.
@ -28,6 +28,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -42,6 +44,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -63,6 +67,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -78,6 +84,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -92,6 +100,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -111,6 +121,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -130,6 +142,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -144,6 +158,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -162,6 +178,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
|
@ -29,6 +29,10 @@ pub struct ReqFilter {
|
||||
pub d_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "#r", skip_serializing_if = "Option::is_none")]
|
||||
pub r_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "#a", skip_serializing_if = "Option::is_none")]
|
||||
pub a_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "#g", skip_serializing_if = "Option::is_none")]
|
||||
pub g_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "search", skip_serializing_if = "Option::is_none")]
|
||||
pub search: Option<HashSet<String>>,
|
||||
#[serde(rename = "since", skip_serializing_if = "Option::is_none")]
|
||||
@ -64,6 +68,10 @@ pub struct FlatReqFilter {
|
||||
pub d_tag: Option<String>,
|
||||
#[serde(rename = "#r", skip_serializing_if = "Option::is_none")]
|
||||
pub r_tag: Option<String>,
|
||||
#[serde(rename = "#a", skip_serializing_if = "Option::is_none")]
|
||||
pub a_tag: Option<String>,
|
||||
#[serde(rename = "#g", skip_serializing_if = "Option::is_none")]
|
||||
pub g_tag: Option<String>,
|
||||
#[serde(rename = "search", skip_serializing_if = "Option::is_none")]
|
||||
pub search: Option<String>,
|
||||
#[serde(rename = "since", skip_serializing_if = "Option::is_none")]
|
||||
@ -145,6 +153,8 @@ impl From<Vec<&FlatReqFilter>> for ReqFilter {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -159,6 +169,8 @@ impl From<Vec<&FlatReqFilter>> for ReqFilter {
|
||||
array_prop_append(&x.t_tag, &mut acc.t_tag);
|
||||
array_prop_append(&x.d_tag, &mut acc.d_tag);
|
||||
array_prop_append(&x.r_tag, &mut acc.r_tag);
|
||||
array_prop_append(&x.a_tag, &mut acc.a_tag);
|
||||
array_prop_append(&x.g_tag, &mut acc.g_tag);
|
||||
array_prop_append(&x.search, &mut acc.search);
|
||||
acc.since = x.since;
|
||||
acc.until = x.until;
|
||||
@ -180,6 +192,8 @@ impl From<Vec<&ReqFilter>> for ReqFilter {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -194,6 +208,8 @@ impl From<Vec<&ReqFilter>> for ReqFilter {
|
||||
array_prop_append_vec(&x.t_tag, &mut acc.t_tag);
|
||||
array_prop_append_vec(&x.d_tag, &mut acc.d_tag);
|
||||
array_prop_append_vec(&x.r_tag, &mut acc.r_tag);
|
||||
array_prop_append_vec(&x.a_tag, &mut acc.a_tag);
|
||||
array_prop_append_vec(&x.g_tag, &mut acc.g_tag);
|
||||
array_prop_append_vec(&x.search, &mut acc.search);
|
||||
acc.since = x.since;
|
||||
acc.until = x.until;
|
||||
@ -265,6 +281,20 @@ impl Into<Vec<FlatReqFilter>> for &ReqFilter {
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(a_tags) = &self.a_tag {
|
||||
let t_ids = a_tags
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("a_tag", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(g_tags) = &self.g_tag {
|
||||
let t_ids = g_tags
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("g_tag", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(search) = &self.search {
|
||||
let t_ids = search
|
||||
.iter()
|
||||
@ -339,6 +369,22 @@ impl Into<Vec<FlatReqFilter>> for &ReqFilter {
|
||||
}
|
||||
None
|
||||
}),
|
||||
a_tag: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("a_tag") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
g_tag: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("g_tag") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
search: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("search") {
|
||||
@ -355,6 +401,7 @@ impl Into<Vec<FlatReqFilter>> for &ReqFilter {
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl Distance for ReqFilter {
|
||||
fn distance(&self, b: &Self) -> u32 {
|
||||
let mut ret = 0u32;
|
||||
@ -367,6 +414,7 @@ impl Distance for ReqFilter {
|
||||
ret += prop_dist_vec(&self.d_tag, &b.d_tag);
|
||||
ret += prop_dist_vec(&self.r_tag, &b.r_tag);
|
||||
ret += prop_dist_vec(&self.t_tag, &b.t_tag);
|
||||
ret += prop_dist_vec(&self.a_tag, &b.a_tag);
|
||||
ret += prop_dist_vec(&self.search, &b.search);
|
||||
|
||||
ret
|
||||
@ -464,6 +512,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -471,7 +521,7 @@ mod tests {
|
||||
e_tag: None,
|
||||
};
|
||||
|
||||
let output : Vec<FlatReqFilter> = (&input).into();
|
||||
let output: Vec<FlatReqFilter> = (&input).into();
|
||||
let expected = vec![
|
||||
FlatReqFilter {
|
||||
author: Some("a".to_owned()),
|
||||
@ -481,6 +531,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -495,6 +547,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -509,6 +563,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -523,6 +579,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -537,6 +595,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -551,6 +611,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -565,6 +627,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -579,6 +643,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -593,6 +659,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -607,6 +675,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -621,6 +691,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -635,6 +707,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -649,6 +723,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -663,6 +739,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -677,6 +755,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -691,6 +771,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -705,6 +787,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
@ -719,6 +803,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
|
@ -74,6 +74,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
authors: Some(HashSet::from([
|
||||
"kieran".to_string(),
|
||||
"snort".to_string(),
|
||||
@ -94,6 +96,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -109,6 +113,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -122,6 +128,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::filter::CanMerge;
|
||||
|
||||
pub fn merge<'a, T, Z>(all: Vec<&'a T>) -> Vec<Z>
|
||||
where
|
||||
where
|
||||
T: CanMerge,
|
||||
for<'b> Z: CanMerge + From<Vec<&'a T>> + From<Vec<&'b Z>>,
|
||||
{
|
||||
@ -17,7 +17,7 @@ where
|
||||
}
|
||||
|
||||
fn merge_once<'a, T, Z>(all: Vec<&'a T>) -> Vec<Z>
|
||||
where
|
||||
where
|
||||
T: CanMerge,
|
||||
Z: From<Vec<&'a T>>,
|
||||
{
|
||||
@ -66,6 +66,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -80,6 +82,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -94,6 +98,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -108,6 +114,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -122,6 +130,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -144,6 +154,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -158,6 +170,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -173,6 +187,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -192,6 +208,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -206,6 +224,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -220,6 +240,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -241,6 +263,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -255,6 +279,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -269,6 +295,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -283,6 +311,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -297,6 +327,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -311,6 +343,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -325,6 +359,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -339,6 +375,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -353,6 +391,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -373,6 +413,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -387,6 +429,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -401,6 +445,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -415,6 +461,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
@ -429,6 +477,8 @@ mod tests {
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
a_tag: None,
|
||||
g_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
|
18
yarn.lock
18
yarn.lock
@ -2698,6 +2698,7 @@ __metadata:
|
||||
"@types/node": ^20.4.1
|
||||
"@types/react": ^18.0.26
|
||||
"@types/react-dom": ^18.0.10
|
||||
"@types/use-sync-external-store": ^0.0.4
|
||||
"@types/uuid": ^9.0.2
|
||||
"@types/webscopeio__react-textarea-autocomplete": ^4.7.2
|
||||
"@types/webtorrent": ^0.109.3
|
||||
@ -2740,6 +2741,7 @@ __metadata:
|
||||
ts-loader: ^9.4.4
|
||||
typescript: ^5.2.2
|
||||
use-long-press: ^2.0.3
|
||||
use-sync-external-store: ^1.2.0
|
||||
uuid: ^9.0.0
|
||||
webpack: ^5.88.2
|
||||
webpack-bundle-analyzer: ^4.8.0
|
||||
@ -3568,6 +3570,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/use-sync-external-store@npm:^0.0.4":
|
||||
version: 0.0.4
|
||||
resolution: "@types/use-sync-external-store@npm:0.0.4"
|
||||
checksum: f8bf56b14f28fda6d0215281d50623d5affd17c549ba46bcfcfbb97c6301a583066c0477856260ae6feadcaa714c46cd45678e76b74da0f6f8b364aec07bd854
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/uuid@npm:^9.0.2":
|
||||
version: 9.0.2
|
||||
resolution: "@types/uuid@npm:9.0.2"
|
||||
@ -13331,6 +13340,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"use-sync-external-store@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "use-sync-external-store@npm:1.2.0"
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1":
|
||||
version: 1.0.2
|
||||
resolution: "util-deprecate@npm:1.0.2"
|
||||
|
Loading…
Reference in New Issue
Block a user