diff --git a/src/assets/icons/download.svg b/src/assets/icons/download.svg new file mode 100644 index 00000000..6c138a32 --- /dev/null +++ b/src/assets/icons/download.svg @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/src/components/TimePicker.vue b/src/components/TimePicker.vue index 422d0644..c762e021 100755 --- a/src/components/TimePicker.vue +++ b/src/components/TimePicker.vue @@ -310,6 +310,9 @@ limitations under the License. --> break; } dates.value = [start, end]; + if (!props.showButtons) { + ok(true); + } }; const submit = () => { inputDates.value = dates.value; diff --git a/src/graphql/fragments/trace.ts b/src/graphql/fragments/trace.ts index 58c28f30..0aac354d 100644 --- a/src/graphql/fragments/trace.ts +++ b/src/graphql/fragments/trace.ts @@ -163,3 +163,73 @@ export const TraceSpansFromColdStage = { } `, }; +export const HasQueryTracesV2Support = { + query: ` + hasQueryTracesV2Support + `, +}; + +export const QueryV2Traces = { + variable: "$condition: TraceQueryCondition", + query: ` + queryTraces(condition: $condition) { + traces { + spans { + traceId + segmentId + spanId + parentSpanId + refs { + traceId + parentSegmentId + parentSpanId + type + } + serviceCode + serviceInstanceName + startTime + endTime + endpointName + type + peer + component + isError + layer + tags { + key + value + } + logs { + time + data { + key + value + } + } + attachedEvents { + startTime { + seconds + nanos + } + event + endTime { + seconds + nanos + } + tags { + key + value + } + summary { + key + value + } + } + } + } + retrievedTimeRange { + startTime + endTime + } + }`, +}; diff --git a/src/graphql/http/index.ts b/src/graphql/http/index.ts index d9825404..f09f1241 100644 --- a/src/graphql/http/index.ts +++ b/src/graphql/http/index.ts @@ -17,11 +17,45 @@ import { httpQuery } from "../base"; import { HttpURL } from "./url"; -export default async function fetchQuery({ method, json, path }: { method: string; json?: unknown; path: string }) { +export default async function fetchQuery({ + method, + json, + path, +}: { + method: string; + json?: Record; + path: string; +}) { + const upperMethod = method.toUpperCase(); + let url = (HttpURL as Record)[path]; + let body: unknown | undefined = json; + + if (upperMethod === "GET" && json && typeof json === "object") { + const params = new URLSearchParams(); + const stringifyValue = (val: unknown): string => { + if (val instanceof Date) return val.toISOString(); + if (typeof val === "object") return JSON.stringify(val); + return String(val); + }; + for (const [key, value] of Object.entries(json)) { + if (value === undefined || value === null) continue; + if (Array.isArray(value)) { + for (const v of value as unknown[]) params.append(key, stringifyValue(v)); + continue; + } + params.append(key, stringifyValue(value)); + } + const queryString = params.toString(); + if (queryString) { + url += (url.includes("?") ? "&" : "?") + queryString; + } + body = undefined; + } + const response = await httpQuery({ - method, - json, - url: (HttpURL as { [key: string]: string })[path], + method: upperMethod, + json: body, + url, }); if (response.errors) { response.errors = response.errors.map((e: { message: string }) => e.message).join(" "); diff --git a/src/graphql/query/trace.ts b/src/graphql/query/trace.ts index 77b1dfe3..eac2bfdd 100644 --- a/src/graphql/query/trace.ts +++ b/src/graphql/query/trace.ts @@ -15,7 +15,15 @@ * limitations under the License. */ -import { Traces, TraceSpans, TraceTagKeys, TraceTagValues, TraceSpansFromColdStage } from "../fragments/trace"; +import { + Traces, + TraceSpans, + TraceTagKeys, + TraceTagValues, + TraceSpansFromColdStage, + HasQueryTracesV2Support, + QueryV2Traces, +} from "../fragments/trace"; export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`; @@ -26,3 +34,7 @@ export const queryTraceTagKeys = `query queryTraceTagKeys(${TraceTagKeys.variabl export const queryTraceTagValues = `query queryTraceTagValues(${TraceTagValues.variable}) {${TraceTagValues.query}}`; export const queryTraceSpansFromColdStage = `query queryTraceSpansFromColdStage(${TraceSpansFromColdStage.variable}) {${TraceSpansFromColdStage.query}}`; + +export const queryHasQueryTracesV2Support = `query queryHasQueryTracesV2Support {${HasQueryTracesV2Support.query}}`; + +export const queryV2Traces = `query queryV2Traces(${QueryV2Traces.variable}) {${QueryV2Traces.query}}`; diff --git a/src/layout/components/NavBar.vue b/src/layout/components/NavBar.vue index bf5710cb..7dc6ab75 100644 --- a/src/layout/components/NavBar.vue +++ b/src/layout/components/NavBar.vue @@ -89,6 +89,7 @@ limitations under the License. --> import router from "@/router"; import { useAppStoreWithOut, InitializationDurationRow } from "@/store/modules/app"; import { useDashboardStore } from "@/store/modules/dashboard"; + import { useTraceStore } from "@/store/modules/trace"; import type { DashboardItem } from "@/types/dashboard"; import timeFormat from "@/utils/timeFormat"; import { MetricCatalog } from "@/views/dashboard/data"; @@ -98,10 +99,10 @@ limitations under the License. --> import { useI18n } from "vue-i18n"; import { useRoute } from "vue-router"; - /*global Indexable */ const { t, te } = useI18n(); const appStore = useAppStoreWithOut(); const dashboardStore = useDashboardStore(); + const traceStore = useTraceStore(); const route = useRoute(); const pathNames = ref<{ path?: string; name: string; selected: boolean }[][]>([]); const showTimeRangeTips = ref(false); @@ -124,6 +125,7 @@ limitations under the License. --> getVersion(); getNavPaths(); setTTL(); + traceStore.getHasQueryTracesV2Support(); function changeTheme() { const root = document.documentElement; @@ -391,7 +393,7 @@ limitations under the License. --> } function resetDuration() { - const { duration }: Indexable = route.params; + const { duration } = route.params as { duration: string }; if (duration) { const d = JSON.parse(duration); diff --git a/src/layout/components/SideBar.vue b/src/layout/components/SideBar.vue index 955f847f..73b4c114 100644 --- a/src/layout/components/SideBar.vue +++ b/src/layout/components/SideBar.vue @@ -17,7 +17,7 @@ limitations under the License. -->
-