mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
refactor: Update JSONFunctions and Table component to support custom classNames
This commit is contained in:
@@ -15,6 +15,13 @@ export default class JSONFunctions {
|
||||
return sizeToGb;
|
||||
}
|
||||
|
||||
public static isJSONObjectDifferent(
|
||||
obj1: JSONObject,
|
||||
obj2: JSONObject,
|
||||
): boolean {
|
||||
return JSON.stringify(obj1) !== JSON.stringify(obj2);
|
||||
}
|
||||
|
||||
public static nestJson(obj: JSONObject): JSONObject {
|
||||
// obj could be in this format:
|
||||
|
||||
|
||||
@@ -619,6 +619,12 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
||||
setIsFilterFetchLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchItems().catch((err: Error) => {
|
||||
setError(API.getFriendlyMessage(err));
|
||||
});
|
||||
}, [props.query]);
|
||||
|
||||
const fetchAllBulkItems: PromiseVoidFunction = async (): Promise<void> => {
|
||||
setError("");
|
||||
setIsLoading(true);
|
||||
@@ -1260,6 +1266,11 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
||||
onFilterChanged={(filterData: FilterData<TBaseModel>) => {
|
||||
onFilterChanged(filterData);
|
||||
}}
|
||||
className={
|
||||
props.cardProps
|
||||
? ""
|
||||
: "rounded-lg border-2 border-gray-200 p-6 pt-0 pb-0"
|
||||
}
|
||||
onFilterRefreshClick={async () => {
|
||||
await getFilterDropdownItems();
|
||||
}}
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface ComponentProps<T extends GenericObject> {
|
||||
data: Array<T>;
|
||||
id: string;
|
||||
columns: Columns<T>;
|
||||
|
||||
className?: string;
|
||||
disablePagination?: undefined | boolean;
|
||||
onNavigateToPage: (pageNumber: number, itemsOnPage: number) => void;
|
||||
currentPageNumber: number;
|
||||
@@ -200,7 +200,7 @@ const Table: TableFunction = <T extends GenericObject>(
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={props.className}>
|
||||
<FilterViewer
|
||||
id={`${props.id}-filter`}
|
||||
showFilterModal={props.showFilterModal || false}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import MonitorStepTraceMonitor from "Common/Types/Monitor/MonitorStepTraceMonitor";
|
||||
import TelemetryService from "Common/Models/DatabaseModels/TelemetryService";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import React, { FunctionComponent, ReactElement, useEffect } from "react";
|
||||
import BasicForm from "Common/UI/Components/Forms/BasicForm";
|
||||
import DropdownUtil from "Common/UI/Utils/Dropdown";
|
||||
import FormFieldSchemaType from "Common/UI/Components/Forms/Types/FormFieldSchemaType";
|
||||
import Button, { ButtonStyleType } from "Common/UI/Components/Button/Button";
|
||||
import FieldLabelElement from "Common/UI/Components/Forms/Fields/FieldLabel";
|
||||
import HorizontalRule from "Common/UI/Components/HorizontalRule/HorizontalRule";
|
||||
import TraceMonitorPreview from "../../../Monitor/TraceMonitor/TraceMonitorPreview";
|
||||
import { SpanStatus } from "Common/Models/AnalyticsModels/Span";
|
||||
import SpanUtil from "../../../../Utils/SpanUtil";
|
||||
|
||||
export interface ComponentProps {
|
||||
monitorStepTraceMonitor: MonitorStepTraceMonitor;
|
||||
@@ -23,14 +22,19 @@ const TraceMonitorStepForm: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
const [monitorStepTraceMonitor, setMonitorStepTraceMonitor] =
|
||||
React.useState<MonitorStepTraceMonitor>(props.monitorStepTraceMonitor);
|
||||
React.useState<MonitorStepTraceMonitor | null>(null);
|
||||
|
||||
let showAdvancedOptionsByDefault: boolean = false;
|
||||
|
||||
useEffect(() => {
|
||||
setMonitorStepTraceMonitor(props.monitorStepTraceMonitor);
|
||||
}, [props.monitorStepTraceMonitor]);
|
||||
|
||||
if (
|
||||
monitorStepTraceMonitor.attributes ||
|
||||
monitorStepTraceMonitor.spanStatuses ||
|
||||
monitorStepTraceMonitor.telemetryServiceIds
|
||||
monitorStepTraceMonitor &&
|
||||
(monitorStepTraceMonitor.attributes ||
|
||||
monitorStepTraceMonitor.spanStatuses ||
|
||||
monitorStepTraceMonitor.telemetryServiceIds)
|
||||
) {
|
||||
showAdvancedOptionsByDefault = true;
|
||||
}
|
||||
@@ -121,8 +125,7 @@ const TraceMonitorStepForm: FunctionComponent<ComponentProps> = (
|
||||
field: {
|
||||
spanStatuses: true,
|
||||
},
|
||||
dropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(SpanStatus),
|
||||
dropdownOptions: SpanUtil.getSpanStatusDropdownOptions(),
|
||||
fieldType: FormFieldSchemaType.MultiSelectDropdown,
|
||||
title: "Filter by Span Status",
|
||||
description: "Select the status of the spans you want to monitor.",
|
||||
@@ -183,7 +186,7 @@ const TraceMonitorStepForm: FunctionComponent<ComponentProps> = (
|
||||
<div>
|
||||
<HorizontalRule />
|
||||
<FieldLabelElement
|
||||
title={"Traces Preview"}
|
||||
title={"Spans Preview"}
|
||||
description={
|
||||
"Here is the preview of the Traces that will be monitored based on the filters you have set above."
|
||||
}
|
||||
@@ -192,7 +195,7 @@ const TraceMonitorStepForm: FunctionComponent<ComponentProps> = (
|
||||
/>
|
||||
<div className="mt-5 mb-5">
|
||||
<TraceMonitorPreview
|
||||
monitorStepTraceMonitor={monitorStepTraceMonitor}
|
||||
monitorStepTraceMonitor={monitorStepTraceMonitor!}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import MonitorStepTraceMonitor, {
|
||||
import TraceTable from "../../Traces/TraceTable";
|
||||
import Query from "Common/Types/BaseDatabase/Query";
|
||||
import Span from "Common/Models/AnalyticsModels/Span";
|
||||
import JSONFunctions from "Common/Types/JSONFunctions";
|
||||
|
||||
export interface ComponentProps {
|
||||
monitorStepTraceMonitor: MonitorStepTraceMonitor | undefined;
|
||||
@@ -25,10 +26,14 @@ const TraceMonitorPreview: FunctionComponent<ComponentProps> = (
|
||||
const [spanQuery, setSpanQuery] = React.useState<Query<Span>>(refreshQuery());
|
||||
|
||||
useEffect(() => {
|
||||
setSpanQuery(refreshQuery());
|
||||
const query: Query<Span> = refreshQuery();
|
||||
|
||||
if (JSONFunctions.isJSONObjectDifferent(spanQuery, query)) {
|
||||
setSpanQuery(query);
|
||||
}
|
||||
}, [props.monitorStepTraceMonitor]);
|
||||
|
||||
return <TraceTable spanQuery={spanQuery} />;
|
||||
return <TraceTable isMinimalTable={true} spanQuery={spanQuery} />;
|
||||
};
|
||||
|
||||
export default TraceMonitorPreview;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { DropdownOption } from "Common/UI/Components/Dropdown/Dropdown";
|
||||
import AnalyticsModelTable from "Common/UI/Components/ModelTable/AnalyticsModelTable";
|
||||
import FieldType from "Common/UI/Components/Types/FieldType";
|
||||
import DropdownUtil from "Common/UI/Utils/Dropdown";
|
||||
import Span, { SpanKind, SpanStatus } from "Common/Models/AnalyticsModels/Span";
|
||||
import Span, { SpanKind } from "Common/Models/AnalyticsModels/Span";
|
||||
import React, {
|
||||
Fragment,
|
||||
FunctionComponent,
|
||||
@@ -27,10 +27,13 @@ import ModelAPI from "Common/UI/Utils/ModelAPI/ModelAPI";
|
||||
import PageLoader from "Common/UI/Components/Loader/PageLoader";
|
||||
import ErrorMessage from "Common/UI/Components/ErrorMessage/ErrorMessage";
|
||||
import Query from "Common/Types/BaseDatabase/Query";
|
||||
import SpanUtil from "../../Utils/SpanUtil";
|
||||
|
||||
export interface ComponentProps {
|
||||
modelId?: ObjectID | undefined;
|
||||
spanQuery?: Query<Span> | undefined;
|
||||
isMinimalTable?: boolean | undefined;
|
||||
noItemsMessage?: string | undefined;
|
||||
}
|
||||
|
||||
const TraceTable: FunctionComponent<ComponentProps> = (
|
||||
@@ -43,6 +46,16 @@ const TraceTable: FunctionComponent<ComponentProps> = (
|
||||
const [isPageLoading, setIsPageLoading] = React.useState<boolean>(true);
|
||||
const [pageError, setPageError] = React.useState<string>("");
|
||||
|
||||
const [spanQuery, setSpanQuery] = React.useState<Query<Span> | null>(
|
||||
props.spanQuery || null,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.spanQuery) {
|
||||
setSpanQuery(props.spanQuery);
|
||||
}
|
||||
}, [props.spanQuery]);
|
||||
|
||||
const loadAttributes: PromiseVoidFunction = async (): Promise<void> => {
|
||||
try {
|
||||
setIsPageLoading(true);
|
||||
@@ -107,137 +120,139 @@ const TraceTable: FunctionComponent<ComponentProps> = (
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<AnalyticsModelTable<Span>
|
||||
modelType={Span}
|
||||
id="traces-table"
|
||||
isDeleteable={false}
|
||||
isEditable={false}
|
||||
isCreateable={false}
|
||||
singularName="Trace"
|
||||
pluralName="Traces"
|
||||
name="Traces"
|
||||
isViewable={true}
|
||||
cardProps={{
|
||||
title: "Traces",
|
||||
description:
|
||||
"Traces are the individual spans that make up a request. They are the building blocks of a trace and represent the work done by a single service.",
|
||||
}}
|
||||
query={{
|
||||
projectId: DashboardNavigation.getProjectId(),
|
||||
serviceId: modelId ? modelId : undefined,
|
||||
...props.spanQuery,
|
||||
}}
|
||||
showViewIdButton={true}
|
||||
noItemsMessage={"No traces found for this service."}
|
||||
showRefreshButton={true}
|
||||
sortBy="startTime"
|
||||
sortOrder={SortOrder.Descending}
|
||||
onViewPage={(span: Span) => {
|
||||
return Promise.resolve(
|
||||
new Route(viewRoute.toString()).addRoute(span.traceId!.toString()),
|
||||
);
|
||||
}}
|
||||
filters={[
|
||||
{
|
||||
field: {
|
||||
traceId: true,
|
||||
<div className="rounded">
|
||||
<AnalyticsModelTable<Span>
|
||||
disablePagination={true}
|
||||
modelType={Span}
|
||||
id="traces-table"
|
||||
isDeleteable={false}
|
||||
isEditable={false}
|
||||
isCreateable={false}
|
||||
singularName="Trace"
|
||||
pluralName="Traces"
|
||||
name="Traces"
|
||||
isViewable={true}
|
||||
cardProps={
|
||||
props.isMinimalTable
|
||||
? undefined
|
||||
: {
|
||||
title: "Traces",
|
||||
description:
|
||||
"Traces are the individual spans that make up a request. They are the building blocks of a trace and represent the work done by a single service.",
|
||||
}
|
||||
}
|
||||
query={{
|
||||
projectId: DashboardNavigation.getProjectId(),
|
||||
serviceId: modelId ? modelId : undefined,
|
||||
...spanQuery,
|
||||
}}
|
||||
showViewIdButton={true}
|
||||
noItemsMessage={
|
||||
props.noItemsMessage ? props.noItemsMessage : "No traces found."
|
||||
}
|
||||
showRefreshButton={true}
|
||||
sortBy="startTime"
|
||||
sortOrder={SortOrder.Descending}
|
||||
onViewPage={(span: Span) => {
|
||||
return Promise.resolve(
|
||||
new Route(viewRoute.toString()).addRoute(
|
||||
span.traceId!.toString(),
|
||||
),
|
||||
);
|
||||
}}
|
||||
filters={[
|
||||
{
|
||||
field: {
|
||||
traceId: true,
|
||||
},
|
||||
type: FieldType.Text,
|
||||
title: "Trace ID",
|
||||
},
|
||||
type: FieldType.Text,
|
||||
title: "Trace ID",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
statusCode: true,
|
||||
{
|
||||
field: {
|
||||
statusCode: true,
|
||||
},
|
||||
type: FieldType.Dropdown,
|
||||
filterDropdownOptions: SpanUtil.getSpanStatusDropdownOptions(),
|
||||
title: "Span Status",
|
||||
},
|
||||
type: FieldType.Dropdown,
|
||||
filterDropdownOptions: DropdownUtil.getDropdownOptionsFromEnum(
|
||||
SpanStatus,
|
||||
true,
|
||||
).filter((dropdownOption: DropdownOption) => {
|
||||
return (
|
||||
dropdownOption.label === "Unset" ||
|
||||
dropdownOption.label === "Ok" ||
|
||||
dropdownOption.label === "Error"
|
||||
);
|
||||
}),
|
||||
title: "Span Status",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
type: FieldType.Text,
|
||||
title: "Span Name",
|
||||
},
|
||||
type: FieldType.Text,
|
||||
title: "Span Name",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
kind: true,
|
||||
{
|
||||
field: {
|
||||
kind: true,
|
||||
},
|
||||
type: FieldType.Text,
|
||||
title: "Span Kind",
|
||||
filterDropdownOptions: spanKindDropdownOptions,
|
||||
},
|
||||
type: FieldType.Text,
|
||||
title: "Span Kind",
|
||||
filterDropdownOptions: spanKindDropdownOptions,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
startTime: true,
|
||||
{
|
||||
field: {
|
||||
startTime: true,
|
||||
},
|
||||
type: FieldType.DateTime,
|
||||
title: "Seen At",
|
||||
},
|
||||
type: FieldType.DateTime,
|
||||
title: "Seen At",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
attributes: true,
|
||||
{
|
||||
field: {
|
||||
attributes: true,
|
||||
},
|
||||
type: FieldType.JSON,
|
||||
title: "Attributes",
|
||||
jsonKeys: attributes,
|
||||
},
|
||||
type: FieldType.JSON,
|
||||
title: "Attributes",
|
||||
jsonKeys: attributes,
|
||||
},
|
||||
]}
|
||||
selectMoreFields={{
|
||||
statusCode: true,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
spanId: true,
|
||||
]}
|
||||
selectMoreFields={{
|
||||
statusCode: true,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
spanId: true,
|
||||
},
|
||||
title: "Span ID",
|
||||
type: FieldType.Element,
|
||||
getElement: (span: Span): ReactElement => {
|
||||
return (
|
||||
<Fragment>
|
||||
<SpanStatusElement
|
||||
traceId={span.traceId?.toString()}
|
||||
spanStatusCode={span.statusCode!}
|
||||
title={span.spanId?.toString()}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
},
|
||||
},
|
||||
title: "Span ID",
|
||||
type: FieldType.Element,
|
||||
getElement: (span: Span): ReactElement => {
|
||||
return (
|
||||
<Fragment>
|
||||
<SpanStatusElement
|
||||
traceId={span.traceId?.toString()}
|
||||
spanStatusCode={span.statusCode!}
|
||||
title={span.spanId?.toString()}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
{
|
||||
field: {
|
||||
traceId: true,
|
||||
},
|
||||
title: "Trace ID",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
traceId: true,
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: "Span Name",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
title: "Trace ID",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
{
|
||||
field: {
|
||||
startTime: true,
|
||||
},
|
||||
title: "Seen At",
|
||||
type: FieldType.DateTime,
|
||||
},
|
||||
title: "Span Name",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
startTime: true,
|
||||
},
|
||||
title: "Seen At",
|
||||
type: FieldType.DateTime,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Black } from "Common/Types/BrandColors";
|
||||
import Color from "Common/Types/Color";
|
||||
import Span, { SpanKind, SpanStatus } from "Common/Models/AnalyticsModels/Span";
|
||||
import TelemetryService from "Common/Models/DatabaseModels/TelemetryService";
|
||||
import { DropdownOption } from "Common/UI/Components/Dropdown/Dropdown";
|
||||
import DropdownUtil from "Common/UI/Utils/Dropdown";
|
||||
|
||||
export enum IntervalUnit {
|
||||
Nanoseconds = "ns",
|
||||
@@ -16,6 +18,18 @@ export interface DivisibilityFactor {
|
||||
}
|
||||
|
||||
export default class SpanUtil {
|
||||
public static getSpanStatusDropdownOptions(): Array<DropdownOption> {
|
||||
return DropdownUtil.getDropdownOptionsFromEnum(SpanStatus, true).filter(
|
||||
(dropdownOption: DropdownOption) => {
|
||||
return (
|
||||
dropdownOption.label === "Unset" ||
|
||||
dropdownOption.label === "Ok" ||
|
||||
dropdownOption.label === "Error"
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public static getSpanDurationAsString(data: {
|
||||
divisibilityFactor: DivisibilityFactor;
|
||||
spanDurationInUnixNano: number;
|
||||
|
||||
Reference in New Issue
Block a user