fix(meilisearch): prevent refresh text selection

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-09-24 12:09:41 +08:00
1 parent 42a1949bdc
commit 3899aea866
4 files changed
+38 -15

No files matched your search

@@ -76,7 +76,7 @@ onMounted(() => {
<template>
<div class="h-full flex overflow-hidden">
<!-- Left column: index meta + navigation -->
<nav class="w-44 shrink-0 border-r flex flex-col gap-1 overflow-y-auto p-2">
<nav class="w-44 shrink-0 select-none border-r flex flex-col gap-1 overflow-y-auto p-2">
<div class="px-1 pb-2">
<div class="flex items-center gap-1">
<div class="min-w-0 flex-1 truncate text-sm font-semibold text-foreground" :title="index">{{ index }}</div>
@@ -79,6 +79,7 @@ const deleteConfirmation = ref("");
const secretOpen = ref(false);
const createdSecret = ref("");
const createdUid = ref("");
let loadRequestId = 0;
const hasPrevious = computed(() => offset.value > 0);
const hasNext = computed(() => offset.value + rows.value.length < total.value);
@@ -114,16 +115,20 @@ function toggleColumn(key: MeilisearchKeyColumnKey) {
}
async function load() {
const requestId = ++loadRequestId;
const requestedOffset = offset.value;
loading.value = true;
error.value = "";
try {
const page = await api.meilisearchListKeys(props.connectionId, offset.value, limit);
const page = await api.meilisearchListKeys(props.connectionId, requestedOffset, limit);
if (requestId !== loadRequestId) return;
rows.value = page.results;
total.value = page.total;
} catch (cause: any) {
if (requestId !== loadRequestId) return;
error.value = cause?.message || String(cause);
} finally {
loading.value = false;
if (requestId === loadRequestId) loading.value = false;
}
}
@@ -142,6 +147,7 @@ async function loadIndexes() {
}
function refresh() {
if (loading.value) return;
void load();
void loadIndexes();
}
@@ -265,7 +271,7 @@ onMounted(() => {
</script>
<template>
<div class="flex h-full flex-col overflow-hidden p-4">
<div class="flex h-full select-none flex-col overflow-hidden p-4">
<div class="mb-3 flex items-center justify-between gap-3">
<div>
<h2 class="text-base font-semibold">{{ t("meilisearch.apiKeys") }}</h2>
@@ -27,6 +27,7 @@ const createError = ref("");
const createUid = ref("");
const createPrimaryKey = ref("");
const readOnly = computed(() => connectionIsEffectivelyReadOnly(connectionStore.getConfig(props.connectionId)));
let loadRequestId = 0;
const stats = computed(() => overview.value?.stats.data ?? null);
const cards = computed(() => [
@@ -44,17 +45,26 @@ function sectionLabel(section?: OverviewSection<unknown>): string {
}
async function load() {
const requestId = ++loadRequestId;
loading.value = true;
error.value = "";
try {
overview.value = await api.meilisearchGetSystemOverview(props.connectionId);
const result = await api.meilisearchGetSystemOverview(props.connectionId);
if (requestId !== loadRequestId) return;
overview.value = result;
} catch (cause: any) {
if (requestId !== loadRequestId) return;
error.value = cause?.message || String(cause);
} finally {
loading.value = false;
if (requestId === loadRequestId) loading.value = false;
}
}
function refresh() {
if (loading.value) return;
void load();
}
function openCreate() {
createUid.value = "";
createPrimaryKey.value = "";
@@ -95,7 +105,7 @@ onMounted(() => void load());
</script>
<template>
<div class="h-full overflow-y-auto p-4">
<div class="h-full select-none overflow-y-auto p-4">
<div class="mb-4 flex items-center justify-between">
<div>
<h2 class="text-base font-semibold">{{ t("meilisearch.overview") }}</h2>
@@ -103,7 +113,7 @@ onMounted(() => void load());
</div>
<div class="flex items-center gap-2">
<Button size="sm" variant="outline" :disabled="readOnly" @click="openCreate"><Plus class="mr-1 h-3.5 w-3.5" />{{ t("meilisearch.createIndex") }}</Button>
<Button size="sm" variant="outline" :disabled="loading" @click="load"><RefreshCcw class="mr-1 h-3.5 w-3.5" />{{ t("meilisearch.refresh") }}</Button>
<Button size="sm" variant="outline" :disabled="loading" @click="refresh"><RefreshCcw class="mr-1 h-3.5 w-3.5" />{{ t("meilisearch.refresh") }}</Button>
</div>
</div>
<QueryLoadingState v-if="loading && !overview" class="py-12" />
@@ -180,11 +190,11 @@ onMounted(() => void load());
<div class="grid gap-3 text-xs">
<label class="grid gap-1"
><span class="font-medium">{{ t("meilisearch.uid") }}</span
><Input v-model="createUid" :disabled="createWorking" :placeholder="t('meilisearch.createIndexUidPlaceholder')"
><Input v-model="createUid" class="select-text" :disabled="createWorking" :placeholder="t('meilisearch.createIndexUidPlaceholder')"
/></label>
<label class="grid gap-1"
><span class="font-medium">{{ t("meilisearch.primaryKey") }}</span
><Input v-model="createPrimaryKey" :disabled="createWorking" :placeholder="t('meilisearch.createIndexPrimaryKeyPlaceholder')" /><span class="text-[11px] text-muted-foreground">{{ t("meilisearch.createIndexPrimaryKeyHelp") }}</span></label
><Input v-model="createPrimaryKey" class="select-text" :disabled="createWorking" :placeholder="t('meilisearch.createIndexPrimaryKeyPlaceholder')" /><span class="text-[11px] text-muted-foreground">{{ t("meilisearch.createIndexPrimaryKeyHelp") }}</span></label
>
<ErrorBanner v-if="createError" :message="createError" />
</div>
@@ -59,6 +59,7 @@ const pollingTaskUid = ref<number | null>(null);
const timedOutTaskUid = ref<number | null>(null);
const appliedUserSelector = ref<TaskSelector>({});
let disposed = false;
let loadRequestId = 0;
const currentCursor = computed(() => cursorStack.value[cursorStack.value.length - 1] ?? null);
const hasPrevious = computed(() => cursorStack.value.length > 1);
@@ -149,17 +150,22 @@ const selectorPreview = computed(() => JSON.stringify(pendingSelector.value ?? {
async function load(reset = false) {
if (reset) cursorStack.value = [null];
const requestId = ++loadRequestId;
const selector = normalizedSelector();
const from = currentCursor.value;
loading.value = true;
error.value = "";
try {
const page = await api.meilisearchGetTasks(props.connectionId, { selector: normalizedSelector(), from: currentCursor.value, limit: 20 });
const page = await api.meilisearchGetTasks(props.connectionId, { selector, from, limit: 20 });
if (requestId !== loadRequestId || disposed) return;
rows.value = page.results;
total.value = page.total;
next.value = page.next ?? null;
} catch (cause: any) {
if (requestId !== loadRequestId || disposed) return;
error.value = cause?.message || String(cause);
} finally {
loading.value = false;
if (requestId === loadRequestId) loading.value = false;
}
}
@@ -178,6 +184,7 @@ async function loadIndexes() {
}
function refresh() {
if (loading.value) return;
timedOutTaskUid.value = null;
void load();
void loadIndexes();
@@ -305,7 +312,7 @@ onBeforeUnmount(() => {
</script>
<template>
<div class="flex h-full flex-col overflow-hidden p-4">
<div class="flex h-full select-none flex-col overflow-hidden p-4">
<div class="mb-3 flex items-center justify-between gap-3">
<div>
<h2 class="text-base font-semibold">{{ fixedIndexUid ? t("meilisearch.indexTasks", { index: fixedIndexUid }) : t("meilisearch.tasks") }}</h2>
@@ -317,7 +324,7 @@ onBeforeUnmount(() => {
<div class="mb-3 flex items-center gap-2 overflow-x-auto rounded-lg border bg-muted/20 p-2 text-xs">
<div class="relative min-w-[260px] flex-1">
<Search class="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Input v-model="filters.uids" class="pl-9" :aria-label="t('meilisearch.uidFilter')" :placeholder="t('meilisearch.searchUid')" @keyup.enter="applyFilters" />
<Input v-model="filters.uids" class="pl-9 select-text" :aria-label="t('meilisearch.uidFilter')" :placeholder="t('meilisearch.searchUid')" @keyup.enter="applyFilters" />
</div>
<div v-if="!fixedIndexUid" class="w-[200px] shrink-0">
<Select :model-value="filters.indexUid" :disabled="indexesLoading" @update:model-value="updateIndexFilter">
@@ -422,7 +429,7 @@ onBeforeUnmount(() => {
><DialogHeader
><DialogTitle>{{ t("meilisearch.taskDetails") }} #{{ detail?.uid }}</DialogTitle></DialogHeader
>
<pre v-if="detail" class="max-h-[65vh] overflow-auto rounded-md border bg-muted/30 p-3 text-xs">{{ JSON.stringify(detail, null, 2) }}</pre>
<pre v-if="detail" class="max-h-[65vh] select-text overflow-auto rounded-md border bg-muted/30 p-3 text-xs">{{ JSON.stringify(detail, null, 2) }}</pre>
<DialogFooter
><Button variant="outline" @click="detailOpen = false">{{ t("common.close") }}</Button></DialogFooter
></DialogContent