mirror of
https://github.com/tauri-apps/tauri-search.git
synced 2026-02-04 02:41:20 +01:00
refactor: made createModel return a function that returns ISearchModel; allowing stage based offsets in Meili API
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
"@vueuse/core": "^7.5.5",
|
||||
"@vueuse/head": "^0.7.5",
|
||||
"date-fns": "^2.28.0",
|
||||
"docs-searchbar.js": "^2.1.0",
|
||||
"floating-vue": "^2.0.0-beta.5",
|
||||
"inferred-types": "^0.18.4",
|
||||
"markdown-it-expandable": "^1.0.0",
|
||||
|
||||
1
packages/docs/src/components.d.ts
vendored
1
packages/docs/src/components.d.ts
vendored
@@ -30,6 +30,7 @@ declare module 'vue' {
|
||||
'Ph:info': typeof import('~icons/ph/info')['default']
|
||||
'Ph:linkLight': typeof import('~icons/ph/link-light')['default']
|
||||
README: typeof import('./components/README.md')['default']
|
||||
SearchBar: typeof import('./components/SearchBar.vue')['default']
|
||||
SearchHit: typeof import('./components/SearchHit.vue')['default']
|
||||
SearchIndexes: typeof import('./components/SearchIndexes.vue')['default']
|
||||
SearchResults: typeof import('./components/SearchResults.vue')['default']
|
||||
|
||||
@@ -15,7 +15,7 @@ const indexName = computed(() => props.idx.name as "api" | "repo" | "prose");
|
||||
|
||||
const remove = async () => {
|
||||
// just using ApiModel at random, as we can state which index to remove
|
||||
await ApiModel.query.deleteIndex(indexName.value);
|
||||
await ApiModel().query.deleteIndex(indexName.value);
|
||||
};
|
||||
|
||||
const pushCache = async() => {
|
||||
|
||||
@@ -5,10 +5,10 @@ const props = defineProps({
|
||||
idx: {type: String as PropType<"api" | "prose" | "repo" | "consolidated">, required: true}
|
||||
});
|
||||
const models = {
|
||||
api: ApiModel,
|
||||
prose: ProseModel,
|
||||
repo: RepoModel,
|
||||
consolidated: ConsolidatedModel
|
||||
api: ApiModel(),
|
||||
prose: ProseModel(),
|
||||
repo: RepoModel(),
|
||||
consolidated: ConsolidatedModel()
|
||||
};
|
||||
|
||||
async function addIndex() {
|
||||
|
||||
17
packages/docs/src/components/SearchBar.vue
Normal file
17
packages/docs/src/components/SearchBar.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import docsSearchBar from "docs-searchbar.js";
|
||||
|
||||
docsSearchBar({
|
||||
hostUrl: "http://localhost:7700",
|
||||
apiKey: "",
|
||||
indexUid: "docs",
|
||||
inputSelector: "#search-bar-input",
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<input id="search-bar-input" type="text">
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,18 +1,19 @@
|
||||
export const SERVERS = [
|
||||
{
|
||||
export const SERVERS = {
|
||||
local: {
|
||||
name: "local",
|
||||
url: "http://localhost:7700",
|
||||
},
|
||||
{
|
||||
name: "prod",
|
||||
production: {
|
||||
name: "production",
|
||||
url: "https://search.tauri.studio",
|
||||
token: "",
|
||||
indexes: ["unknown"],
|
||||
search_key: "ea0105f56bb5a2111ed28c7a0c637fc0bed07273f571dc7cb1f73900e44f8e7f",
|
||||
indexes: ["v1_0_0_beta_8"],
|
||||
},
|
||||
{
|
||||
staging: {
|
||||
name: "staging",
|
||||
url: "https://search2.tauri.studio",
|
||||
token: "XZEH8BS90ee09c45215a8421c06857bcbde5c1a6797bdf4859a57a3ac1228a2b81df0994",
|
||||
search_key: "XZEH8BS90ee09c45215a8421c06857bcbde5c1a6797bdf4859a57a3ac1228a2b81df0994",
|
||||
indexes: ["consolidated"],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { acceptHMRUpdate, defineStore } from "pinia";
|
||||
import type { UserModule } from "~/types";
|
||||
import type {
|
||||
import {
|
||||
IMeiliSearchHealth,
|
||||
IMeilisearchIndex,
|
||||
IMeilisearchInterface,
|
||||
IMeilisearchSearchResponse,
|
||||
IMeiliSearchStats,
|
||||
IMeilisearchIndexSettings,
|
||||
ConsolidatedModel,
|
||||
} from "tauri-search";
|
||||
import { ApiModel } from "tauri-search";
|
||||
import { SERVERS } from "~/constants";
|
||||
|
||||
//#region STORE
|
||||
export interface SearchState {
|
||||
@@ -34,6 +36,8 @@ export interface SearchState {
|
||||
searchQuery: string;
|
||||
|
||||
searchResults: { id: string; _idx: string; [key: string]: unknown }[];
|
||||
|
||||
prodResults: { id: string; _idx: string; [key: string]: unknown }[];
|
||||
}
|
||||
|
||||
export const useSearch = defineStore("search", {
|
||||
@@ -47,6 +51,7 @@ export const useSearch = defineStore("search", {
|
||||
searchQuery: "",
|
||||
searchStatus: "not-ready",
|
||||
searchResults: [],
|
||||
prodResults: []
|
||||
} as SearchState),
|
||||
actions: {
|
||||
async search(text: string, force: boolean = false) {
|
||||
@@ -67,6 +72,7 @@ export const useSearch = defineStore("search", {
|
||||
console.time("search");
|
||||
this.$state.searchStatus = "searching";
|
||||
|
||||
// local search
|
||||
const waitFor: Promise<any>[] = [];
|
||||
for (const idx of indexes) {
|
||||
const addIndex = (
|
||||
@@ -92,12 +98,31 @@ export const useSearch = defineStore("search", {
|
||||
console.groupEnd();
|
||||
this.$state.searchResults = hits;
|
||||
|
||||
// prod search
|
||||
const waitForProd: Promise<any>[] = [];
|
||||
for (const idx of SERVERS.production.indexes) {
|
||||
const addIndex = (
|
||||
result: IMeilisearchSearchResponse
|
||||
): IMeilisearchSearchResponse => ({
|
||||
...result,
|
||||
hits: result.hits.map((i) => ({ ...i, _idx: idx })),
|
||||
});
|
||||
|
||||
const model = ConsolidatedModel("production");
|
||||
|
||||
waitForProd.push(
|
||||
model.query.search(text, SERVERS.production.indexes[0]).then(r => addIndex(r))
|
||||
);
|
||||
}
|
||||
|
||||
this.$state.prodResults = await Promise.all(waitForProd);
|
||||
|
||||
return results;
|
||||
},
|
||||
/** updates settings for all active indexes */
|
||||
async updateIndexSettings() {
|
||||
for (const idx of this.indexes.map((i) => i.name)) {
|
||||
const result = (await ApiModel.query.getIndexSettings(
|
||||
const result = (await ApiModel().query.getIndexSettings(
|
||||
idx
|
||||
)) as IMeilisearchIndexSettings<any>;
|
||||
|
||||
@@ -196,7 +221,7 @@ export const install: UserModule = ({ isClient }) => {
|
||||
};
|
||||
|
||||
async function get<T extends {}, U extends {} = never>(url: string, cb?: (r: T) => U) {
|
||||
const res = await fetch(url);
|
||||
const res = await fetch(url, {headers: { "Access-Control-Allow-Origin" : "*"}});
|
||||
if (res.ok) {
|
||||
const result = res.json();
|
||||
|
||||
@@ -211,12 +236,28 @@ async function get<T extends {}, U extends {} = never>(url: string, cb?: (r: T)
|
||||
}
|
||||
}
|
||||
|
||||
function api(base: string = "http://localhost:7700") {
|
||||
async function post<T extends {}, U extends {} = never>(url: string, body: string, cb?: (r: T) => U) {
|
||||
const res = await fetch(url, { method: "post", body, headers: { "Access-Control-Allow-Origin" : "*", "Content-Type": "application/json"}});
|
||||
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>;
|
||||
} else {
|
||||
console.groupCollapsed(`Error with API`);
|
||||
console.info(`Request: GET ${url}`);
|
||||
console.warn(`Error [${res.status}]: ${res.statusText}`);
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
function api(baseUrl: string = "http://localhost:7700") {
|
||||
return {
|
||||
search: (idx: string, text: string) => `${base}/indexes/${idx}/search?q=${text}`,
|
||||
stats: `${base}/stats`,
|
||||
health: `${base}/health`,
|
||||
indexes: `${base}/indexes`,
|
||||
search: (idx: string, text: string) => `${baseUrl}/indexes/${idx}/search?q=${text}`,
|
||||
stats: `${baseUrl}/stats`,
|
||||
health: `${baseUrl}/health`,
|
||||
indexes: `${baseUrl}/indexes`,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# MeiliSearch Search Bar
|
||||
|
||||
|
||||

|
||||
|
||||
## First Considerations
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { onStartTyping } from "@vueuse/core";
|
||||
import { useSearch } from "~/modules/search";
|
||||
import { SERVERS } from "~/constants";
|
||||
const el = ref();
|
||||
const s = useSearch();
|
||||
const searchText = ref(s.$state.searchQuery);
|
||||
const { t } = useI18n();
|
||||
const serverChosen = ref("local");
|
||||
|
||||
debouncedWatch(
|
||||
searchText,
|
||||
@@ -20,9 +18,6 @@ onStartTyping(() => {
|
||||
if (!el.value.active) {el.value.focus();};
|
||||
});
|
||||
|
||||
const changeServer = (_server: {name: string; url: string}) => {
|
||||
//
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -34,17 +29,7 @@ const changeServer = (_server: {name: string; url: string}) => {
|
||||
<div class="grid grid-cols-3 gap-x-4">
|
||||
<div class="left flex flex-grow items-center justify-center">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<div class="mr-2">Server:</div>
|
||||
<div
|
||||
v-for="server in SERVERS"
|
||||
:key="server.name"
|
||||
v-tooltip="{content: server.url}"
|
||||
class="server text-gray-500 font-light"
|
||||
:class="server.name === serverChosen ? `text-gray-800 dark:text-gray-200 border-b-1 cursor-default` : `cursor-pointer`"
|
||||
@click="() => changeServer(server)"
|
||||
>
|
||||
{{server.name}}
|
||||
</div>
|
||||
<!-- -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
2
packages/docs/src/shims.d.ts
vendored
2
packages/docs/src/shims.d.ts
vendored
@@ -14,3 +14,5 @@ declare module "*.vue" {
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
declare module "docs-searchbar.js";
|
||||
@@ -3,7 +3,7 @@ import { ApiModel } from "..";
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const result = await ApiModel.query.currentIndexes();
|
||||
const result = await ApiModel().query.currentIndexes();
|
||||
console.log(`MeiliSearch currently has the following indexes:\n`);
|
||||
for (const r of result) {
|
||||
console.log(` > ${r.name} - created at ${r.createdAt}`);
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
import { ApiModel } from "~/models";
|
||||
|
||||
(async () => {
|
||||
const active = (await ApiModel.query.currentIndexes()).map((i) => i.name);
|
||||
const active = (await ApiModel().query.currentIndexes()).map((i) => i.name);
|
||||
console.log(`- clearing all active indexes: ${active.join(", ")}`);
|
||||
for (const idx of active) {
|
||||
await ApiModel.query.deleteIndex(idx);
|
||||
await ApiModel().query.deleteIndex(idx);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -3,21 +3,18 @@ import { existsSync } from "node:fs";
|
||||
import { REPO_DOCS_CACHE, TS_DOCS_CACHE } from "~/constants";
|
||||
import { ApiModel, ConsolidatedModel, ProseModel, RepoModel } from "~/models";
|
||||
import {
|
||||
proseDocsCacheFile,
|
||||
pushProseDocs,
|
||||
pushRepoDocs,
|
||||
pushTypescriptDocs,
|
||||
refreshProse,
|
||||
refreshRepos,
|
||||
refreshTypescript,
|
||||
} from "~/pipelines";
|
||||
import { pushConsolidatedDocs } from "~/pipelines/pushConsolidatedDocs";
|
||||
import { communicateTaskStatus } from "~/utils/communicateTaskStatus";
|
||||
import { getEnv } from "~/utils/getEnv";
|
||||
|
||||
(async () => {
|
||||
console.log(`- Pushing ALL document caches into local MeiliSearch server`);
|
||||
const idx = (await ApiModel.query.currentIndexes()).map((i) => i.name);
|
||||
const idx = (await ApiModel().query.currentIndexes()).map((i) => i.name);
|
||||
if (idx.length > 0) {
|
||||
console.log(
|
||||
`- found the following indexes setup: ${idx.join(
|
||||
@@ -26,7 +23,7 @@ import { getEnv } from "~/utils/getEnv";
|
||||
);
|
||||
}
|
||||
|
||||
[ApiModel, RepoModel, ProseModel, ConsolidatedModel].forEach(async (model) => {
|
||||
[ApiModel(), RepoModel(), ProseModel(), ConsolidatedModel()].forEach(async (model) => {
|
||||
if (!idx.includes(model.name)) {
|
||||
console.log(
|
||||
`- creating the "${model.name}" index with the following config: ${JSON.stringify(
|
||||
@@ -37,18 +34,13 @@ import { getEnv } from "~/utils/getEnv";
|
||||
}
|
||||
});
|
||||
|
||||
const { repo, branch } = getEnv();
|
||||
if (!existsSync(proseDocsCacheFile(repo, branch))) {
|
||||
await refreshProse(repo, branch);
|
||||
}
|
||||
|
||||
console.log(`- Pushing "prose" documents to MeiliSearch`);
|
||||
const proseTasks = await pushProseDocs(repo, branch);
|
||||
const proseTasks = await pushProseDocs();
|
||||
console.log(
|
||||
`- all ${proseTasks.length} documents were pushed via API; monitoring task status ...`
|
||||
);
|
||||
|
||||
await communicateTaskStatus(ProseModel, proseTasks, { timeout: 45000 });
|
||||
await communicateTaskStatus(ProseModel(), proseTasks, { timeout: 45000 });
|
||||
|
||||
console.log(`- Pushing Repo document cache into MeiliSearch`);
|
||||
|
||||
@@ -70,11 +62,11 @@ import { getEnv } from "~/utils/getEnv";
|
||||
`- Completed pushing all ${docs.length} Repo docs to MeiliSearch; monitoring queue status`
|
||||
);
|
||||
|
||||
await communicateTaskStatus(RepoModel, repoTasks);
|
||||
await communicateTaskStatus(RepoModel(), repoTasks);
|
||||
|
||||
if (!existsSync(TS_DOCS_CACHE)) {
|
||||
console.log(`- The Typescript documents cache wasn't found; creating first`);
|
||||
await refreshTypescript(repo, branch);
|
||||
await refreshTypescript();
|
||||
}
|
||||
|
||||
console.log(`- Starting update process for Typescript API documents`);
|
||||
@@ -94,15 +86,15 @@ import { getEnv } from "~/utils/getEnv";
|
||||
console.log(
|
||||
`- Completed pushing all Typescript docs [${tasks.length}] to MeiliSearch. Now monitoring task progress ...`
|
||||
);
|
||||
communicateTaskStatus(ApiModel, tasks, { timeout: 45000 });
|
||||
communicateTaskStatus(ApiModel(), tasks, { timeout: 45000 });
|
||||
}
|
||||
|
||||
const { tasks: consolidatedTasks } = await pushConsolidatedDocs(repo, branch);
|
||||
const { tasks: consolidatedTasks } = await pushConsolidatedDocs();
|
||||
console.log();
|
||||
console.log(
|
||||
`- all consolidated documents [${tasks.length}] have been pushed to MeiliSearch queue`
|
||||
);
|
||||
|
||||
communicateTaskStatus(ConsolidatedModel, consolidatedTasks, { timeout: 75000 });
|
||||
communicateTaskStatus(ConsolidatedModel(), consolidatedTasks, { timeout: 75000 });
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -12,5 +12,5 @@ import { ConsolidatedModel } from "~/models";
|
||||
`- all consolidated documents [${tasks.length}] have been pushed to MeiliSearch queue`
|
||||
);
|
||||
|
||||
communicateTaskStatus(ConsolidatedModel, tasks, { timeout: 75000 });
|
||||
communicateTaskStatus(ConsolidatedModel(), tasks, { timeout: 75000 });
|
||||
})();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-console */
|
||||
import { pushProseDocs } from "~/pipelines/pushProseDocs";
|
||||
import { pushProseDocs } from "~/pipelines";
|
||||
import { communicateTaskStatus } from "~/utils/communicateTaskStatus";
|
||||
import { ProseModel } from "..";
|
||||
import { ProseModel } from "~/models";
|
||||
|
||||
(async () => {
|
||||
console.log(`- Pushing "prose" documents to MeiliSearch`);
|
||||
@@ -10,5 +10,5 @@ import { ProseModel } from "..";
|
||||
`- all ${tasks.length} documents were pushed via API; monitoring task status ...`
|
||||
);
|
||||
|
||||
await communicateTaskStatus(ProseModel, tasks, { timeout: 75000 });
|
||||
await communicateTaskStatus(ProseModel(), tasks, { timeout: 75000 });
|
||||
})();
|
||||
|
||||
@@ -20,6 +20,6 @@ import { RepoModel } from "..";
|
||||
`- Completed pushing all ${docs.length} Repo docs to MeiliSearch; monitoring queue status`
|
||||
);
|
||||
|
||||
await communicateTaskStatus(RepoModel, tasks);
|
||||
await communicateTaskStatus(RepoModel(), tasks);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -21,6 +21,6 @@ import { communicateTaskStatus } from "~/utils/communicateTaskStatus";
|
||||
console.log(
|
||||
`- Completed pushing all Typescript docs [${tasks.length}] to MeiliSearch. Now monitoring task progress ...`
|
||||
);
|
||||
communicateTaskStatus(ApiModel, tasks, { timeout: 65000 });
|
||||
communicateTaskStatus(ApiModel(), tasks, { timeout: 65000 });
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Stage } from "~/types";
|
||||
|
||||
export const TAURI_BASE_URL = `https://tauri.studio`;
|
||||
export const TAURI_JS_DOCS_URL = `${TAURI_BASE_URL}/docs/api/js`;
|
||||
|
||||
@@ -9,6 +11,12 @@ export const TS_DOCS_CACHE = `src/generated/ast/api/ts-documents.json`;
|
||||
export const TS_AST_CACHE = `src/generated/ast/api/ts-ast.json`;
|
||||
export const RS_DOCS_CACHE = `src/generated/ast/api/rs-documents.json`;
|
||||
|
||||
export const SERVERS: Record<Stage, { url: string; search_key: string }> = {
|
||||
local: { url: "http://localhost:7700", search_key: "" },
|
||||
staging: { url: "https://search2.tauri.studio", search_key: "" },
|
||||
production: { url: "https://search.tauri.studio", search_key: "" },
|
||||
};
|
||||
|
||||
export const REPOS: `${string}/${string}`[] = [
|
||||
"tauri-apps/tauri",
|
||||
"tauri-apps/wry",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,21 +0,0 @@
|
||||
import { IApiModel, IProseModel, IRepoModel } from "~/models";
|
||||
|
||||
/**
|
||||
* Gets the document cache for a given index
|
||||
*/
|
||||
export async function getCache(
|
||||
index: "api" | "prose" | "repo",
|
||||
_options: { repo?: string; branch?: string } = {}
|
||||
): Promise<(IProseModel | IRepoModel | IApiModel)[]> {
|
||||
switch (index) {
|
||||
case "prose":
|
||||
return (await import(`~/generated/ast/prose/tauri_dev/documents.json`))
|
||||
.default as IProseModel[];
|
||||
case "repo":
|
||||
return (await import("~/generated/ast/repo/documents.json"))
|
||||
.default as IRepoModel[];
|
||||
case "api":
|
||||
return (await import("~/generated/ast/api/ts-documents.json"))
|
||||
.default as IApiModel[];
|
||||
}
|
||||
}
|
||||
@@ -23,13 +23,13 @@ export async function pushDocs(
|
||||
const t: Promise<IMeilisearchTaskStatus>[] = [];
|
||||
for (const doc of docs) {
|
||||
if (isProseDocument(doc)) {
|
||||
t.push(ProseModel.query.addOrReplaceDocuments(doc));
|
||||
t.push(ProseModel().query.addOrReplaceDocuments(doc));
|
||||
} else if (isRepoDocument(doc)) {
|
||||
t.push(RepoModel.query.addOrReplaceDocuments(doc));
|
||||
t.push(RepoModel().query.addOrReplaceDocuments(doc));
|
||||
} else if (isApiDocument(doc)) {
|
||||
t.push(ApiModel.query.addOrReplaceDocuments(doc));
|
||||
t.push(ApiModel().query.addOrReplaceDocuments(doc));
|
||||
} else if (isConsolidatedDocument(doc)) {
|
||||
t.push(ConsolidatedModel.query.addOrReplaceDocuments(doc));
|
||||
t.push(ConsolidatedModel().query.addOrReplaceDocuments(doc));
|
||||
}
|
||||
}
|
||||
const tasks = await Promise.all(t);
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import { ProseModel, ApiModel, RepoModel, ConsolidatedModel } from "~/models";
|
||||
|
||||
const models = {
|
||||
api: ApiModel,
|
||||
repo: RepoModel,
|
||||
prose: ProseModel,
|
||||
consolidated: ConsolidatedModel,
|
||||
api: ApiModel(),
|
||||
repo: RepoModel(),
|
||||
prose: ProseModel(),
|
||||
consolidated: ConsolidatedModel(),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -13,7 +13,7 @@ const models = {
|
||||
* present in server.
|
||||
*/
|
||||
export async function createIndexes() {
|
||||
const skipping = (await ProseModel.query.currentIndexes()).map((i) => i.name);
|
||||
const skipping = (await ProseModel().query.currentIndexes()).map((i) => i.name);
|
||||
const created: string[] = [];
|
||||
for (const key of Object.keys(models)) {
|
||||
const model = models[key as keyof typeof models];
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function pushConsolidatedDocs(options: Partial<IEnv> = {}) {
|
||||
const errors: IConsolidatedModel[] = [];
|
||||
const tasks: IMonitoredTask[] = [];
|
||||
for (const doc of docs) {
|
||||
const res = await ConsolidatedModel.query.addOrReplaceDocuments(doc);
|
||||
const res = await ConsolidatedModel().query.addOrReplaceDocuments(doc);
|
||||
if (res.status !== "enqueued") {
|
||||
errors.push(doc);
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ProseModel } from "~/models/ProseModel";
|
||||
import { CacheKind, getCache } from "~/utils/getCache";
|
||||
import { getEnv, IEnv } from "~/utils/getEnv";
|
||||
import { IMonitoredTask } from "..";
|
||||
import { IMonitoredTask } from "~/types";
|
||||
|
||||
/**
|
||||
* Pushes the cached prose documents into the MeiliSearch "prose" index
|
||||
@@ -14,8 +14,8 @@ export async function pushProseDocs(options: Partial<IEnv> = {}) {
|
||||
|
||||
for (const doc of cache) {
|
||||
tasks.push(
|
||||
await ProseModel.query
|
||||
.addOrReplaceDocuments(doc)
|
||||
await ProseModel()
|
||||
.query.addOrReplaceDocuments(doc)
|
||||
.then((i) => ({ docId: doc.id, taskId: i.uid }))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export async function pushRepoDocs(options: Partial<IEnv> = {}) {
|
||||
const tasks: IMonitoredTask[] = [];
|
||||
|
||||
for (const doc of docs) {
|
||||
const res = await RepoModel.query.addOrReplaceDocuments(doc);
|
||||
const res = await RepoModel().query.addOrReplaceDocuments(doc);
|
||||
if (res.status !== "enqueued") {
|
||||
errors.push(doc);
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,7 @@ export async function pushTypescriptDocs(options: Partial<IEnv> = {}) {
|
||||
const tasks: IMonitoredTask[] = [];
|
||||
|
||||
for (const doc of docs) {
|
||||
const res = await ApiModel.query.addOrReplaceDocuments(doc);
|
||||
const res = await ApiModel().query.addOrReplaceDocuments(doc);
|
||||
if (res.status !== "enqueued") {
|
||||
errors.push(doc);
|
||||
} else {
|
||||
|
||||
@@ -10,16 +10,12 @@ import { IApiModel, TypescriptBlock } from "..";
|
||||
* Refreshes the document cache
|
||||
*/
|
||||
export async function refreshTypescript(options: Partial<IEnv> = {}) {
|
||||
const { org, repo, branch } = { ...getEnv(), ...options };
|
||||
const { org, repo, branch, tsAstPath } = { ...getEnv(), ...options };
|
||||
const { cacheFile } = await getCache(CacheKind.typescriptDocs, {
|
||||
...getEnv(),
|
||||
...options,
|
||||
});
|
||||
const ast = (await getRepoFile(
|
||||
`${org}/${repo}`,
|
||||
"docs/api/js/js-api.json",
|
||||
branch
|
||||
)) as TypescriptBlock;
|
||||
const ast = (await getRepoFile(`${org}/${repo}`, tsAstPath, branch)) as TypescriptBlock;
|
||||
|
||||
const simplified = await parseTypescriptAst(ast);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AxiosRequestConfig } from 'axios';
|
||||
import { RankingRule, Wildcard } from '.';
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
import { RankingRule, Wildcard } from ".";
|
||||
import { ApiOptions } from "~/utils/MeiliSearchApi";
|
||||
|
||||
export interface MsIndexStatusResponse {
|
||||
@@ -200,7 +200,7 @@ export interface IMeiliSearchQueryApi<TDoc extends {}> {
|
||||
addOrReplaceDocuments: (doc: TDoc, o?: ApiOptions) => Promise<IMeilisearchAddOrReplace>;
|
||||
addOrUpdateDocuments: (doc: TDoc, o?: ApiOptions) => Promise<IMeilisearchAddOrReplace>;
|
||||
|
||||
search: (text: string) => Promise<IMeilisearchSearchResponse>;
|
||||
search: (text: string, altIndex?: string) => Promise<IMeilisearchSearchResponse>;
|
||||
|
||||
getIndexSettings: (override?: string) => Promise<IMeilisearchIndexSettings<TDoc>>;
|
||||
updateIndexSettings: (
|
||||
|
||||
@@ -2,6 +2,8 @@ import { IndexSynonyms, RankingRule, RankingRulesApi } from "~/types/apis";
|
||||
import { MeiliSearchApi } from "~/utils/MeiliSearchApi";
|
||||
import { IMeiliSearchQueryApi } from ".";
|
||||
|
||||
export type Stage = "production" | "staging" | "local";
|
||||
|
||||
export type MeiliApi = ReturnType<typeof MeiliSearchApi>;
|
||||
|
||||
export type Wildcard<T> = (keyof T)[] | ["*"];
|
||||
|
||||
@@ -13,9 +13,11 @@ import {
|
||||
ISearchConfig,
|
||||
IMeilisearchAllTasks,
|
||||
} from "~/types";
|
||||
import { getEnv } from "./getEnv";
|
||||
|
||||
export interface MeiliSearchOptions {
|
||||
url?: string;
|
||||
search_key?: string;
|
||||
}
|
||||
export type PagingOptions = {
|
||||
limit?: number;
|
||||
@@ -30,6 +32,12 @@ export function MeiliSearchApi<TDoc extends {}>(
|
||||
) {
|
||||
const baseURL = options.url || "http://localhost:7700";
|
||||
const idx = model.name;
|
||||
const { adminKey, searchKey } = getEnv();
|
||||
|
||||
const headers = {
|
||||
"X-Meili-API-Key": options.search_key || adminKey || searchKey || "",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
};
|
||||
|
||||
const call = async <T>(
|
||||
method: "get" | "post" | "put" | "delete",
|
||||
@@ -45,6 +53,7 @@ export function MeiliSearchApi<TDoc extends {}>(
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": options.data ? "application/json" : "application/text",
|
||||
...headers,
|
||||
},
|
||||
},
|
||||
}).catch((err) => {
|
||||
@@ -155,8 +164,8 @@ export function MeiliSearchApi<TDoc extends {}>(
|
||||
post<IMeilisearchAddOrReplace>(`indexes/${idx}/documents`, JSON.stringify(doc), o),
|
||||
addOrUpdateDocuments: (doc: TDoc, o: ApiOptions = {}) =>
|
||||
put<IMeilisearchAddOrReplace>(`indexes/${idx}/documents`, JSON.stringify(doc), o),
|
||||
search: (text: string) =>
|
||||
get<IMeilisearchSearchResponse>(`indexes/${idx}/search?q=${text}`),
|
||||
search: (text: string, altIndex?: string) =>
|
||||
get<IMeilisearchSearchResponse>(`indexes/${altIndex || idx}/search?q=${text}`),
|
||||
getIndexSettings: (override?: string) =>
|
||||
get<IMeilisearchIndexSettings<TDoc>>(`indexes/${override || idx}/settings`),
|
||||
updateIndexSettings: (settings: IMeilisearchIndexSettings<TDoc>) =>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { SERVERS } from "~/constants";
|
||||
import {
|
||||
IndexApi,
|
||||
ISearchConfig,
|
||||
ISearchModel,
|
||||
RankingRule,
|
||||
RankingRulesApi,
|
||||
Stage,
|
||||
} from "~/types";
|
||||
import { getEnv } from "./getEnv";
|
||||
import { MeiliSearchApi } from "./MeiliSearchApi";
|
||||
import { rankingRules } from "./model-api/rankingRules";
|
||||
|
||||
@@ -79,8 +82,7 @@ const modelConfigApi = <TDoc extends {}>(update: (s: PartialModel<TDoc>) => void
|
||||
export const createModel = <TDoc extends Record<string, any>>(
|
||||
/** the MeiliSearch index name which this model is servicing */
|
||||
name: string,
|
||||
cb?: (api: IndexApi<TDoc>) => void,
|
||||
url: string = "http://localhost:7700"
|
||||
cb?: (api: IndexApi<TDoc>) => void
|
||||
) => {
|
||||
const state: ISearchConfig<TDoc> = {
|
||||
name,
|
||||
@@ -99,11 +101,17 @@ export const createModel = <TDoc extends Record<string, any>>(
|
||||
cb(modelConfigApi<TDoc>(updateState));
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
query: MeiliSearchApi<TDoc>(state, { url }),
|
||||
toString() {
|
||||
return `Model(${name}[${state.index.pk}])`;
|
||||
},
|
||||
} as ISearchModel<TDoc>;
|
||||
return (stage?: Stage) => {
|
||||
const url = stage ? SERVERS[stage]?.url : SERVERS[getEnv().stage]?.url;
|
||||
const search_key = stage
|
||||
? SERVERS[stage]?.search_key
|
||||
: SERVERS[getEnv().stage]?.search_key;
|
||||
return {
|
||||
...state,
|
||||
query: MeiliSearchApi<TDoc>(state, { url, search_key }),
|
||||
toString() {
|
||||
return `Model(${name}[${state.index.pk}])`;
|
||||
},
|
||||
} as ISearchModel<TDoc>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { config } from "dotenv";
|
||||
import { Stage } from "~/types";
|
||||
|
||||
export type Stage = "production" | "staging" | "local" | undefined;
|
||||
export interface IEnv {
|
||||
org: string;
|
||||
repo: string;
|
||||
@@ -9,6 +9,14 @@ export interface IEnv {
|
||||
stage: Stage;
|
||||
|
||||
docsPath: string;
|
||||
/**
|
||||
* the full filename path to the AST JSON file exported by
|
||||
*/
|
||||
tsAstPath: string;
|
||||
|
||||
adminKey?: string;
|
||||
searchKey?: string;
|
||||
|
||||
github_token?: string;
|
||||
github_user?: string;
|
||||
force?: boolean;
|
||||
@@ -20,8 +28,13 @@ export function getEnv(): IEnv {
|
||||
org: process.env.ORG || "tauri-apps",
|
||||
repo: process.env.REPO || "tauri-docs",
|
||||
branch: process.env.BRANCH || "dev",
|
||||
stage: process.env.NODE_ENV as Stage,
|
||||
stage: (process.env.NODE_ENV as Stage) || "local",
|
||||
docsPath: process.env.DOCS_PATH || "docs",
|
||||
tsAstPath: process.env.TS_AST_PATH || "docs/api/js/js-api.json",
|
||||
|
||||
adminKey: process.env.ADMIN_KEY || undefined,
|
||||
searchKey: process.env.SEARCH_KEY || undefined,
|
||||
|
||||
github_token: process.env.GH_TOKEN || process.env.GITHUB_TOKEN || undefined,
|
||||
github_user: process.env.GH_USER || undefined,
|
||||
force: process.env.FORCE ? Boolean(process.env.FORCE) : false,
|
||||
|
||||
@@ -16,18 +16,18 @@ describe("createModel()", () => {
|
||||
.filterable("lastUpdated")
|
||||
);
|
||||
|
||||
expect(m.index.displayed).toContain("title");
|
||||
expect(m.index.displayed).toContain("section");
|
||||
expect(m.index.displayed).not.toContain("lastUpdated");
|
||||
expect(m().index.displayed).toContain("title");
|
||||
expect(m().index.displayed).toContain("section");
|
||||
expect(m().index.displayed).not.toContain("lastUpdated");
|
||||
|
||||
expect(m.index.sortable).toContain("section");
|
||||
expect(m.index.filterable).toContain("lastUpdated");
|
||||
expect(m().index.sortable).toContain("section");
|
||||
expect(m().index.filterable).toContain("lastUpdated");
|
||||
});
|
||||
|
||||
it("toString() produces a clear and concise indication of what model it is", async () => {
|
||||
const m = createModel<Model>("foobar");
|
||||
expect(m.toString()).toContain("Model");
|
||||
expect(m.toString()).toContain("foobar");
|
||||
expect(m().toString()).toContain("Model");
|
||||
expect(m().toString()).toContain("foobar");
|
||||
});
|
||||
|
||||
it("model can set ranking rules to any order they like", () => {
|
||||
@@ -35,8 +35,10 @@ describe("createModel()", () => {
|
||||
m.rankingRules((r) => r.attribute().exactness().words())
|
||||
);
|
||||
expect(
|
||||
m.index.rules,
|
||||
`the ranking rules were expected to be [attribute, exactness, words] but instead were ${m.index.rules}`
|
||||
m().index.rules,
|
||||
`the ranking rules were expected to be [attribute, exactness, words] but instead were ${
|
||||
m().index.rules
|
||||
}`
|
||||
).toEqual(["attribute", "exactness", "words"]);
|
||||
});
|
||||
});
|
||||
|
||||
74
pnpm-lock.yaml
generated
74
pnpm-lock.yaml
generated
@@ -26,6 +26,7 @@ importers:
|
||||
critters: ^0.0.16
|
||||
cross-env: ^7.0.3
|
||||
date-fns: ^2.28.0
|
||||
docs-searchbar.js: ^2.1.0
|
||||
dotenv: ^14.3.2
|
||||
eslint: ^8.8.0
|
||||
eslint-plugin-cypress: ^2.12.1
|
||||
@@ -63,6 +64,7 @@ importers:
|
||||
'@vueuse/core': 7.5.5_vue@3.2.29
|
||||
'@vueuse/head': 0.7.5_vue@3.2.29
|
||||
date-fns: 2.28.0
|
||||
docs-searchbar.js: 2.1.0
|
||||
floating-vue: 2.0.0-beta.5_vue@3.2.29
|
||||
inferred-types: 0.18.4
|
||||
markdown-it-expandable: 1.0.0_markdown-it@12.3.2
|
||||
@@ -2435,6 +2437,12 @@ packages:
|
||||
engines: {node: '>= 4.0.0'}
|
||||
dev: true
|
||||
|
||||
/autocomplete.js/0.38.1:
|
||||
resolution: {integrity: sha512-6pSJzuRMY3pqpozt+SXThl2DmJfma8Bi3SVFbZHS0PW/N72bOUv+Db0jAh2cWOhTsA4X+GNmKvIl8wExJTnN9w==}
|
||||
dependencies:
|
||||
immediate: 3.3.0
|
||||
dev: false
|
||||
|
||||
/available-typed-arrays/1.0.5:
|
||||
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2851,6 +2859,14 @@ packages:
|
||||
cross-spawn: 7.0.3
|
||||
dev: true
|
||||
|
||||
/cross-fetch/3.1.5:
|
||||
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
|
||||
dependencies:
|
||||
node-fetch: 2.6.7
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/cross-spawn/6.0.5:
|
||||
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
|
||||
engines: {node: '>=4.8'}
|
||||
@@ -3028,6 +3044,17 @@ packages:
|
||||
resolution: {integrity: sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=}
|
||||
dev: false
|
||||
|
||||
/docs-searchbar.js/2.1.0:
|
||||
resolution: {integrity: sha512-lHDeJelI8NrtmTrX38rZN86BQ6pxL8QzlfMqR6dHhfAXdrpDX2nNRT51sNSg6nIuI0ubpCVyJMyncedglmK/FA==}
|
||||
dependencies:
|
||||
autocomplete.js: 0.38.1
|
||||
meilisearch: 0.24.0
|
||||
to-factory: 1.0.0
|
||||
zepto: 1.2.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/doctrine/2.1.0:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -4511,6 +4538,10 @@ packages:
|
||||
engines: {node: '>= 4'}
|
||||
dev: true
|
||||
|
||||
/immediate/3.3.0:
|
||||
resolution: {integrity: sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==}
|
||||
dev: false
|
||||
|
||||
/import-fresh/3.3.0:
|
||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -5139,6 +5170,14 @@ packages:
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: true
|
||||
|
||||
/meilisearch/0.24.0:
|
||||
resolution: {integrity: sha512-qME1dsHZePBQi8qFdhbilcFzaL+oZJgUuls+FZ23hHpdhJI+iMFSmjjcfsxq5hdg2qczbCXv7yAo3Sh8xgfkgA==}
|
||||
dependencies:
|
||||
cross-fetch: 3.1.5
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/memorystream/0.3.1:
|
||||
resolution: {integrity: sha1-htcJCzDORV1j+64S3aUaR93K+bI=}
|
||||
engines: {node: '>= 0.10.0'}
|
||||
@@ -5284,6 +5323,18 @@ packages:
|
||||
lower-case: 1.1.4
|
||||
dev: true
|
||||
|
||||
/node-fetch/2.6.7:
|
||||
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
dev: false
|
||||
|
||||
/node-releases/2.0.1:
|
||||
resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==}
|
||||
dev: true
|
||||
@@ -6553,6 +6604,10 @@ packages:
|
||||
engines: {node: '>=14.0.0'}
|
||||
dev: true
|
||||
|
||||
/to-factory/1.0.0:
|
||||
resolution: {integrity: sha1-hzivi9lxIK0dQEeXKtpVY7+UebE=}
|
||||
dev: false
|
||||
|
||||
/to-fast-properties/2.0.0:
|
||||
resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=}
|
||||
engines: {node: '>=4'}
|
||||
@@ -6587,6 +6642,10 @@ packages:
|
||||
universalify: 0.1.2
|
||||
dev: true
|
||||
|
||||
/tr46/0.0.3:
|
||||
resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=}
|
||||
dev: false
|
||||
|
||||
/tr46/1.0.1:
|
||||
resolution: {integrity: sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=}
|
||||
dependencies:
|
||||
@@ -7454,6 +7513,10 @@ packages:
|
||||
minimalistic-assert: 1.0.1
|
||||
dev: true
|
||||
|
||||
/webidl-conversions/3.0.1:
|
||||
resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=}
|
||||
dev: false
|
||||
|
||||
/webidl-conversions/4.0.2:
|
||||
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
||||
dev: true
|
||||
@@ -7487,6 +7550,13 @@ packages:
|
||||
webidl-conversions: 7.0.0
|
||||
dev: true
|
||||
|
||||
/whatwg-url/5.0.0:
|
||||
resolution: {integrity: sha1-lmRU6HZUYuN2RNNib2dCzotwll0=}
|
||||
dependencies:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
dev: false
|
||||
|
||||
/whatwg-url/7.1.0:
|
||||
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
|
||||
dependencies:
|
||||
@@ -7808,3 +7878,7 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/zepto/1.2.0:
|
||||
resolution: {integrity: sha1-4Se9nmb9hGvl6rSME5SIL3wOT5g=}
|
||||
dev: false
|
||||
|
||||
Reference in New Issue
Block a user