fix(oracle): apply visible schema filter
This commit is contained in:
1 parent
1ded7e8332
commit
b2edf7cad6
20 files changed
+469
-102
No files matched your search
@@ -36,7 +36,7 @@ import { prestoSqlBuiltinDriverPaths } from "@/lib/prestoSqlBuiltinDriver";
|
||||
import { SQLITE_DATABASE_FILE_EXTENSIONS } from "@/lib/databaseFileDetection";
|
||||
import { ArrowLeft, ArrowDown, ArrowUp, CheckSquare, ChevronRight, CircleHelp, Copy, ExternalLink, FilePlus2, FolderOpen, GripVertical, Grid3X3, KeyRound, Link2, List, ListFilter, Loader2, Pipette, Plus, Search, ShieldCheck, Square, Trash2 } from "@lucide/vue";
|
||||
import { buildDraftVisibleDatabasesConnectionId, connectionCanChooseVisibleDatabases, initialVisibleDatabaseSelection, visibleDatabaseSelectionIsStale } from "@/lib/connectionVisibleDatabases";
|
||||
import { canSaveVisibleDatabaseSelection, filterDatabaseNamesForConnection, isSystemDatabaseName, normalizeVisibleDatabaseSelection, buildDraftVisibleSchemasConnectionId } from "@/lib/visibleDatabases";
|
||||
import { canSaveVisibleDatabaseSelection, filterDatabaseNamesForConnection, isSystemDatabaseName, normalizeVisibleDatabaseSelection, buildDraftVisibleSchemasConnectionId, normalizeVisibleSchemaSelection } from "@/lib/visibleDatabases";
|
||||
import { isSchemaAware } from "@/lib/databaseFeatureSupport";
|
||||
import VisibleSchemasDialog from "@/components/sidebar/VisibleSchemasDialog.vue";
|
||||
|
||||
@@ -1281,6 +1281,7 @@ const canUseTransportLayers = computed(() => form.value.db_type !== "sqlite" &&
|
||||
const shouldShowAgentDriverInstallHint = computed(() => showAgentDriverInstallHint(form.value.db_type, agentDrivers.value, form.value.driver_profile));
|
||||
const h2DriverMissing = computed(() => form.value.db_type === "h2" && isH2FileMode.value && agentDrivers.value.find((d) => d.db_type === "h2")?.installed !== true);
|
||||
const canChooseVisibleDatabases = computed(() => connectionCanChooseVisibleDatabases(form.value));
|
||||
const visibleFilterUsesSchemas = computed(() => form.value.db_type === "oracle" || form.value.db_type === "dameng");
|
||||
const hasVisibleDatabaseFilter = computed(() => Array.isArray(form.value.visible_databases));
|
||||
const visibleDatabaseSummary = computed(() => {
|
||||
const configured = form.value.visible_databases;
|
||||
@@ -1288,6 +1289,7 @@ const visibleDatabaseSummary = computed(() => {
|
||||
return t("visibleDatabases.selectedCount", { selected: configured.length, total: visibleDatabaseNames.value.length });
|
||||
});
|
||||
const listedVisibleDatabaseNames = computed(() => {
|
||||
if (visibleFilterUsesSchemas.value) return visibleDatabaseNames.value;
|
||||
const connection = connectionConfigSnapshotForVisibleDatabases();
|
||||
if (visibleDatabaseShowSystem.value) return visibleDatabaseNames.value;
|
||||
return filterDatabaseNamesForConnection(visibleDatabaseNames.value, connection);
|
||||
@@ -1301,6 +1303,7 @@ const visibleDatabaseSelectedCount = computed(() => visibleDatabaseSelection.val
|
||||
const visibleDatabaseTotalCount = computed(() => listedVisibleDatabaseNames.value.length);
|
||||
const visibleDatabaseCanSave = computed(() => canSaveVisibleDatabaseSelection([...visibleDatabaseSelection.value]));
|
||||
const visibleDatabaseHasSystemDatabases = computed(() => {
|
||||
if (visibleFilterUsesSchemas.value) return false;
|
||||
const connection = connectionConfigSnapshotForVisibleDatabases();
|
||||
return visibleDatabaseNames.value.some((database) => isSystemDatabaseName(connection.db_type, database));
|
||||
});
|
||||
@@ -1310,12 +1313,32 @@ const hasVisibleSchemaFilter = computed(() => {
|
||||
const key = visibleSchemasDatabaseKey.value;
|
||||
return Array.isArray(form.value.visible_schemas?.[key]);
|
||||
});
|
||||
const visibleSchemaObjectSelection = computed(() => {
|
||||
const configured = form.value.visible_schemas?.[visibleSchemasDatabaseKey.value];
|
||||
if (Array.isArray(configured)) return configured;
|
||||
if (visibleFilterUsesSchemas.value && Array.isArray(form.value.visible_databases)) return form.value.visible_databases;
|
||||
return undefined;
|
||||
});
|
||||
const visibleSchemaSummary = computed(() => {
|
||||
const key = visibleSchemasDatabaseKey.value;
|
||||
const configured = form.value.visible_schemas?.[key];
|
||||
if (!configured?.length) return t("visibleSchemas.showAll");
|
||||
return t("visibleSchemas.selectedCount", { selected: configured.length, total: visibleSchemaNames.value.length });
|
||||
});
|
||||
const hasVisibleObjectFilter = computed(() => (visibleFilterUsesSchemas.value ? Array.isArray(visibleSchemaObjectSelection.value) : hasVisibleDatabaseFilter.value));
|
||||
const visibleObjectSummary = computed(() => {
|
||||
if (!visibleFilterUsesSchemas.value) return visibleDatabaseSummary.value;
|
||||
const configured = visibleSchemaObjectSelection.value;
|
||||
if (!Array.isArray(configured)) return t("visibleSchemas.showAll");
|
||||
return t("visibleSchemas.selectedCount", { selected: configured.length, total: visibleDatabaseNames.value.length });
|
||||
});
|
||||
const visibleObjectTitleKey = computed(() => (visibleFilterUsesSchemas.value ? "visibleSchemas.title" : "visibleDatabases.title"));
|
||||
const visibleObjectDescriptionKey = computed(() => (visibleFilterUsesSchemas.value ? "visibleSchemas.description" : "visibleDatabases.description"));
|
||||
const visibleObjectSearchPlaceholderKey = computed(() => (visibleFilterUsesSchemas.value ? "visibleSchemas.searchPlaceholder" : "visibleDatabases.searchPlaceholder"));
|
||||
const visibleObjectSelectedCountKey = computed(() => (visibleFilterUsesSchemas.value ? "visibleSchemas.selectedCount" : "visibleDatabases.selectedCount"));
|
||||
const visibleObjectEmptySelectionKey = computed(() => (visibleFilterUsesSchemas.value ? "visibleSchemas.emptySelection" : "visibleDatabases.emptySelection"));
|
||||
const visibleObjectLoadFailedKey = computed(() => (visibleFilterUsesSchemas.value ? "visibleSchemas.loadFailed" : "visibleDatabases.loadFailed"));
|
||||
const visibleObjectSaveKey = computed(() => (visibleFilterUsesSchemas.value ? "visibleSchemas.save" : "visibleDatabases.save"));
|
||||
const testResultMessage = computed(() => {
|
||||
if (!testResult.value) return "";
|
||||
return testResult.value.ok ? t("connection.testSuccess") : testResult.value.message;
|
||||
@@ -1626,7 +1649,11 @@ function connectionConfigForSubmit(id: string): ConnectionConfig {
|
||||
delete legacy.proxy_port;
|
||||
delete legacy.proxy_username;
|
||||
delete legacy.proxy_password;
|
||||
config.visible_databases = Array.isArray(config.visible_databases) && config.visible_databases.length > 0 ? config.visible_databases : undefined;
|
||||
if (config.db_type === "oracle" || config.db_type === "dameng") {
|
||||
config.visible_databases = undefined;
|
||||
} else {
|
||||
config.visible_databases = Array.isArray(config.visible_databases) && config.visible_databases.length > 0 ? config.visible_databases : undefined;
|
||||
}
|
||||
if (config.visible_schemas && Object.keys(config.visible_schemas).length === 0) config.visible_schemas = undefined;
|
||||
return config as ConnectionConfig;
|
||||
}
|
||||
@@ -1894,9 +1921,10 @@ async function openVisibleDatabasesPicker() {
|
||||
await api.connectDb(draftConfig);
|
||||
const names = await loadVisibleDatabaseNames(draftId, draftConfig);
|
||||
visibleDatabaseNames.value = names;
|
||||
const initialSelection = initialVisibleDatabaseSelection(names, form.value.visible_databases, draftConfig);
|
||||
const configuredSchemas = visibleSchemaObjectSelection.value;
|
||||
const initialSelection = visibleFilterUsesSchemas.value ? (Array.isArray(configuredSchemas) ? normalizeVisibleSchemaSelection(configuredSchemas, names) : names) : initialVisibleDatabaseSelection(names, form.value.visible_databases, draftConfig);
|
||||
visibleDatabaseSelection.value = new Set(initialSelection);
|
||||
visibleDatabaseShowSystem.value = initialSelection.some((database) => isSystemDatabaseName(draftConfig.db_type, database));
|
||||
visibleDatabaseShowSystem.value = !visibleFilterUsesSchemas.value && initialSelection.some((database) => isSystemDatabaseName(draftConfig.db_type, database));
|
||||
showVisibleDatabasesDialog.value = true;
|
||||
} catch (e: any) {
|
||||
visibleDatabaseNames.value = [];
|
||||
@@ -1938,7 +1966,12 @@ function clearVisibleDatabaseSelection() {
|
||||
}
|
||||
|
||||
function showAllVisibleDatabases() {
|
||||
form.value.visible_databases = undefined;
|
||||
if (visibleFilterUsesSchemas.value) {
|
||||
handleDraftSchemasShowAll();
|
||||
form.value.visible_databases = undefined;
|
||||
} else {
|
||||
form.value.visible_databases = undefined;
|
||||
}
|
||||
visibleDatabaseSelection.value = new Set();
|
||||
visibleDatabaseNames.value = [];
|
||||
showVisibleDatabasesDialog.value = false;
|
||||
@@ -1946,7 +1979,16 @@ function showAllVisibleDatabases() {
|
||||
|
||||
function saveVisibleDatabaseSelection() {
|
||||
if (!visibleDatabaseCanSave.value) return;
|
||||
form.value.visible_databases = normalizeVisibleDatabaseSelection([...visibleDatabaseSelection.value], visibleDatabaseNames.value);
|
||||
if (visibleFilterUsesSchemas.value) {
|
||||
const key = visibleSchemasDatabaseKey.value;
|
||||
form.value.visible_databases = undefined;
|
||||
form.value.visible_schemas = {
|
||||
...form.value.visible_schemas,
|
||||
[key]: normalizeVisibleSchemaSelection([...visibleDatabaseSelection.value], visibleDatabaseNames.value),
|
||||
};
|
||||
} else {
|
||||
form.value.visible_databases = normalizeVisibleDatabaseSelection([...visibleDatabaseSelection.value], visibleDatabaseNames.value);
|
||||
}
|
||||
showVisibleDatabasesDialog.value = false;
|
||||
}
|
||||
|
||||
@@ -1989,7 +2031,7 @@ async function openVisibleSchemasPicker() {
|
||||
|
||||
function handleDraftSchemasSave(selectedNames: string[]) {
|
||||
const key = visibleSchemasDatabaseKey.value;
|
||||
form.value.visible_schemas = { ...(form.value.visible_schemas || {}), [key]: selectedNames };
|
||||
form.value.visible_schemas = { ...form.value.visible_schemas, [key]: selectedNames };
|
||||
}
|
||||
|
||||
function handleDraftSchemasShowAll() {
|
||||
@@ -3967,9 +4009,9 @@ function openExternalUrl(url: string) {
|
||||
<Button v-if="canChooseVisibleDatabases" variant="outline" class="shrink-0" :disabled="isTesting || isSaving || isLoadingVisibleDatabases || !hasRequiredConnectionTarget" @click="openVisibleDatabasesPicker">
|
||||
<Loader2 v-if="isLoadingVisibleDatabases" class="mr-1.5 h-4 w-4 animate-spin" />
|
||||
<ListFilter v-else class="mr-1.5 h-4 w-4" />
|
||||
{{ hasVisibleDatabaseFilter ? visibleDatabaseSummary : t("contextMenu.selectVisibleDatabases") }}
|
||||
{{ hasVisibleObjectFilter ? visibleObjectSummary : visibleFilterUsesSchemas ? t("contextMenu.configureVisibleObjects") : t("contextMenu.selectVisibleDatabases") }}
|
||||
</Button>
|
||||
<Button v-if="canChooseVisibleSchemas" variant="outline" class="shrink-0" :disabled="isTesting || isSaving || isLoadingVisibleSchemas || !hasRequiredConnectionTarget" @click="openVisibleSchemasPicker">
|
||||
<Button v-if="canChooseVisibleSchemas && !visibleFilterUsesSchemas" variant="outline" class="shrink-0" :disabled="isTesting || isSaving || isLoadingVisibleSchemas || !hasRequiredConnectionTarget" @click="openVisibleSchemasPicker">
|
||||
<Loader2 v-if="isLoadingVisibleSchemas" class="mr-1.5 h-4 w-4 animate-spin" />
|
||||
<ListFilter v-else class="mr-1.5 h-4 w-4" />
|
||||
{{ hasVisibleSchemaFilter ? visibleSchemaSummary : t("visibleSchemas.showAll") }}
|
||||
@@ -3988,21 +4030,21 @@ function openExternalUrl(url: string) {
|
||||
<Dialog v-model:open="showVisibleDatabasesDialog">
|
||||
<DialogContent class="sm:max-w-[460px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t("visibleDatabases.title") }}</DialogTitle>
|
||||
<DialogTitle>{{ t(visibleObjectTitleKey) }}</DialogTitle>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ t("visibleDatabases.description", { connection: form.name || selectedProfile().label }) }}
|
||||
{{ t(visibleObjectDescriptionKey, { connection: form.name || selectedProfile().label }) }}
|
||||
</p>
|
||||
</DialogHeader>
|
||||
|
||||
<div class="flex items-center gap-2 rounded-md border bg-background px-2">
|
||||
<Search class="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
<Input v-model="visibleDatabaseSearchText" :placeholder="t('visibleDatabases.searchPlaceholder')" class="h-8 border-0 px-0 shadow-none focus-visible:ring-0" :disabled="isLoadingVisibleDatabases || !!visibleDatabaseError" />
|
||||
<Input v-model="visibleDatabaseSearchText" :placeholder="t(visibleObjectSearchPlaceholderKey)" class="h-8 border-0 px-0 shadow-none focus-visible:ring-0" :disabled="isLoadingVisibleDatabases || !!visibleDatabaseError" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-xs text-muted-foreground">
|
||||
<span>
|
||||
{{
|
||||
t("visibleDatabases.selectedCount", {
|
||||
t(visibleObjectSelectedCountKey, {
|
||||
selected: visibleDatabaseSelectedCount,
|
||||
total: visibleDatabaseTotalCount,
|
||||
})
|
||||
@@ -4021,7 +4063,7 @@ function openExternalUrl(url: string) {
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="!isLoadingVisibleDatabases && !visibleDatabaseError && !visibleDatabaseCanSave" class="text-xs text-destructive">
|
||||
{{ t("visibleDatabases.emptySelection") }}
|
||||
{{ t(visibleObjectEmptySelectionKey) }}
|
||||
</p>
|
||||
|
||||
<label v-if="visibleDatabaseHasSystemDatabases" class="flex h-8 items-center gap-2 rounded-md px-1 text-xs text-muted-foreground">
|
||||
@@ -4035,7 +4077,7 @@ function openExternalUrl(url: string) {
|
||||
{{ t("common.loading") }}
|
||||
</div>
|
||||
<div v-else-if="visibleDatabaseError" class="p-3 text-sm text-destructive">
|
||||
{{ t("visibleDatabases.loadFailed", { message: visibleDatabaseError }) }}
|
||||
{{ t(visibleObjectLoadFailedKey, { message: visibleDatabaseError }) }}
|
||||
</div>
|
||||
<div v-else-if="!filteredVisibleDatabaseNames.length" class="p-3 text-sm text-muted-foreground">
|
||||
{{ t("grid.noSearchResults") }}
|
||||
@@ -4058,7 +4100,7 @@ function openExternalUrl(url: string) {
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="showVisibleDatabasesDialog = false">{{ t("dangerDialog.cancel") }}</Button>
|
||||
<Button :disabled="isLoadingVisibleDatabases || !!visibleDatabaseError || !visibleDatabaseCanSave" @click="saveVisibleDatabaseSelection">
|
||||
{{ t("visibleDatabases.save") }}
|
||||
{{ t(visibleObjectSaveKey) }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@@ -3561,12 +3561,11 @@ function treeItemMenuItems(): ContextMenuItem[] {
|
||||
});
|
||||
if (canConfigureVisibleDatabases.value) {
|
||||
items.push({
|
||||
label: t("contextMenu.selectVisibleDatabases"),
|
||||
label: t("contextMenu.configureVisibleObjects"),
|
||||
action: openVisibleDatabasesDialog,
|
||||
icon: ListFilter,
|
||||
});
|
||||
}
|
||||
if (canConfigureVisibleSchemas.value) {
|
||||
} else if (canConfigureVisibleSchemas.value) {
|
||||
items.push({
|
||||
label: t("visibleSchemas.title"),
|
||||
action: openVisibleSchemasDialog,
|
||||
|
||||
@@ -22,7 +22,9 @@ const emit = defineEmits<{
|
||||
const { t } = useI18n();
|
||||
const connectionStore = useConnectionStore();
|
||||
|
||||
const databaseNames = ref<string[]>([]);
|
||||
type FilterMode = "database" | "schema";
|
||||
|
||||
const objectNames = ref<string[]>([]);
|
||||
const selectedNames = ref<Set<string>>(new Set());
|
||||
const searchText = ref("");
|
||||
const showSystemDatabases = ref(false);
|
||||
@@ -30,19 +32,34 @@ const isLoading = ref(false);
|
||||
const errorMessage = ref("");
|
||||
|
||||
const connection = computed(() => connectionStore.getConfig(props.connectionId));
|
||||
const listedDatabaseNames = computed(() => {
|
||||
if (showSystemDatabases.value) return databaseNames.value;
|
||||
return filterDatabaseNamesForConnection(databaseNames.value, connection.value);
|
||||
const filterMode = computed<FilterMode>(() => (connection.value?.db_type === "oracle" || connection.value?.db_type === "dameng" ? "schema" : "database"));
|
||||
const databaseKey = computed(() => connection.value?.database || "");
|
||||
const isSchemaFilterMode = computed(() => filterMode.value === "schema");
|
||||
const titleKey = computed(() => (isSchemaFilterMode.value ? "visibleSchemas.title" : "visibleDatabases.title"));
|
||||
const descriptionKey = computed(() => (isSchemaFilterMode.value ? "visibleSchemas.description" : "visibleDatabases.description"));
|
||||
const searchPlaceholderKey = computed(() => (isSchemaFilterMode.value ? "visibleSchemas.searchPlaceholder" : "visibleDatabases.searchPlaceholder"));
|
||||
const emptySelectionKey = computed(() => (isSchemaFilterMode.value ? "visibleSchemas.emptySelection" : "visibleDatabases.emptySelection"));
|
||||
const loadFailedKey = computed(() => (isSchemaFilterMode.value ? "visibleSchemas.loadFailed" : "visibleDatabases.loadFailed"));
|
||||
const listedObjectNames = computed(() => {
|
||||
if (isSchemaFilterMode.value) return objectNames.value;
|
||||
if (showSystemDatabases.value) return objectNames.value;
|
||||
return filterDatabaseNamesForConnection(objectNames.value, connection.value);
|
||||
});
|
||||
const filteredDatabaseNames = computed(() => {
|
||||
const filteredObjectNames = computed(() => {
|
||||
const query = searchText.value.trim().toLowerCase();
|
||||
if (!query) return listedDatabaseNames.value;
|
||||
return listedDatabaseNames.value.filter((name) => name.toLowerCase().includes(query));
|
||||
if (!query) return listedObjectNames.value;
|
||||
return listedObjectNames.value.filter((name) => name.toLowerCase().includes(query));
|
||||
});
|
||||
const selectedCount = computed(() => selectedNames.value.size);
|
||||
const totalCount = computed(() => listedDatabaseNames.value.length);
|
||||
const totalCount = computed(() => listedObjectNames.value.length);
|
||||
const canSaveSelection = computed(() => canSaveVisibleDatabaseSelection([...selectedNames.value]));
|
||||
const hasSystemDatabases = computed(() => databaseNames.value.some((database) => isSystemDatabaseName(connection.value?.db_type, database)));
|
||||
const hasSystemDatabases = computed(() => !isSchemaFilterMode.value && objectNames.value.some((database) => isSystemDatabaseName(connection.value?.db_type, database)));
|
||||
const showAllDisabled = computed(() => {
|
||||
if (isSchemaFilterMode.value) {
|
||||
return !connection.value?.visible_schemas?.[databaseKey.value];
|
||||
}
|
||||
return !Array.isArray(connection.value?.visible_databases);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
@@ -62,14 +79,14 @@ async function loadDatabases() {
|
||||
errorMessage.value = "";
|
||||
searchText.value = "";
|
||||
try {
|
||||
const names = await loadDatabaseNames();
|
||||
databaseNames.value = names;
|
||||
const configured = connection.value?.visible_databases;
|
||||
const initialSelection = Array.isArray(configured) ? normalizeVisibleDatabaseSelection(configured, names) : filterDatabaseNamesForConnection(names, connection.value);
|
||||
const names = await loadObjectNames();
|
||||
objectNames.value = names;
|
||||
const configured = isSchemaFilterMode.value ? connection.value?.visible_schemas?.[databaseKey.value] : connection.value?.visible_databases;
|
||||
const initialSelection = Array.isArray(configured) ? normalizeVisibleDatabaseSelection(configured, names) : listedObjectNames.value;
|
||||
selectedNames.value = new Set(initialSelection);
|
||||
showSystemDatabases.value = initialSelection.some((database) => isSystemDatabaseName(connection.value?.db_type, database));
|
||||
showSystemDatabases.value = !isSchemaFilterMode.value && initialSelection.some((database) => isSystemDatabaseName(connection.value?.db_type, database));
|
||||
} catch (e: any) {
|
||||
databaseNames.value = [];
|
||||
objectNames.value = [];
|
||||
selectedNames.value = new Set();
|
||||
showSystemDatabases.value = false;
|
||||
errorMessage.value = String(e?.message || e);
|
||||
@@ -78,11 +95,11 @@ async function loadDatabases() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDatabaseNames(): Promise<string[]> {
|
||||
async function loadObjectNames(): Promise<string[]> {
|
||||
const config = connection.value;
|
||||
if (config?.db_type === "oracle" || config?.db_type === "dameng") {
|
||||
if (isSchemaFilterMode.value) {
|
||||
await connectionStore.ensureConnected(props.connectionId);
|
||||
return api.listSchemas(props.connectionId, config.database || "");
|
||||
return api.listSchemas(props.connectionId, config?.database || "");
|
||||
}
|
||||
await connectionStore.ensureConnected(props.connectionId);
|
||||
if (config?.db_type === "redis") {
|
||||
@@ -94,21 +111,21 @@ async function loadDatabaseNames(): Promise<string[]> {
|
||||
return (await api.listDatabases(props.connectionId)).map((database) => database.name);
|
||||
}
|
||||
|
||||
function toggleDatabase(database: string) {
|
||||
function toggleObject(name: string) {
|
||||
const next = new Set(selectedNames.value);
|
||||
if (next.has(database)) next.delete(database);
|
||||
else next.add(database);
|
||||
if (next.has(name)) next.delete(name);
|
||||
else next.add(name);
|
||||
selectedNames.value = next;
|
||||
}
|
||||
|
||||
const isSearching = computed(() => searchText.value.trim().length > 0);
|
||||
|
||||
function selectAll() {
|
||||
selectedNames.value = new Set(listedDatabaseNames.value);
|
||||
selectedNames.value = new Set(listedObjectNames.value);
|
||||
}
|
||||
|
||||
function selectFiltered() {
|
||||
selectedNames.value = new Set(filteredDatabaseNames.value);
|
||||
selectedNames.value = new Set(filteredObjectNames.value);
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
@@ -116,13 +133,21 @@ function clearSelection() {
|
||||
}
|
||||
|
||||
async function showAllDatabases() {
|
||||
await connectionStore.clearVisibleDatabases(props.connectionId);
|
||||
if (isSchemaFilterMode.value) {
|
||||
await connectionStore.clearVisibleSchemas(props.connectionId, databaseKey.value);
|
||||
} else {
|
||||
await connectionStore.clearVisibleDatabases(props.connectionId);
|
||||
}
|
||||
emit("update:open", false);
|
||||
}
|
||||
|
||||
async function saveSelection() {
|
||||
if (!canSaveSelection.value) return;
|
||||
await connectionStore.setVisibleDatabases(props.connectionId, [...selectedNames.value]);
|
||||
if (isSchemaFilterMode.value) {
|
||||
await connectionStore.setVisibleSchemas(props.connectionId, databaseKey.value, normalizeVisibleDatabaseSelection([...selectedNames.value], objectNames.value));
|
||||
} else {
|
||||
await connectionStore.setVisibleDatabases(props.connectionId, [...selectedNames.value]);
|
||||
}
|
||||
emit("update:open", false);
|
||||
}
|
||||
</script>
|
||||
@@ -131,15 +156,15 @@ async function saveSelection() {
|
||||
<Dialog :open="open" @update:open="(value: boolean) => emit('update:open', value)">
|
||||
<DialogContent class="sm:max-w-[460px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t("visibleDatabases.title") }}</DialogTitle>
|
||||
<DialogTitle>{{ t(titleKey) }}</DialogTitle>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ t("visibleDatabases.description", { connection: connectionName }) }}
|
||||
{{ t(descriptionKey, { connection: connectionName }) }}
|
||||
</p>
|
||||
</DialogHeader>
|
||||
|
||||
<div class="flex items-center gap-2 rounded-md border bg-background px-2">
|
||||
<Search class="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
<Input v-model="searchText" :placeholder="t('visibleDatabases.searchPlaceholder')" class="h-8 border-0 px-0 shadow-none focus-visible:ring-0" :disabled="isLoading || !!errorMessage" />
|
||||
<Input v-model="searchText" :placeholder="t(searchPlaceholderKey)" class="h-8 border-0 px-0 shadow-none focus-visible:ring-0" :disabled="isLoading || !!errorMessage" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-xs text-muted-foreground">
|
||||
@@ -154,13 +179,13 @@ async function saveSelection() {
|
||||
<button class="hover:text-foreground disabled:opacity-50" :disabled="isLoading" @click="clearSelection">
|
||||
{{ t("visibleDatabases.clear") }}
|
||||
</button>
|
||||
<button class="hover:text-foreground disabled:opacity-50" :disabled="isLoading || !Array.isArray(connection?.visible_databases)" @click="showAllDatabases">
|
||||
<button class="hover:text-foreground disabled:opacity-50" :disabled="isLoading || showAllDisabled" @click="showAllDatabases">
|
||||
{{ t("visibleDatabases.showAll") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="!isLoading && !errorMessage && !canSaveSelection" class="text-xs text-destructive">
|
||||
{{ t("visibleDatabases.emptySelection") }}
|
||||
{{ t(emptySelectionKey) }}
|
||||
</p>
|
||||
|
||||
<label v-if="hasSystemDatabases" class="flex h-8 items-center gap-2 rounded-md px-1 text-xs text-muted-foreground">
|
||||
@@ -174,22 +199,22 @@ async function saveSelection() {
|
||||
{{ t("common.loading") }}
|
||||
</div>
|
||||
<div v-else-if="errorMessage" class="p-3 text-sm text-destructive">
|
||||
{{ t("visibleDatabases.loadFailed", { message: errorMessage }) }}
|
||||
{{ t(loadFailedKey, { message: errorMessage }) }}
|
||||
</div>
|
||||
<div v-else-if="!filteredDatabaseNames.length" class="p-3 text-sm text-muted-foreground">
|
||||
<div v-else-if="!filteredObjectNames.length" class="p-3 text-sm text-muted-foreground">
|
||||
{{ t("grid.noSearchResults") }}
|
||||
</div>
|
||||
<template v-else>
|
||||
<button
|
||||
v-for="database in filteredDatabaseNames"
|
||||
:key="database"
|
||||
v-for="name in filteredObjectNames"
|
||||
:key="name"
|
||||
type="button"
|
||||
class="flex h-8 w-full min-w-0 items-center gap-2 rounded-sm px-2 text-left text-sm hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none"
|
||||
@click="toggleDatabase(database)"
|
||||
@click="toggleObject(name)"
|
||||
>
|
||||
<CheckSquare v-if="selectedNames.has(database)" class="h-4 w-4 shrink-0 text-primary" />
|
||||
<CheckSquare v-if="selectedNames.has(name)" class="h-4 w-4 shrink-0 text-primary" />
|
||||
<Square v-else class="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
<span class="truncate">{{ database }}</span>
|
||||
<span class="truncate">{{ name }}</span>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user