feat(grid): show column comments in condition suggestions
This commit is contained in:
7 files changed
+174
-21
No files matched your search
@@ -41,6 +41,64 @@ describe("useDataGridConditionEditor", () => {
|
||||
expect(value.value).toBe("status = customer_name");
|
||||
});
|
||||
|
||||
it("reuses column comments for field suggestions without adding them to history", async () => {
|
||||
const scope = { connectionId: "connection", database: "db", tableName: "users" };
|
||||
rememberDataGridConditionHistory("where", scope, "customer_id = 1");
|
||||
const value = ref("");
|
||||
const editor = useDataGridConditionEditor({
|
||||
kind: "where",
|
||||
value,
|
||||
columns: [
|
||||
{ name: "customer_id", comment: "客户编号" },
|
||||
{ name: "customer_name", comment: null },
|
||||
],
|
||||
historyScope: scope,
|
||||
});
|
||||
|
||||
value.value = "cust";
|
||||
await nextTick();
|
||||
await vi.waitFor(() =>
|
||||
expect(editor.suggestions.value).toEqual([
|
||||
{ value: "customer_id", kind: "column", comment: "客户编号" },
|
||||
{ value: "customer_name", kind: "column" },
|
||||
]),
|
||||
);
|
||||
|
||||
value.value = "customer";
|
||||
editor.dismiss();
|
||||
editor.openHistory();
|
||||
expect(editor.suggestions.value).toEqual([{ value: "customer_id = 1", kind: "history" }]);
|
||||
});
|
||||
|
||||
it.each(["where", "orderBy"] as const)("normalizes %s comments from different metadata providers", async (kind) => {
|
||||
const value = ref("");
|
||||
const editor = useDataGridConditionEditor({
|
||||
kind,
|
||||
value,
|
||||
columns: [
|
||||
"customer_plain",
|
||||
{ name: "customer_native", comment: " 原生注释 " },
|
||||
{ name: "customer_jdbc", comment: "JDBC remarks" },
|
||||
{ name: "customer_null", comment: null },
|
||||
{ name: "customer_blank", comment: " \n\t " },
|
||||
{ name: "customer_invalid", comment: 42 } as unknown as { name: string; comment: string },
|
||||
],
|
||||
historyScope: {},
|
||||
});
|
||||
|
||||
value.value = "cust";
|
||||
await nextTick();
|
||||
await vi.waitFor(() => expect(editor.suggestions.value).toHaveLength(6));
|
||||
expect(editor.suggestions.value).toEqual([
|
||||
{ value: "customer_plain", kind: "column" },
|
||||
{ value: "customer_native", kind: "column", comment: "原生注释" },
|
||||
{ value: "customer_jdbc", kind: "column", comment: "JDBC remarks" },
|
||||
{ value: "customer_null", kind: "column" },
|
||||
{ value: "customer_blank", kind: "column" },
|
||||
{ value: "customer_invalid", kind: "column" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("ignores stale asynchronous suggestion responses", async () => {
|
||||
vi.useFakeTimers();
|
||||
const value = ref("");
|
||||
|
||||
@@ -3,9 +3,17 @@ import { forgetDataGridConditionHistory, loadDataGridConditionHistory, rememberD
|
||||
|
||||
export type DataGridConditionSuggestionKind = "column" | "history";
|
||||
|
||||
export interface DataGridConditionColumnSuggestion {
|
||||
name: string;
|
||||
comment?: string | null;
|
||||
}
|
||||
|
||||
export type DataGridConditionColumnOption = string | DataGridConditionColumnSuggestion;
|
||||
|
||||
export interface DataGridConditionSuggestion {
|
||||
value: string;
|
||||
kind: DataGridConditionSuggestionKind;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
export interface DataGridConditionSuggestionContext {
|
||||
@@ -20,7 +28,7 @@ export type DataGridConditionSuggestionProvider = (context: DataGridConditionSug
|
||||
export interface UseDataGridConditionEditorOptions {
|
||||
kind: DataGridConditionHistoryKind;
|
||||
value: Ref<string>;
|
||||
columns?: MaybeRefOrGetter<readonly string[] | undefined>;
|
||||
columns?: MaybeRefOrGetter<readonly DataGridConditionColumnOption[] | undefined>;
|
||||
historyScope: MaybeRefOrGetter<DataGridConditionHistoryScope>;
|
||||
suggestionProvider?: DataGridConditionSuggestionProvider;
|
||||
suggestionDebounceMs?: number;
|
||||
@@ -30,6 +38,11 @@ export interface UseDataGridConditionEditorOptions {
|
||||
const WHERE_TOKEN_PATTERN = /([^\s,()><=!&|]+)$/;
|
||||
const ORDER_BY_TOKEN_PATTERN = /([^\s,()]+)$/;
|
||||
|
||||
function normalizedColumnComment(column: DataGridConditionColumnOption): string | undefined {
|
||||
if (typeof column === "string" || typeof column.comment !== "string") return undefined;
|
||||
return column.comment.trim() || undefined;
|
||||
}
|
||||
|
||||
function activeToken(kind: DataGridConditionHistoryKind, value: string): string {
|
||||
return (
|
||||
value
|
||||
@@ -73,10 +86,20 @@ export function useDataGridConditionEditor(options: UseDataGridConditionEditorOp
|
||||
historyOpen.value = false;
|
||||
}
|
||||
|
||||
function defaultSuggestions(token: string): readonly string[] {
|
||||
function defaultSuggestions(token: string): DataGridConditionSuggestion[] {
|
||||
const normalizedToken = token.toLowerCase();
|
||||
if (!normalizedToken) return [];
|
||||
return (toValue(options.columns) ?? []).filter((column) => column.toLowerCase().startsWith(normalizedToken) && column.toLowerCase() !== normalizedToken);
|
||||
const seen = new Set<string>();
|
||||
const suggestions: DataGridConditionSuggestion[] = [];
|
||||
for (const column of toValue(options.columns) ?? []) {
|
||||
const value = typeof column === "string" ? column : column.name;
|
||||
const normalizedValue = value.toLowerCase();
|
||||
if (!normalizedValue.startsWith(normalizedToken) || normalizedValue === normalizedToken || seen.has(value)) continue;
|
||||
seen.add(value);
|
||||
const comment = normalizedColumnComment(column);
|
||||
suggestions.push({ value, kind: "column", ...(comment ? { comment } : {}) });
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
async function loadSuggestions(value: string, requestId: number, controller: AbortController) {
|
||||
@@ -84,11 +107,11 @@ export function useDataGridConditionEditor(options: UseDataGridConditionEditorOp
|
||||
if (!token) return;
|
||||
suggestionsLoading.value = true;
|
||||
try {
|
||||
const values = options.suggestionProvider ? await options.suggestionProvider({ kind: options.kind, value, token, signal: controller.signal }) : defaultSuggestions(token);
|
||||
const values = options.suggestionProvider ? await options.suggestionProvider({ kind: options.kind, value, token, signal: controller.signal }) : undefined;
|
||||
// A slower request must never replace suggestions for a newer editor value.
|
||||
if (controller.signal.aborted || requestId !== suggestionRequestId || options.value.value !== value || historyOpen.value) return;
|
||||
const limit = options.suggestionLimit ?? 8;
|
||||
suggestions.value = [...new Set(values)].slice(0, limit).map((suggestion) => ({ value: suggestion, kind: "column" }));
|
||||
suggestions.value = values ? [...new Set(values)].slice(0, limit).map((suggestion) => ({ value: suggestion, kind: "column" })) : defaultSuggestions(token).slice(0, limit);
|
||||
highlightedIndex.value = suggestions.value.length > 0 ? 0 : -1;
|
||||
} catch (error) {
|
||||
if (!controller.signal.aborted && requestId === suggestionRequestId) {
|
||||
|
||||
Reference in new issue
Block a user