refactor(editor): rename useFieldValueStore, and write down what it captures
I claimed field values could only ever exist for logs streams, and repeated it after being questioned. Wrong twice over: the sidebar path captureFromValuesApi is reached from logs, traces AND pipeline, and captureFromSearchHits captures under whichever stream type the Logs page searched -- its selector covers metrics and traces. Proved by searching cache_hit_ratio in the Logs UI, after which the store held 21 metrics keys and the SLO form resolved environment -> [development, staging]. Two names made that easy to get wrong, so both are fixed rather than just apologised for: useFieldValueStore.ts -> fieldValueStore.ts It is not a composable -- plain functions over IndexedDB, no reactive state -- and the false `use` prefix left it one character from useFieldValuesStream, which IS a composable and does something else entirely. Dropping the prefix also puts it next to its sibling fieldValueDB.ts, where it belongs. The header now names BOTH writers, states that neither is tied to a stream type, and spells out the trap directly: composables/useLogs/ is the Logs PAGE, not the logs stream TYPE. StreamContext.streamType says the same at the field level -- part of the key, never a filter on what may be captured. The rule worth remembering: values come from what has been SEARCHED or EXPANDED. A stream nobody has looked at has none. That is a cold cache, not a missing capability -- which is exactly the distinction I failed to make, off one grep. Mechanical rename across 10 files including the vi.mock paths. 140 passing in the touched specs; type-check, prettier clean; the 13 eslint warnings in IndexList.vue are pre-existing (identical count with this change stashed).
This commit is contained in:
parent
4d231b9e48
commit
449e2d2dda
|
|
@ -634,7 +634,7 @@ describe("QueryEditorDialog - N1 context keywords reach the editor", () => {
|
|||
|
||||
// Stored field values for the N1 value-context probe above. Only useSuggestions
|
||||
// consumes this module, so mocking it does not affect the rest of the suite.
|
||||
vi.mock("@/composables/useFieldValueStore", () => ({
|
||||
vi.mock("@/composables/fieldValueStore", () => ({
|
||||
getFieldValuesForSuggestion: vi.fn().mockResolvedValue(["error", "warn"]),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -2128,6 +2128,6 @@ describe("QueryConfig.vue", () => {
|
|||
|
||||
// Stored field values for the N1 value-context probe above. Only useSuggestions
|
||||
// consumes this module, so mocking it does not affect the rest of the suite.
|
||||
vi.mock("@/composables/useFieldValueStore", () => ({
|
||||
vi.mock("@/composables/fieldValueStore", () => ({
|
||||
getFieldValuesForSuggestion: vi.fn().mockResolvedValue(["error", "warn"]),
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ vi.mock("@/services/stream", () => ({
|
|||
const { getFieldValuesForSuggestion } = vi.hoisted(() => ({
|
||||
getFieldValuesForSuggestion: vi.fn(async () => ["ERROR", "INFO"]),
|
||||
}));
|
||||
vi.mock("@/composables/useFieldValueStore", () => ({ getFieldValuesForSuggestion }));
|
||||
vi.mock("@/composables/fieldValueStore", () => ({ getFieldValuesForSuggestion }));
|
||||
|
||||
vi.mock("@/components/dashboards/PanelSchemaRenderer.vue", () => ({
|
||||
default: { template: '<div data-test="panel-schema-renderer" />' },
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import {
|
|||
captureFromSearchHits,
|
||||
captureFromValuesApi,
|
||||
getFieldValuesForSuggestion,
|
||||
} from "./useFieldValueStore";
|
||||
} from "./fieldValueStore";
|
||||
|
||||
const ctx = { org: "myorg", streamType: "logs", streamName: "http_logs" };
|
||||
|
||||
|
|
@ -14,9 +14,22 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Composable that orchestrates field value capture from both data sources:
|
||||
* 1. Values API — field expansion in FieldList
|
||||
* 2. Search result hits — Run Query results
|
||||
* Persisted field VALUES, for autocomplete. Not a composable — plain functions
|
||||
* over IndexedDB, which is why it carries no `use` prefix and sits beside
|
||||
* fieldValueDB.ts. (It was `useFieldValueStore`, one character from the real
|
||||
* composable `useFieldValuesStream`, and the two were mistaken for each other.)
|
||||
*
|
||||
* THE ONLY TWO WRITERS, and neither is tied to a stream type:
|
||||
* 1. captureFromValuesApi — expanding a field in the sidebar. Reached from
|
||||
* logs, traces and pipeline, via useFieldValuesStream.
|
||||
* 2. captureFromSearchHits — Run Query results. Its one caller lives under
|
||||
* composables/useLogs/, which is the Logs PAGE, not the logs stream TYPE:
|
||||
* it captures under whichever type was searched, and that page's stream
|
||||
* selector covers metrics and traces too.
|
||||
*
|
||||
* So the rule is "values come from what has been SEARCHED or EXPANDED", never
|
||||
* "values are logs-only". A stream nobody has looked at yet simply has none;
|
||||
* that is a cold cache, not a missing capability.
|
||||
*
|
||||
* All IndexedDB writes are scheduled via requestIdleCallback so they have
|
||||
* zero impact on main-thread rendering. Reads use an in-memory cache
|
||||
|
|
@ -52,7 +65,12 @@ const READ_CACHE_MAX_ENTRIES = 500;
|
|||
|
||||
export interface StreamContext {
|
||||
org: string;
|
||||
streamType: string; // 'logs' | 'metrics' | 'traces'
|
||||
/**
|
||||
* Whichever type the caller searched or expanded — all three are stored and
|
||||
* read back the same way. Part of the key, never a filter on what may be
|
||||
* captured.
|
||||
*/
|
||||
streamType: "logs" | "metrics" | "traces" | (string & {});
|
||||
streamName: string;
|
||||
}
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ import { ref, type Ref } from "vue";
|
|||
import store from "@/stores";
|
||||
import { generateTraceContext } from "@/utils/zincutils";
|
||||
import useHttpStreaming from "@/composables/useStreamingSearch";
|
||||
import { captureFromValuesApi } from "@/composables/useFieldValueStore";
|
||||
import { captureFromValuesApi } from "@/composables/fieldValueStore";
|
||||
|
||||
export interface FieldValueEntry {
|
||||
key: string;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import config from "@/aws-exports";
|
|||
import { searchState } from "@/composables/useLogs/searchState";
|
||||
import useStreams from "@/composables/useStreams";
|
||||
import useSqlSuggestions from "@/composables/useSuggestions";
|
||||
import { captureFromSearchHits } from "@/composables/useFieldValueStore";
|
||||
import { captureFromSearchHits } from "@/composables/fieldValueStore";
|
||||
|
||||
import {
|
||||
useLocalLogFilterField,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ vi.mock("vuex", async (importOriginal) => {
|
|||
return { ...actual, useStore: vi.fn(() => mockStore) };
|
||||
});
|
||||
|
||||
vi.mock("@/composables/useFieldValueStore", () => ({
|
||||
vi.mock("@/composables/fieldValueStore", () => ({
|
||||
getFieldValuesForSuggestion: vi.fn().mockResolvedValue([]),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ vi.mock("vuex", async (importOriginal) => {
|
|||
});
|
||||
|
||||
// ─── Mock IDB so no real storage is touched ───────────────────────────────────
|
||||
vi.mock("@/composables/useFieldValueStore", () => ({
|
||||
vi.mock("@/composables/fieldValueStore", () => ({
|
||||
getFieldValuesForSuggestion: vi.fn().mockResolvedValue([]),
|
||||
}));
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ vi.mock("@/services/query_functions", () => ({
|
|||
default: { list: vi.fn().mockResolvedValue({ data: { list: [] } }) },
|
||||
}));
|
||||
|
||||
import { getFieldValuesForSuggestion } from "@/composables/useFieldValueStore";
|
||||
import { getFieldValuesForSuggestion } from "@/composables/fieldValueStore";
|
||||
import useSqlSuggestions from "./useSuggestions";
|
||||
|
||||
// ─── helper: build composable with common defaults ────────────────────────────
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { ref, computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { getFieldValuesForSuggestion } from "@/composables/useFieldValueStore";
|
||||
import { getFieldValuesForSuggestion } from "@/composables/fieldValueStore";
|
||||
import {
|
||||
SQL_KEYWORDS,
|
||||
SQL_CLAUSE_KEYWORDS,
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ import OSelect from "@/lib/forms/Select/OSelect.vue";
|
|||
import type { SelectModelValue } from "@/lib/forms/Select/OSelect.types";
|
||||
import OSkeleton from "@/lib/feedback/Skeleton/OSkeleton.vue";
|
||||
import OEmptyState from "@/lib/core/EmptyState/OEmptyState.vue";
|
||||
import { captureFromValuesApi } from "@/composables/useFieldValueStore";
|
||||
import { captureFromValuesApi } from "@/composables/fieldValueStore";
|
||||
import { saveLogsStreamType, saveLogsStream } from "@/utils/streamPersist";
|
||||
import { quoteSqlIdentifierIfNeeded } from "@/utils/query/sqlIdentifiers";
|
||||
import { toast } from "@/lib/feedback/Toast/useToast";
|
||||
|
|
|
|||
Loading…
Reference in New Issue