Link up omnisearch lookup
All checks were successful
Build and Publish Docker Container / build (push) Successful in 1m0s
All checks were successful
Build and Publish Docker Container / build (push) Successful in 1m0s
This commit is contained in:
parent
87e482e943
commit
5d146aaf3f
106
src/App.tsx
106
src/App.tsx
@ -1,7 +1,4 @@
|
|||||||
import {ReactNode, useCallback, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {FixedSizeList as List} from "react-window";
|
|
||||||
import Select, {createFilter, MenuListProps} from "react-select";
|
|
||||||
import * as R from 'ramda';
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import {useQuery} from "@tanstack/react-query";
|
import {useQuery} from "@tanstack/react-query";
|
||||||
@ -9,73 +6,6 @@ import {LinkCollection, type Option} from "./aliases";
|
|||||||
|
|
||||||
import {CheckIcon, ChevronUpDownIcon} from '@heroicons/react/20/solid'
|
import {CheckIcon, ChevronUpDownIcon} from '@heroicons/react/20/solid'
|
||||||
import {Combobox} from '@headlessui/react'
|
import {Combobox} from '@headlessui/react'
|
||||||
// TODO: Fix this for wrapping items, esp on phones
|
|
||||||
const height = 35;
|
|
||||||
|
|
||||||
function MenuList(props: MenuListProps) {
|
|
||||||
const {
|
|
||||||
options,
|
|
||||||
children,
|
|
||||||
maxHeight,
|
|
||||||
getValue
|
|
||||||
} = props as Omit<MenuListProps, 'children'> & {
|
|
||||||
children: ReactNode[]
|
|
||||||
};
|
|
||||||
|
|
||||||
const [value] = getValue();
|
|
||||||
const initialOffset = options.indexOf(value) * height;
|
|
||||||
|
|
||||||
return (<List
|
|
||||||
width={'100%'}
|
|
||||||
height={maxHeight}
|
|
||||||
itemCount={children?.length ?? 0}
|
|
||||||
itemSize={height}
|
|
||||||
initialScrollOffset={initialOffset}
|
|
||||||
>
|
|
||||||
{({
|
|
||||||
index,
|
|
||||||
style
|
|
||||||
}) => <div style={style}>{children[index]}</div>}
|
|
||||||
</List>);
|
|
||||||
}
|
|
||||||
|
|
||||||
function NaiveSelect({setSelected}: {
|
|
||||||
setSelected: (value: Option) => void
|
|
||||||
}) {
|
|
||||||
const {
|
|
||||||
data: options,
|
|
||||||
isLoading,
|
|
||||||
} = useQuery({
|
|
||||||
queryKey: ['obsidian-metadata'],
|
|
||||||
initialData: [],
|
|
||||||
queryFn: async () => {
|
|
||||||
const response = await fetch("/metadata")
|
|
||||||
const fullData: any[] = await response.json();
|
|
||||||
|
|
||||||
return R.sortBy(v => -(v.data.backlinks?.length ?? 0), fullData.map(md => ({
|
|
||||||
value: md.relativePath,
|
|
||||||
label: md.fileName,
|
|
||||||
data: md,
|
|
||||||
}) as Option));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const onChange = useCallback((value: Option) => {
|
|
||||||
setSelected(value);
|
|
||||||
navigator.clipboard.writeText(`[[${value.label}]]`)
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (<Select
|
|
||||||
classNames={{input: () => 'select-input-wrapper'}}
|
|
||||||
onChange={onChange as any}
|
|
||||||
components={{MenuList}}
|
|
||||||
isDisabled={isLoading}
|
|
||||||
isLoading={isLoading}
|
|
||||||
isClearable={true}
|
|
||||||
options={options}
|
|
||||||
filterOption={createFilter({ignoreAccents: false})}
|
|
||||||
/>)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultNoteApi = {
|
type ResultNoteApi = {
|
||||||
score: number
|
score: number
|
||||||
@ -101,20 +31,16 @@ export function OmnisearchSelect({setSelected}: {
|
|||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryKey: ['obsidian-metadata'],
|
queryKey: ['obsidian-metadata'],
|
||||||
initialData: [],
|
initialData: [],
|
||||||
|
refetchInterval: false,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const response = await fetch("/metadata")
|
const response = await fetch("http://localhost:9002/metadata")
|
||||||
const fullData: any[] = await response.json();
|
const fullData: any[] = await response.json();
|
||||||
|
return fullData;
|
||||||
return R.sortBy(v => -(v.data.backlinks?.length ?? 0), fullData.map(md => ({
|
|
||||||
value: md.relativePath,
|
|
||||||
label: md.fileName,
|
|
||||||
data: md,
|
|
||||||
}) as Option));
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [query, setQuery] = useState('')
|
const [query, setQuery] = useState('')
|
||||||
const [selectedPerson, setSelectedPerson] = useState(null);
|
const [selectedPerson, setSelectedPerson] = useState<ResultNoteApi | null>(null);
|
||||||
|
|
||||||
const {data: filteredPeople} = useQuery({
|
const {data: filteredPeople} = useQuery({
|
||||||
queryKey: ['obsidian-omnisearch', query],
|
queryKey: ['obsidian-omnisearch', query],
|
||||||
@ -123,7 +49,7 @@ export function OmnisearchSelect({setSelected}: {
|
|||||||
if (query === '') {
|
if (query === '') {
|
||||||
return [];
|
return [];
|
||||||
} else {
|
} else {
|
||||||
const response = await fetch(`/search?q=${query}`)
|
const response = await fetch(`http://localhost:9002/search?q=${query}`)
|
||||||
const fullData: ResultNoteApi[] = await response.json();
|
const fullData: ResultNoteApi[] = await response.json();
|
||||||
|
|
||||||
return fullData;
|
return fullData;
|
||||||
@ -131,14 +57,32 @@ export function OmnisearchSelect({setSelected}: {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedPerson != undefined && metadata.length > 0) {
|
||||||
|
console.log(selectedPerson);
|
||||||
|
const data = metadata.find(md => md.relativePath === selectedPerson.path);
|
||||||
|
if (!data) {
|
||||||
|
debugger
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected({
|
||||||
|
value: selectedPerson.path,
|
||||||
|
label: selectedPerson.basename,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [selectedPerson, metadata]);
|
||||||
|
|
||||||
return (<Combobox as="div" value={selectedPerson} onChange={setSelectedPerson}>
|
return (<Combobox as="div" value={selectedPerson} onChange={setSelectedPerson}>
|
||||||
<Combobox.Label className="block text-sm font-medium leading-6 text-gray-900">Assigned to</Combobox.Label>
|
<Combobox.Label className="block text-sm font-medium leading-6 text-gray-900">Search for note</Combobox.Label>
|
||||||
<div className="relative mt-2">
|
<div className="relative mt-2">
|
||||||
<Combobox.Input
|
<Combobox.Input
|
||||||
|
aria-disabled={isLoading}
|
||||||
className="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
className="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||||
onChange={(event) => setQuery(event.target.value)}
|
onChange={(event) => setQuery(event.target.value)}
|
||||||
displayValue={(person: ResultNoteApi) => person?.basename}
|
displayValue={(person: ResultNoteApi) => person?.basename}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Combobox.Button
|
<Combobox.Button
|
||||||
className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
|
className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
|
||||||
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true"/>
|
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true"/>
|
||||||
|
|||||||
74
src/NaiveSelect.tsx
Normal file
74
src/NaiveSelect.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// TODO: Fix this for wrapping items, esp on phones
|
||||||
|
import Select, {createFilter, MenuListProps} from "react-select";
|
||||||
|
import {ReactNode, useCallback} from "react";
|
||||||
|
import {FixedSizeList as List} from "react-window";
|
||||||
|
import type {Option} from "./aliases.tsx";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import * as R from "ramda";
|
||||||
|
|
||||||
|
const height = 35;
|
||||||
|
|
||||||
|
function MenuList(props: MenuListProps) {
|
||||||
|
const {
|
||||||
|
options,
|
||||||
|
children,
|
||||||
|
maxHeight,
|
||||||
|
getValue
|
||||||
|
} = props as Omit<MenuListProps, 'children'> & {
|
||||||
|
children: ReactNode[]
|
||||||
|
};
|
||||||
|
|
||||||
|
const [value] = getValue();
|
||||||
|
const initialOffset = options.indexOf(value) * height;
|
||||||
|
|
||||||
|
return (<List
|
||||||
|
width={'100%'}
|
||||||
|
height={maxHeight}
|
||||||
|
itemCount={children?.length ?? 0}
|
||||||
|
itemSize={height}
|
||||||
|
initialScrollOffset={initialOffset}
|
||||||
|
>
|
||||||
|
{({
|
||||||
|
index,
|
||||||
|
style
|
||||||
|
}) => <div style={style}>{children[index]}</div>}
|
||||||
|
</List>);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NaiveSelect({setSelected}: {
|
||||||
|
setSelected: (value: Option) => void
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
data: options,
|
||||||
|
isLoading,
|
||||||
|
} = useQuery({
|
||||||
|
queryKey: ['obsidian-metadata'],
|
||||||
|
initialData: [],
|
||||||
|
queryFn: async () => {
|
||||||
|
const response = await fetch("http://localhost:9002/metadata")
|
||||||
|
const fullData: any[] = await response.json();
|
||||||
|
|
||||||
|
return R.sortBy(v => -(v.data.backlinks?.length ?? 0), fullData.map(md => ({
|
||||||
|
value: md.relativePath,
|
||||||
|
label: md.fileName,
|
||||||
|
data: md,
|
||||||
|
}) as Option));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onChange = useCallback((value: Option) => {
|
||||||
|
setSelected(value);
|
||||||
|
navigator.clipboard.writeText(`[[${value.label}]]`)
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (<Select
|
||||||
|
classNames={{input: () => 'select-input-wrapper'}}
|
||||||
|
onChange={onChange as any}
|
||||||
|
components={{MenuList}}
|
||||||
|
isDisabled={isLoading}
|
||||||
|
isLoading={isLoading}
|
||||||
|
isClearable={true}
|
||||||
|
options={options}
|
||||||
|
filterOption={createFilter({ignoreAccents: false})}
|
||||||
|
/>)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user