chore(docs): 2nd round of de-linting once React type bleed-in was removed

This commit is contained in:
Ken Snyder
2022-02-01 12:20:26 -08:00
parent 1742280b3f
commit 6377eb0a08
5 changed files with 106 additions and 161 deletions

View File

@@ -3,11 +3,11 @@
import { useSearch } from "~/modules/search";
import { format } from "date-fns";
import { PropType } from "vue";
import { MeiliSearchInterface } from "~/types/meilisearch";
import { ApiModel } from "tauri-search";
import type { IMeilisearchInterface} from "tauri-search";
const s = useSearch();
const props = defineProps({
idx: {type: Object as PropType<MeiliSearchInterface>, required: true},
idx: {type: Object as PropType<IMeilisearchInterface>, required: true},
unknown: {type: Boolean, default: false, required: false}
});
const settings = computed(() => s.$state.indexSettings[props.idx.name]);

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { PropType } from "vue";
import { GenericDoc } from "~/types/meilisearch";
import { GenericDoc } from "tauri-search";
const props = defineProps({
document: {
@@ -84,7 +84,7 @@ const details = () => {
{{apiKind}}
</div>
<div class="flex px-1 hover:text-green-600 hover:font-bold ">
<a :href="doc.url" target="_new">
<a :href="(doc.url as string)" target="_new">
<ph:link-light class="flex" />
</a>
</div>

View File

@@ -1,12 +1,13 @@
<script setup lang="ts">
import { Keys } from "inferred-types";
import { useSearch } from "~/modules/search";
import type { IMeilisearchInterface} from "tauri-search";
const s = useSearch();
/**
* this allows all expected indexes to be shown and in a sensible order
*/
const knownIndexes = ["api", "prose", "repo", "consolidated"];
const knownIndexes = ["api", "prose", "repo", "consolidated"] as const;
/** the name of the indexes current known by MeiliSearch */
const currentIndexes = computed(() => s.$state.indexes.map(i => i.name));
@@ -14,7 +15,7 @@ const currentIndexes = computed(() => s.$state.indexes.map(i => i.name));
* we do want to see ANY index that exists though too
*/
const unknownIndexes = computed(() => {
return s.$state.indexes.filter(i => !knownIndexes.includes(i.name));
return s.$state.indexes.filter(i => !knownIndexes.includes(i.name as Keys<typeof knownIndexes>));
});
const indexStateOptions = ["consolidated", "individual", "bespoke"] as const;
@@ -80,7 +81,7 @@ const optionStyle = (opt: IndexState) => computed(() => {
</div>
<template v-for="idx in knownIndexes" :key="idx">
<current-index v-if="currentIndexes.includes(idx)" :idx="s.$state.indexes.find(i => i.name === idx)"/>
<current-index v-if="currentIndexes.includes(idx)" :idx="((s.indexes.find(i => i.name === idx))as IMeilisearchInterface)"/>
<missing-index v-else :idx="idx" />
</template>
<template v-for="idx in unknownIndexes" :key="idx">

View File

@@ -2,9 +2,15 @@
/* eslint-disable no-use-before-define */
import { acceptHMRUpdate, defineStore } from "pinia";
import type { UserModule } from "~/types";
import { MeiliSearchHealth, MeiliSearchIndex, MeiliSearchInterface, MeiliSearchResponse, MeiliSearchStats } from "~/types/meilisearch";
import { ApiModel, IMeilisearchIndexSettings } from "tauri-search";
import type {
IMeiliSearchHealth,
IMeilisearchIndex,
IMeilisearchInterface,
IMeilisearchSearchResponse,
IMeiliSearchStats,
IMeilisearchIndexSettings,
} from "tauri-search";
import { ApiModel } from "tauri-search";
//#region STORE
export interface SearchState {
@@ -12,13 +18,13 @@ export interface SearchState {
health: boolean | "initializing";
/** the indexes which are defined on MeiliSearch */
indexes: MeiliSearchInterface[];
indexes: IMeilisearchInterface[];
/** indexes to use when searching */
searchUsing: string[];
/** database stats for MeiliSearch */
stats?: MeiliSearchStats;
stats?: IMeiliSearchStats;
/** index settings */
indexSettings: Record<string, IMeilisearchIndexSettings<any>>;
@@ -27,28 +33,29 @@ export interface SearchState {
searchQuery: string;
searchResults: {id: string; _idx: string; [key: string]: unknown}[];
searchResults: { id: string; _idx: string; [key: string]: unknown }[];
}
export const useSearch = defineStore("search", ({
state: () => ({
health: "initializing",
indexes: [],
indexSettings: {},
searchUsing: ["consolidated"],
stats: undefined,
searchQuery: "",
searchStatus: "not-ready",
searchResults: [],
}) as SearchState,
export const useSearch = defineStore("search", {
state: () =>
({
health: "initializing",
indexes: [],
indexSettings: {},
searchUsing: ["consolidated"],
stats: undefined,
searchQuery: "",
searchStatus: "not-ready",
searchResults: [],
} as SearchState),
actions: {
async search(text: string, force: boolean = false) {
if(text.trim()==="") {
if (text.trim() === "") {
this.$state.searchResults = [];
this.$state.searchQuery = text.trim();
return;
}
if(text.trim() === this.searchQuery.trim() && !force) {
if (text.trim() === this.searchQuery.trim() && !force) {
// no change
return;
} else {
@@ -59,30 +66,28 @@ export const useSearch = defineStore("search", ({
console.info(`search on ${indexes.length} indexes`, indexes);
console.time("search");
this.$state.searchStatus = "searching";
const waitFor: Promise<any>[] = [];
for (const idx of indexes) {
const addIndex =
(result: MeiliSearchResponse): MeiliSearchResponse => ({
...result,
hits: result.hits.map(i =>
({...i, _idx: idx})
)
});
const addIndex = (
result: IMeilisearchSearchResponse
): IMeilisearchSearchResponse => ({
...result,
hits: result.hits.map((i) => ({ ...i, _idx: idx })),
});
waitFor.push(
get<
MeiliSearchResponse,
MeiliSearchResponse
>
(api().search(idx,text), addIndex)
get<IMeilisearchSearchResponse, IMeilisearchSearchResponse>(
api().search(idx, text),
addIndex
)
);
}
const results = await Promise.all(waitFor);
this.$state.searchStatus = "ready";
console.timeEnd("search");
const hits = results.flatMap(i => i.hits);
const hits = results.flatMap((i) => i.hits);
console.info(`found ${hits.length} documents`);
console.groupEnd();
this.$state.searchResults = hits;
@@ -91,15 +96,17 @@ export const useSearch = defineStore("search", ({
},
/** updates settings for all active indexes */
async updateIndexSettings() {
for (const idx of this.indexes.map(i => i.name)) {
const result = await ApiModel.query.getIndexSettings(idx) as IMeilisearchIndexSettings<any>;
this.$state.indexSettings = {...this.$state.indexSettings, [idx]:result} ;
for (const idx of this.indexes.map((i) => i.name)) {
const result = (await ApiModel.query.getIndexSettings(
idx
)) as IMeilisearchIndexSettings<any>;
this.$state.indexSettings = { ...this.$state.indexSettings, [idx]: result };
}
},
toggleUseOfIndex(idx: string) {
if(this.$state.searchUsing.includes(idx)) {
this.$state.searchUsing = this.$state.searchUsing.filter(i => i !== idx);
if (this.$state.searchUsing.includes(idx)) {
this.$state.searchUsing = this.$state.searchUsing.filter((i) => i !== idx);
this.search(this.searchQuery, true);
this.updateIndexSettings();
} else {
@@ -113,36 +120,37 @@ export const useSearch = defineStore("search", ({
this.search(this.searchQuery, true);
this.updateIndexSettings();
},
statsUpdate(s: MeiliSearchStats) {
statsUpdate(s: IMeiliSearchStats) {
this.$state.stats = s;
},
healthUpdate(h: boolean) {
this.$state.health = h;
},
indexUpdate(idx: MeiliSearchInterface[]) {
const current = this.$state.indexes.map(i => i.name);
const newList = idx.map(i => i.name);
if(current.length === newList.length && newList.every(i => current.includes(i))) {
indexUpdate(idx: IMeilisearchInterface[]) {
const current = this.$state.indexes.map((i) => i.name);
const newList = idx.map((i) => i.name);
if (
current.length === newList.length &&
newList.every((i) => current.includes(i))
) {
return;
}
this.$state.indexes = idx;
}
},
},
getters: {
indexIsUsed: (state) => (idx: string) => state.searchUsing.includes(idx),
dbSize: (state) => state.stats?.databaseSize || 0,
indexInfo: (state) => (idx: string): MeiliSearchIndex | undefined => state.stats?.indexes[idx]
}
}));
dbSize: (state) => state.stats?.databaseSize || 0,
indexInfo:
(state) =>
(idx: string): IMeilisearchIndex | undefined =>
state.stats?.indexes[idx],
},
});
if (import.meta.hot) {
import.meta.hot.accept(
acceptHMRUpdate(
useSearch,
import.meta.hot)
);
import.meta.hot.accept(acceptHMRUpdate(useSearch, import.meta.hot));
}
//#endregion STORE
@@ -157,43 +165,44 @@ export const install: UserModule = ({ isClient }) => {
if (isClient) {
const s = useSearch();
const { pause, resume, isActive } = useIntervalFn(async() => {
s.indexUpdate(await indexes());
s.statsUpdate(await stats());
}, 2000, {immediate: true});
const { pause, resume, isActive } = useIntervalFn(
async () => {
s.indexUpdate(await indexes());
s.statsUpdate(await stats());
},
2000,
{ immediate: true }
);
// check health of MeiliSearch
useIntervalFn(async() => {
const h = await health();
s.healthUpdate(h);
s.$state.searchStatus = !h ? "not-ready": "ready";
useIntervalFn(
async () => {
const h = await health();
s.healthUpdate(h);
s.$state.searchStatus = !h ? "not-ready" : "ready";
if(h === true) {
s.updateIndexSettings();
if(!isActive.value) {
resume();
if (h === true) {
s.updateIndexSettings();
if (!isActive.value) {
resume();
}
}
};
if(h === false && isActive.value) pause();
}, 1000, {immediate: true});
if (h === false && isActive.value) pause();
},
1000,
{ immediate: true }
);
}
};
async function get<T extends {}, U extends {} = never>(
url: string,
cb?: ((r: T) => U)
) {
async function get<T extends {}, U extends {} = never>(url: string, cb?: (r: T) => U) {
const res = await fetch(url);
if(res.ok) {
if (res.ok) {
const result = res.json();
return (
cb
? result.then(r => cb(r)) as Promise<U>
: result as Promise<T>
) as never extends U ? Promise<T> : Promise<U>;
return (
cb ? (result.then((r) => cb(r)) as Promise<U>) : (result as Promise<T>)
) as never extends U ? Promise<T> : Promise<U>;
} else {
console.groupCollapsed(`Error with API`);
console.info(`Request: GET ${url}`);
@@ -207,15 +216,13 @@ function api(base: string = "http://localhost:7700") {
search: (idx: string, text: string) => `${base}/indexes/${idx}/search?q=${text}`,
stats: `${base}/stats`,
health: `${base}/health`,
indexes: `${base}/indexes`
indexes: `${base}/indexes`,
};
}
async function health(): Promise<boolean> {
try {
const response = await (
await fetch(api().health)
).json() as MeiliSearchHealth;
const response = (await (await fetch(api().health)).json()) as IMeiliSearchHealth;
return response.status === "available";
} catch {
return false;
@@ -223,15 +230,11 @@ async function health(): Promise<boolean> {
}
async function indexes() {
return await (
await fetch(api().indexes)
).json() as MeiliSearchInterface[];
return (await (await fetch(api().indexes)).json()) as IMeilisearchInterface[];
}
async function stats() {
return await (
await fetch(api().stats)
).json() as MeiliSearchStats;
return (await (await fetch(api().stats)).json()) as IMeiliSearchStats;
}
//#endregion
//#endregion

View File

@@ -1,59 +0,0 @@
export interface MeiliSearchHealth {
/** the current health status; is "available" when healthy */
status: string;
}
export type datetime = string;
export interface MeiliSearchInterface {
uid: string;
name: string;
/** datetime string (aka., 2022-01-23T22:47:42.745395044Z) */
createdAt: datetime;
/** datetime string (aka., 2022-01-23T22:47:42.745395044Z) */
updatedAt: datetime;
/**
* the property serving as the primary key for the index,
* use `id` unless there's a good reason not to
*/
primaryKey: string;
}
export interface MeiliSearchIndex {
numberOfDocuments: number;
isIndexing: false;
fieldDistribution: Record<string, any>;
}
/**
* Global MeiliSearch Stats
*/
export interface MeiliSearchStats {
databaseSize: number;
lastUpdate: datetime;
indexes: Record<string, MeiliSearchIndex>;
}
export type GenericDoc = {id: string; _idx?: string; [key:string]: unknown};
export interface MeiliSearchResponse<T extends {} = GenericDoc> {
hits: T[];
limit: number;
nbHits: number;
offset: number;
processingTimeMs: number;
query: string;
}
/**
* The search results but _with_ the index used inserted on
* each "hit"
*/
export type WithIndex<T extends MeiliSearchResponse> =
Omit<T, "hits"> & { hits:
{
[K in keyof T["hits"]]: T["hits"][K] & Record<K, {_idx: string}>
}[number];
};