feat(influxdb3): add influxdb 3 engine over http

This commit is contained in:
Clarence authored and GitHub committed 2026-09-01 15:28:08 +08:00
1 parent 613c4f7ca3
commit 264f5c4836
25 files changed
+741 -19

No files matched your search

@@ -1409,22 +1409,26 @@ function buildMqttExternalConfig(): MqttConnectionConfig {
};
}
const INFLUXDB_V1V2_DEFAULT_PORT = 8086;
const INFLUXDB_V3_DEFAULT_PORT = 8181;
const influxDbVersion = ref<InfluxDbVersion>("1");
const influxDbOrg = ref("");
const victoriaMetricsApiPath = ref("/prometheus");
const victoriaMetricsLookback = ref("1h");
function resetInfluxDbFields(config?: Partial<InfluxDbExternalConfig>) {
influxDbVersion.value = config?.version === "2" ? "2" : "1";
function resetInfluxDbFields(config?: Partial<InfluxDbExternalConfig>, versionHint?: InfluxDbVersion) {
const version = versionHint ?? (config?.version === "2" ? "2" : config?.version === "3" ? "3" : "1");
influxDbVersion.value = version;
influxDbOrg.value = config?.org?.trim() || "";
}
function hydrateInfluxDbFields(value: unknown) {
function hydrateInfluxDbFields(value: unknown, versionHint?: InfluxDbVersion) {
if (!value || typeof value !== "object") {
resetInfluxDbFields();
resetInfluxDbFields(undefined, versionHint);
return;
}
resetInfluxDbFields(value as Partial<InfluxDbExternalConfig>);
resetInfluxDbFields(value as Partial<InfluxDbExternalConfig>, versionHint);
}
function resetHiveKerberosFields(config?: Pick<ConnectionConfig, "url_params" | "agent_java_options">) {
@@ -1442,6 +1446,9 @@ function resetDamengJvmOptions(config?: Pick<ConnectionConfig, "agent_java_optio
}
function buildInfluxDbExternalConfig(): InfluxDbExternalConfig {
// InfluxDB 3 Core can run with --without-auth; the driver treats an empty
// password as "no Authorization header", so the token stays optional here.
if (influxDbVersion.value === "3") return { version: "3" };
if (influxDbVersion.value !== "2") return { version: "1" };
const org = influxDbOrg.value.trim();
if (!org) throw new Error("InfluxDB 2.x organization is required");
@@ -1477,11 +1484,17 @@ function buildVictoriaMetricsExternalConfig(): VictoriaMetricsExternalConfig {
return { apiPath, lookback };
}
watch(influxDbVersion, (version) => {
watch(influxDbVersion, (version, previousVersion) => {
if (form.value.db_type !== "influxdb") return;
if (version === "2") {
if (version === "2" || version === "3") {
form.value.username = "";
}
const port = form.value.port;
if (version === "3" && (!port || port === INFLUXDB_V1V2_DEFAULT_PORT)) {
form.value.port = INFLUXDB_V3_DEFAULT_PORT;
} else if (previousVersion === "3" && port === INFLUXDB_V3_DEFAULT_PORT) {
form.value.port = INFLUXDB_V1V2_DEFAULT_PORT;
}
});
function requireMqField(value: string, message: string): string {
@@ -2556,8 +2569,15 @@ watch(
} else {
resetMqttFields();
}
if (config.db_type === "influxdb") {
hydrateInfluxDbFields(config.external_config);
if (config.db_type === "influxdb" || config.db_type === "influxdb3") {
// The influxdb3 engine is presented as the InfluxDB card with
// version = 3. Save-side (`applyConnectionFormToConfig`) swaps
// db_type back to `influxdb3` when saving.
const versionHint: InfluxDbVersion | undefined = config.db_type === "influxdb3" ? "3" : undefined;
hydrateInfluxDbFields(config.external_config, versionHint);
if (config.db_type === "influxdb3") {
form.value.db_type = "influxdb";
}
} else {
resetInfluxDbFields();
}
@@ -2831,7 +2851,9 @@ function jdbcProductCategory(profileId: string): DbCategoryKey {
return category;
}
const dbOptions: DbOption[] = [...CONNECTION_PICKER_OPTIONS, ...jdbcProductPickerOptions().map((option) => ({ ...option, category: jdbcProductCategory(option.value) }))];
// `influxdb3` is presented as a version option inside the InfluxDB card
// (see the version <Select> below), not as a standalone picker entry.
const dbOptions: DbOption[] = [...CONNECTION_PICKER_OPTIONS.filter((option) => option.value !== "influxdb3"), ...jdbcProductPickerOptions().map((option) => ({ ...option, category: jdbcProductCategory(option.value) }))];
const dbCategoryDefinitions = dbCategoryMetadata.map((category) => ({
...category,
@@ -3934,11 +3956,17 @@ function connectionConfigForSubmit(id: string, generatedName = ""): ConnectionCo
} else if (config.db_type === "influxdb") {
config.external_config = buildInfluxDbExternalConfig();
config.connection_string = undefined;
if (influxDbVersion.value === "2") {
if (influxDbVersion.value === "2" || influxDbVersion.value === "3") {
config.username = "";
config.password = config.password.trim();
config.database = config.database?.trim() || undefined;
}
// Swap db_type to the standalone influxdb3 engine when the version
// picker is on 3; the form keeps db_type = influxdb so the same card
// renders every InfluxDB flavor.
if (influxDbVersion.value === "3") {
config.db_type = "influxdb3";
}
} else if (config.db_type === "victoriametrics") {
config.external_config = buildVictoriaMetricsExternalConfig();
config.connection_string = undefined;
@@ -7218,6 +7246,7 @@ function openExternalUrl(url: string) {
<SelectContent>
<SelectItem value="1">InfluxDB 1.x</SelectItem>
<SelectItem value="2">InfluxDB 2.x</SelectItem>
<SelectItem value="3">InfluxDB 3.x</SelectItem>
</SelectContent>
</Select>
</div>
@@ -7247,6 +7276,16 @@ function openExternalUrl(url: string) {
<PasswordInput v-model="form.password" class="col-span-3" />
</div>
</template>
<template v-else-if="influxDbVersion === '3'">
<div class="grid grid-cols-4 items-center gap-4">
<Label :class="connectionLabelClass">{{ t("connection.database") }}</Label>
<Input v-model="form.database" class="col-span-3" placeholder="my-database" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label :class="connectionLabelClass">Token</Label>
<PasswordInput v-model="form.password" class="col-span-3" />
</div>
</template>
<template v-else>
<div class="grid grid-cols-4 items-center gap-4">
<Label :class="connectionLabelClass">{{ t("connection.user") }}</Label>
@@ -7263,7 +7302,7 @@ function openExternalUrl(url: string) {
</template>
<div class="grid grid-cols-4 items-center gap-4">
<Label :class="connectionLabelClass">{{ t("connection.urlParams") }}</Label>
<Input v-model="form.url_params" class="col-span-3" :placeholder="influxDbVersion === '2' ? 'precision=ns' : 'epoch=ms'" />
<Input v-model="form.url_params" class="col-span-3" :placeholder="influxDbVersion === '2' ? 'precision=ns' : influxDbVersion === '3' ? '' : 'epoch=ms'" />
</div>
</template>
@@ -113,6 +113,7 @@ const assetIcons: Record<string, string> = {
consul: "consul",
iris: "iris",
influxdb: "influxdb",
influxdb3: "influxdb",
victoriametrics: "victoriametrics.png",
zookeeper: "zookeeper",
oscar: "oscar.png",
@@ -263,6 +263,9 @@ export function connectionUrlPlaceholder(dbType: DatabaseType): string {
case "influxdb":
return "influxdb://user:password@host:port/database";
case "influxdb3":
return "influxdb3://token@host:8181/database";
case "victoriametrics":
return "http://user:password@host:port/prometheus";
@@ -229,7 +229,7 @@ export function supportsObjectBrowserTreeNode(dbType: DatabaseType | undefined,
}
export function supportsTableTruncate(dbType?: DatabaseType): boolean {
return !!dbType && dbType !== "impala" && dbType !== "sqlite" && dbType !== "rqlite" && dbType !== "turso" && dbType !== "cloudflare-d1" && dbType !== "duckdb" && dbType !== "influxdb" && dbType !== "victoriametrics" && dbType !== "manticoresearch";
return !!dbType && dbType !== "impala" && dbType !== "sqlite" && dbType !== "rqlite" && dbType !== "turso" && dbType !== "cloudflare-d1" && dbType !== "duckdb" && dbType !== "influxdb" && dbType !== "influxdb3" && dbType !== "victoriametrics" && dbType !== "manticoresearch";
}
export function supportsTableVacuum(dbType?: DatabaseType): boolean {
@@ -90,6 +90,7 @@ export const DATABASE_NAMESPACE_CREATION_MATRIX = {
zookeeper: { deferred: "key-value namespaces are not databases" },
iris: { database: "schema" },
influxdb: { connection: "database" },
influxdb3: { deferred: "database creation on InfluxDB 3.x goes through the /api/v3/configure/database admin endpoint, which is not part of the SQL execution path" },
victoriametrics: { deferred: "metric namespaces are managed by VictoriaMetrics deployment configuration" },
jdbc: { deferred: "generic JDBC does not expose a reliable dialect-specific create target" },
mq: { deferred: "message queue namespaces are handled by MQ admin panels" },
@@ -92,6 +92,7 @@ const DATABASE_TYPE_OBJECTS = new Map<DatabaseType, SidebarObjectKind[]>([
["neo4j", TABLE_VIEW_OBJECTS],
// others
["influxdb", ["TABLE"]],
["influxdb3", ["TABLE"]],
["victoriametrics", ["TABLE"]],
["hbase", ["TABLE"]],
["questdb", ["TABLE", "VIEW", "MATERIALIZED_VIEW"]],
@@ -90,6 +90,7 @@ export const DATABASE_PROPERTY_EDITING_MATRIX = {
zookeeper: { deferred: "key-value namespaces are not databases" },
iris: { deferred: "schema properties need product-specific handling" },
influxdb: { deferred: "database retention policies need a dedicated workflow" },
influxdb3: { deferred: "database retention policies need a dedicated workflow" },
victoriametrics: { deferred: "metric and retention settings are managed by VictoriaMetrics deployment configuration" },
jdbc: { deferred: "generic JDBC does not expose reliable dialect-specific properties" },
mq: { deferred: "message queue namespaces are handled by MQ admin panels" },
@@ -102,6 +102,12 @@ const capabilityByType: Partial<Record<DatabaseType, Partial<TableMetadataCapabi
triggers: false,
ddl: false,
},
influxdb3: {
indexes: false,
foreignKeys: false,
triggers: false,
ddl: false,
},
influxdb: {
indexes: false,
foreignKeys: false,
@@ -117,6 +117,7 @@ export const CONNECTION_PROFILES = {
mqtt: { type: "mqtt", port: 1883, user: "", label: "MQTT", icon: "mqtt", host: "127.0.0.1" },
iris: { type: "iris", port: 1972, user: "_SYSTEM", label: "IRIS", icon: "iris" },
influxdb: { type: "influxdb", port: 8086, user: "", label: "InfluxDB", icon: "InfluxDB" },
influxdb3: { type: "influxdb3", port: 8181, user: "", label: "InfluxDB 3.x", icon: "InfluxDB" },
victoriametrics: { type: "victoriametrics", port: 8428, user: "", label: "VictoriaMetrics", icon: "victoriametrics" },
custom_mysql: { type: "mysql", port: 3306, user: "root", label: "Custom", icon: "mysql", urlParams: "" },
dolt: { type: "mysql", port: 3306, user: "root", label: "Dolt", icon: "dolt", urlParams: "" },
@@ -221,6 +222,7 @@ export const CONNECTION_PROFILE_ICONS = {
mqtt: "mqtt",
iris: "iris",
influxdb: "influxdb",
influxdb3: "influxdb",
victoriametrics: "victoriametrics",
custom_mysql: "mysql",
dolt: "dolt",
@@ -319,6 +321,7 @@ export const CONNECTION_PICKER_OPTIONS = [
{ value: "mqtt", label: "MQTT", category: "mq" },
{ value: "iris", label: "IRIS", category: "sql" },
{ value: "influxdb", label: "InfluxDB", category: "timeseries" },
{ value: "influxdb3", label: "InfluxDB 3.x", category: "timeseries" },
{ value: "victoriametrics", label: "VictoriaMetrics", category: "timeseries" },
{ value: "custom_mysql", label: "Custom (MySQL)", category: "sql" },
{ value: "dolt", label: "Dolt", category: "sql" },
@@ -76,6 +76,7 @@ export const DATABASE_TYPES = [
"iotdb",
"iris",
"influxdb",
"influxdb3",
"victoriametrics",
"jdbc",
"spark",
+1 -1
View File
@@ -1,4 +1,4 @@
export type InfluxDbVersion = "1" | "2";
export type InfluxDbVersion = "1" | "2" | "3";
export interface InfluxDbExternalConfig {
version?: InfluxDbVersion;