1 parent
f621e40655
commit
e2fa810f2e
16 files changed
+146
-10
No files matched your search
@@ -1036,6 +1036,8 @@ const allFilterModeOptions: Array<{ value: FilterMode; labelKey: string }> = [
|
||||
{ value: "not-between", labelKey: "grid.filterBuilderNotBetween" },
|
||||
{ value: "is-null", labelKey: "grid.filterBuilderIsNull" },
|
||||
{ value: "is-not-null", labelKey: "grid.filterBuilderIsNotNull" },
|
||||
{ value: "is-blank", labelKey: "grid.filterBuilderIsBlank" },
|
||||
{ value: "is-not-blank", labelKey: "grid.filterBuilderIsNotBlank" },
|
||||
];
|
||||
const filterModeOptions = computed(() => allFilterModeOptions.filter((option) => filterModeIsSupportedForDatabase(option.value, resolvedDatabaseType.value)));
|
||||
const filterBuilderColumnOptions = computed(() => filterBuilderColumns.value.map((column) => column.name));
|
||||
@@ -6372,7 +6374,7 @@ async function contextFilterCondition(target: ContextFilterTarget, mode: FilterM
|
||||
const { columnName, sourceResult, sourceIndex, sourceValue, requiresHydration } = target;
|
||||
// CustomContextMenu closes before invoking its action. Keep the target
|
||||
// stable across hydration after the close lifecycle clears contextCell.
|
||||
if (mode !== "is-null" && mode !== "is-not-null") {
|
||||
if (filterModeNeedsValue(mode)) {
|
||||
if (!(await hydrateLargeValueCell(target.rowId, target.col))) return null;
|
||||
}
|
||||
if (props.result !== sourceResult) return null;
|
||||
|
||||
@@ -1711,6 +1711,8 @@ export default {
|
||||
filterBuilderNotBetween: "Outside range",
|
||||
filterBuilderIsNull: "Is NULL",
|
||||
filterBuilderIsNotNull: "Is not NULL",
|
||||
filterBuilderIsBlank: "Is blank (NULL or empty)",
|
||||
filterBuilderIsNotBlank: "Is not blank (not NULL and not empty)",
|
||||
columnActions: "Column actions",
|
||||
localFilter: "Local value filter",
|
||||
localFilterFor: "Local Values For '{column}'",
|
||||
|
||||
@@ -1594,6 +1594,8 @@ export default withEnglishFallback({
|
||||
filterBuilderNotBetween: "Fuera de rango",
|
||||
filterBuilderIsNull: "Es NULL",
|
||||
filterBuilderIsNotNull: "No es NULL",
|
||||
filterBuilderIsBlank: "Está vacío (NULL o cadena vacía)",
|
||||
filterBuilderIsNotBlank: "No está vacío (ni NULL ni cadena vacía)",
|
||||
columnActions: "Acciones de columna",
|
||||
localFilter: "Filtro local de valores",
|
||||
localFilterFor: "Valores locales para '{column}'",
|
||||
|
||||
@@ -1592,6 +1592,8 @@ export default withEnglishFallback({
|
||||
filterBuilderNotBetween: "Fuori intervallo",
|
||||
filterBuilderIsNull: "È NULL",
|
||||
filterBuilderIsNotNull: "Non è NULL",
|
||||
filterBuilderIsBlank: "È vuoto (NULL o stringa vuota)",
|
||||
filterBuilderIsNotBlank: "Non è vuoto (né NULL né stringa vuota)",
|
||||
columnActions: "Azioni colonna",
|
||||
localFilter: "Filtro valori locale",
|
||||
localFilterFor: "Valori locali per '{column}'",
|
||||
|
||||
@@ -1610,6 +1610,8 @@ export default withEnglishFallback({
|
||||
filterBuilderNotBetween: "範囲外",
|
||||
filterBuilderIsNull: "NULLである",
|
||||
filterBuilderIsNotNull: "NULLでない",
|
||||
filterBuilderIsBlank: "空(NULLまたは空文字)",
|
||||
filterBuilderIsNotBlank: "空でない(NULLでも空文字でもない)",
|
||||
columnActions: "列の操作",
|
||||
localFilter: "ローカル値フィルター",
|
||||
localFilterFor: "'{column}'のローカル値",
|
||||
|
||||
@@ -1587,6 +1587,8 @@ export default withEnglishFallback({
|
||||
filterBuilderNotBetween: "범위 외",
|
||||
filterBuilderIsNull: "NULL임",
|
||||
filterBuilderIsNotNull: "NULL이 아님",
|
||||
filterBuilderIsBlank: "비어 있음(NULL 또는 빈 문자열)",
|
||||
filterBuilderIsNotBlank: "비어 있지 않음(NULL도 빈 문자열도 아님)",
|
||||
columnActions: "컬럼 작업",
|
||||
localFilter: "로컬 값 필터",
|
||||
localFilterFor: "'{column}' 로컬 값",
|
||||
|
||||
@@ -1594,6 +1594,8 @@ export default withEnglishFallback({
|
||||
filterBuilderNotBetween: "Fora do intervalo",
|
||||
filterBuilderIsNull: "É NULL",
|
||||
filterBuilderIsNotNull: "Não é NULL",
|
||||
filterBuilderIsBlank: "Está em branco (NULL ou string vazia)",
|
||||
filterBuilderIsNotBlank: "Não está em branco (nem NULL nem string vazia)",
|
||||
columnActions: "Ações da coluna",
|
||||
localFilter: "Filtro local de valores",
|
||||
localFilterFor: "Valores locais para '{column}'",
|
||||
|
||||
@@ -1634,8 +1634,10 @@ export default withEnglishFallback({
|
||||
filterBuilderNotIn: "列表外",
|
||||
filterBuilderBetween: "介于",
|
||||
filterBuilderNotBetween: "不介于",
|
||||
filterBuilderIsNull: "为空",
|
||||
filterBuilderIsNotNull: "不为空",
|
||||
filterBuilderIsNull: "为 NULL",
|
||||
filterBuilderIsNotNull: "不为 NULL",
|
||||
filterBuilderIsBlank: "为空(NULL 或空字符串)",
|
||||
filterBuilderIsNotBlank: "不为空(非 NULL 且非空字符串)",
|
||||
columnActions: "字段操作",
|
||||
localFilter: "本地值筛选",
|
||||
localFilterFor: "本地值筛选“{column}”",
|
||||
|
||||
@@ -1591,8 +1591,10 @@ export default withEnglishFallback({
|
||||
filterBuilderNotIn: "清單外",
|
||||
filterBuilderBetween: "介於",
|
||||
filterBuilderNotBetween: "不介於",
|
||||
filterBuilderIsNull: "為空",
|
||||
filterBuilderIsNotNull: "不為空",
|
||||
filterBuilderIsNull: "為 NULL",
|
||||
filterBuilderIsNotNull: "不為 NULL",
|
||||
filterBuilderIsBlank: "為空(NULL 或空字串)",
|
||||
filterBuilderIsNotBlank: "不為空(非 NULL 且非空字串)",
|
||||
columnActions: "欄位操作",
|
||||
localFilter: "本機值篩選",
|
||||
localFilterFor: "本機值篩選「{column}」",
|
||||
|
||||
@@ -36,6 +36,19 @@ describe("normalizeColumnFormatter", () => {
|
||||
expect(normalizeColumnFormatter({ ...base, filter: { column: "dict_type", mode: "between", value: "A" } })).toBeUndefined();
|
||||
expect(normalizeColumnFormatter({ ...base, filter: { column: "dict_type", mode: "raw-sql", value: "1=1" } })).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each(["is-blank", "is-not-blank"] as const)("preserves the value-less %s manual reference filter", (mode) => {
|
||||
expect(
|
||||
normalizeColumnFormatter({
|
||||
kind: "foreign-key-display",
|
||||
referenceMode: "manual",
|
||||
refTable: "dictionary",
|
||||
refColumn: "dict_key",
|
||||
displayColumn: "dict_value",
|
||||
filter: { column: "dict_type", mode },
|
||||
}),
|
||||
).toMatchObject({ filter: { column: "dict_type", mode, value: undefined, endValue: undefined } });
|
||||
});
|
||||
});
|
||||
|
||||
describe("normalizeSupportedDateTimePattern", () => {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import type { DataGridContextFilterMode } from "@/lib/dataGrid/dataGridSql";
|
||||
|
||||
describe("VictoriaMetrics data grid filters", () => {
|
||||
it("does not expose SQL filter modes for MetricsQL results", () => {
|
||||
const modes: DataGridContextFilterMode[] = ["equals", "not-equals", "is-null", "is-not-null", "like", "not-like", "less-than", "greater-than", "in", "not-in", "between", "not-between"];
|
||||
const modes: DataGridContextFilterMode[] = ["equals", "not-equals", "is-null", "is-not-null", "is-blank", "is-not-blank", "like", "not-like", "less-than", "greater-than", "in", "not-in", "between", "not-between"];
|
||||
|
||||
expect(modes.every((mode) => !filterModeIsSupportedForDatabase(mode, "victoriametrics"))).toBe(true);
|
||||
expect(filterModeIsSupportedForDatabase("equals", "postgres")).toBe(true);
|
||||
|
||||
@@ -190,7 +190,7 @@ export function normalizeColumnFormatter(value: unknown): ColumnFormatterConfig
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const FOREIGN_KEY_DISPLAY_FILTER_MODES = new Set<DataGridContextFilterMode>(["equals", "not-equals", "is-null", "is-not-null", "like", "not-like", "less-than", "less-than-or-equal", "greater-than", "greater-than-or-equal", "in", "not-in", "between", "not-between"]);
|
||||
const FOREIGN_KEY_DISPLAY_FILTER_MODES = new Set<DataGridContextFilterMode>(["equals", "not-equals", "is-null", "is-not-null", "is-blank", "is-not-blank", "like", "not-like", "less-than", "less-than-or-equal", "greater-than", "greater-than-or-equal", "in", "not-in", "between", "not-between"]);
|
||||
|
||||
function normalizeForeignKeyDisplayFilter(value: unknown): ForeignKeyDisplayFilterConfig | undefined {
|
||||
if (!value || typeof value !== "object") return undefined;
|
||||
@@ -200,7 +200,7 @@ function normalizeForeignKeyDisplayFilter(value: unknown): ForeignKeyDisplayFilt
|
||||
const mode = filter.mode as DataGridContextFilterMode;
|
||||
const rawValue = typeof filter.value === "string" ? filter.value.trim() : "";
|
||||
const rawEndValue = typeof filter.endValue === "string" ? filter.endValue.trim() : "";
|
||||
if (mode !== "is-null" && mode !== "is-not-null" && !rawValue) return undefined;
|
||||
if (mode !== "is-null" && mode !== "is-not-null" && mode !== "is-blank" && mode !== "is-not-blank" && !rawValue) return undefined;
|
||||
if ((mode === "between" || mode === "not-between") && !rawEndValue) return undefined;
|
||||
return {
|
||||
column: filter.column.trim(),
|
||||
|
||||
@@ -172,7 +172,7 @@ export function combineWhereInputs(manualWhereInput?: string, structuredWhereInp
|
||||
}
|
||||
|
||||
export function filterModeNeedsValue(mode: DataGridContextFilterMode): boolean {
|
||||
return mode !== "is-null" && mode !== "is-not-null";
|
||||
return mode !== "is-null" && mode !== "is-not-null" && mode !== "is-blank" && mode !== "is-not-blank";
|
||||
}
|
||||
|
||||
export function filterModeUsesList(mode: DataGridContextFilterMode): boolean {
|
||||
|
||||
@@ -58,7 +58,7 @@ export interface DataGridCopyInsertStatementOptions {
|
||||
insertMode?: DataGridCopyInsertMode;
|
||||
}
|
||||
|
||||
export type DataGridContextFilterMode = "equals" | "not-equals" | "is-null" | "is-not-null" | "like" | "not-like" | "less-than" | "less-than-or-equal" | "greater-than" | "greater-than-or-equal" | "in" | "not-in" | "between" | "not-between";
|
||||
export type DataGridContextFilterMode = "equals" | "not-equals" | "is-null" | "is-not-null" | "is-blank" | "is-not-blank" | "like" | "not-like" | "less-than" | "less-than-or-equal" | "greater-than" | "greater-than-or-equal" | "in" | "not-in" | "between" | "not-between";
|
||||
|
||||
export interface DataGridContextFilterConditionOptions {
|
||||
databaseType?: DatabaseType;
|
||||
|
||||
Reference in new issue
Block a user