diff --git a/src/page/Dashboard/FieldBox.js b/src/page/Dashboard/FieldBox.js
new file mode 100644
index 00000000..fa2c21d6
--- /dev/null
+++ b/src/page/Dashboard/FieldBox.js
@@ -0,0 +1,45 @@
+import Checkbox from "../../components/Checkbox";
+
+const Field = ({
+ logStreamSchema,
+ selectedLogSchema,
+ setSelectedLogSchema,
+}) => {
+ return (
+
+
+
Columns
+
+
+ {logStreamSchema?.data?.data?.fields
+ ?.filter((field) => field.name !== "p_metadata" && field.name !== "p_tags")
+ .map((key, index) => (
+
+ e.target.checked
+ ? setSelectedLogSchema(
+ logStreamSchema.data.data.fields
+ .map((x) => x.name)
+ .filter(
+ (schema) =>
+ selectedLogSchema.includes(schema) ||
+ schema === key.name,
+ ),
+ )
+ : setSelectedLogSchema(
+ selectedLogSchema.filter(
+ (clickedName) => clickedName !== key.name,
+ ),
+ )
+ }
+ selected={selectedLogSchema?.includes(key.name)}
+ />
+ ))}
+
+
+ );
+};
+
+export default Field;
diff --git a/src/page/Dashboard/index.js b/src/page/Dashboard/index.js
index 5cfe31d3..7758fdb1 100644
--- a/src/page/Dashboard/index.js
+++ b/src/page/Dashboard/index.js
@@ -1,5 +1,5 @@
import moment from "moment";
-import { useState, Fragment } from "react";
+import { useState, Fragment, useRef, useCallback, useEffect } from "react";
import Layout from "../../components/Layout";
import SideDialog from "../../components/SideDialog";
import { Listbox, Transition } from "@headlessui/react";
@@ -9,9 +9,13 @@ import { Combobox } from "@headlessui/react";
import { CheckIcon, XCircleIcon, SelectorIcon } from "@heroicons/react/solid";
import BeatLoader from "react-spinners/BeatLoader";
import { Menu } from "@headlessui/react";
-import { useGetLogStream, useQueryLogs } from "../../utils/api";
+import {
+ useGetLogStream,
+ useGetLogStreamSchema,
+ useQueryLogs,
+} from "../../utils/api";
import "./index.css";
-import Picker from "./DateTimeRangePicker";
+import Field from "./FieldBox";
import Calendar from "./DateRangeSeletor";
const override = {
@@ -21,6 +25,8 @@ const override = {
};
function hasSubArray(master, sub) {
+ master.sort();
+ sub.sort();
return sub.every(
(
(i) => (v) =>
@@ -28,6 +34,7 @@ function hasSubArray(master, sub) {
)(0),
);
}
+
const Dashboard = () => {
const getCurrentTime = () => {
let now = new Date();
@@ -45,6 +52,7 @@ const Dashboard = () => {
return moment(start);
};
+
const getRange = () => {
return {
// "Live tracking": [moment(start), moment(end)],
@@ -80,13 +88,24 @@ const Dashboard = () => {
const [searchSelected, setSearchSelected] = useState({});
const [interval, setInterval] = useState(null);
const [range, setRange] = useState(0);
- const [dateRangeValues, setDateRangeValues] = useState(getRange);
+ const [selectedLogSchema, setSelectedLogSchema] = useState([]);
+ const [availableTags, setAvailableTags] = useState([]);
+ const [selectedTags, setSelectedTags] = useState([]);
+ // const [dateRangeValues, setDateRangeValues] = useState(getRange);
const [startTime, setStartTime] = useState(
getCurrentTime().subtract(10, "minutes"),
// .utcOffset("+00:00")
// .format("YYYY-MM-DDThh:mm:ss),
);
+ const addAvailableTags = (label) => {
+ if (availableTags.includes(label)) {
+ return;
+ } else {
+ setAvailableTags([...availableTags, label]);
+ }
+ };
+
const [endTime, setEndTime] = useState(getCurrentTime());
const refreshInterval = [
@@ -135,38 +154,73 @@ const Dashboard = () => {
const logStream = useGetLogStream({
retry: false,
- staleTime: 60 * 1000,
refetchOnWindowFocus: false,
+ onSuccess: (data) => {
+ setSelectedLogStream(data.data[0]);
+ },
+ });
+
+ const logStreamSchema = useGetLogStreamSchema(selectedLogStream?.name, {
+ retry: false,
+ enabled: !!(selectedLogStream?.name != null),
+ refetchOnWindowFocus: false,
+ onSuccess: (data) => {
+ const allFields = data.data.fields.map((field) => {
+ return field.name;
+ });
+
+ setSelectedLogSchema([
+ ...allFields.filter(
+ (field) => field !== "p_metadata" && field !== "p_tags",
+ ),
+ ]);
+ },
});
- if (
- logStream.isSuccess &&
- logStream?.data?.data.length &&
- !selectedLogStream
- ) {
- setSelectedLogStream(logStream.data.data[0]);
- }
const logQueries = useQueryLogs(
selectedLogStream?.name,
moment(startTime).utcOffset("+00:00").format("YYYY-MM-DDTHH:mm:ssZ"),
moment(endTime).utcOffset("+00:00").format("YYYY-MM-DDTHH:mm:ssZ"),
+ selectedLogSchema,
() => {
if (range < 7) {
const rangeVal = getRange();
- setDateRangeValues(rangeVal);
setStartTime(rangeVal[rangeArr[range]][0]);
setEndTime(rangeVal[rangeArr[range]][1]);
}
},
{
+ onSuccess: () => {
+ setSelectedTags([]);
+ setAvailableTags([]);
+ },
retry: false,
- enabled: !!(selectedLogStream?.name != null),
+ enabled: !!(selectedLogSchema?.length !== 0),
refetchOnWindowFocus: false,
refetchInterval:
interval === null || range === 7 ? false : interval * 1000,
},
);
+ const { fetchNextPage } = logQueries;
+
+ useEffect(() => {
+ let fetching = false;
+ const handleScroll = async (e) => {
+ const { scrollHeight, scrollTop, clientHeight } =
+ e.target.scrollingElement;
+ if (!fetching && scrollHeight - scrollTop <= clientHeight * 1.2) {
+ fetching = true;
+ await fetchNextPage();
+ fetching = false;
+ }
+ };
+ document.addEventListener("scroll", handleScroll);
+ return () => {
+ document.removeEventListener("scroll", handleScroll);
+ };
+ }, [fetchNextPage]);
+
const timeZoneChange = (e) => {
setTimeZone(e.target.value);
};
@@ -187,21 +241,20 @@ const Dashboard = () => {
}
};
- const clearLabel = (label) => {
- const labelArray = labelSelected;
- const filteredArray = [...labelArray.filter((item) => item !== label)];
- setLabelSelected(filteredArray);
+ const removeTag = (tag) => {
+ setSelectedTags([...selectedTags.filter((item) => item !== tag)]);
};
return (
<>
0 && logQueries?.data?.data[0]?.labels
+ logQueries?.data?.data?.length > 0 &&
+ logQueries?.data?.data[0]?.labels
}
>
-
-
+
+
@@ -341,7 +394,7 @@ const Dashboard = () => {
/>
-
{
))
)}
-
+ */}
@@ -444,7 +497,7 @@ const Dashboard = () => {
}
>
{refreshInterval.map((interval) => (
-
+
{({ active, selected }) => (
setInterval(interval.value)}
@@ -467,18 +520,18 @@ const Dashboard = () => {
Tag filters
- {labelSelected.length > 0
- ? labelSelected.map((label) => (
+ {selectedTags.length > 0
+ ? selectedTags.map((tag) => (
- {label}
+ {tag}
clearLabel(label)}
+ onClick={() => removeTag(tag)}
className="hover:text-gray-600 transform duration-200 text-gray-700 w-4 absolute top-1 right-1"
/>
@@ -498,43 +551,39 @@ const Dashboard = () => {
leaveTo="opacity-0"
>
- {Object.keys(
- logQueries?.data?.data ? logQueries?.data?.data : [],
- ).length !== 0 ? (
- logQueries?.data?.data[0].labels
- ?.split(",")
- .map((person, personIdx) => (
-
- `relative cursor-default select-none py-2 px-2 ${
- active
- ? "bg-bluePrimary text-white"
- : "text-gray-900"
- }`
- }
- value={person}
- >
- {({ selected }) => (
- <>
-
- {selected ? (
-
-
-
- ) : (
-
- )}
- {person}
-
- >
- )}
-
- ))
+ {availableTags.length !== 0 ? (
+ availableTags.map((person, personIdx) => (
+
+ `relative cursor-default select-none py-2 px-2 ${
+ active
+ ? "bg-bluePrimary text-white"
+ : "text-gray-900"
+ }`
+ }
+ value={person}
+ >
+ {({ selected }) => (
+ <>
+
+ {selected ? (
+
+
+
+ ) : (
+
+ )}
+ {person}
+
+ >
+ )}
+
+ ))
) : (
Nothing Found
)}
@@ -552,123 +601,118 @@ const Dashboard = () => {
*/}
-
-
-
-
-
-
- |
- Time
-
- |
+ {logQueries.isLoading &&
+ (!logQueries.data ||
+ !logQueries.data?.data ||
+ logQueries.data?.data?.length === 0) ? (
+
+
+ |
+
+ |
+
+
+ ) : (
+
+ {logQueries?.data?.pages?.map &&
+ logQueries.data.pages.map(
+ (page) =>
+ page?.data?.map &&
+ page?.data?.map(
+ (data, index) =>
+ hasSubArray(
+ data.p_tags?.split(","),
+ selectedTags,
+ ) &&
+ (searchQuery === "" ||
+ JSON.stringify(data)
+ .toLowerCase()
+ .includes(searchQuery.toLowerCase())) && (
+ {
+ console.log(JSON.stringify(data));
+ setOpen(true);
+ setClickedRow(data);
+ }}
+ className="cursor-pointer hover:bg-slate-100 hover:shadow"
+ key={index}
+ >
+ {selectedLogSchema.map((schema) => (
+ |
+ {data[schema] || ""}
+ |
+ ))}
+
+ {data.p_tags
+ ?.split(",")
+ .map((tag, index) => {
+ addAvailableTags(tag);
+ return (
+
+ {tag}
+
+ );
+ })}
+ |
+
+ ),
+ ),
+ )}
+
+ |
+
+ |
+
+
+ )}
+
+
{logStream.isError || !logStream?.data?.data.length ? (
diff --git a/src/utils/api/constants.js b/src/utils/api/constants.js
index 9140c9b4..4a47c059 100644
--- a/src/utils/api/constants.js
+++ b/src/utils/api/constants.js
@@ -1,5 +1,7 @@
export const LOG_STREAMS = "log_stream";
export const LOG_STREAMS_URL = "api/v1/logstream";
+export const LOG_STREAMS_SCHEMA = "logstream_schema";
+
export const QUERY = "query";
export const QUERY_URL = "api/v1/query";
diff --git a/src/utils/api/logstreams.js b/src/utils/api/logstreams.js
index 04ce6948..6e2f9afa 100644
--- a/src/utils/api/logstreams.js
+++ b/src/utils/api/logstreams.js
@@ -1,9 +1,21 @@
import { useQuery } from "@tanstack/react-query";
import { get } from "./index";
-import { LOG_STREAMS, LOG_STREAMS_URL } from "./constants";
+import {
+ LOG_STREAMS,
+ LOG_STREAMS_URL,
+} from "./constants";
const getLogStream = async () => {
return await get(LOG_STREAMS_URL);
};
-export const useGetLogStream = (option = {}) => useQuery([LOG_STREAMS], getLogStream, option);
\ No newline at end of file
+export const useGetLogStream = (option = {}) =>
+ useQuery([LOG_STREAMS], getLogStream, {...option});
+
+
+const getLogStreamSchema = async (streamName) => {
+ return await get(`${LOG_STREAMS_URL}/${streamName}/schema`);
+};
+
+export const useGetLogStreamSchema = (streamName, option = {}) =>
+ useQuery([streamName], () => getLogStreamSchema(streamName), option);
\ No newline at end of file
diff --git a/src/utils/api/query.js b/src/utils/api/query.js
index 658b7f5a..a6fa2d99 100644
--- a/src/utils/api/query.js
+++ b/src/utils/api/query.js
@@ -1,12 +1,32 @@
-import { useQuery } from "@tanstack/react-query";
+import { useInfiniteQuery } from "@tanstack/react-query";
import { post } from "./index";
import { QUERY_URL, QUERY } from "./constants";
-const queryLogs = async (streamName, startTime, endTime, signal) => {
+const queryLogs = async (
+ streamName,
+ startTime,
+ endTime,
+ signal,
+ pageParam,
+ selectedLogSchema,
+) => {
+ let dateStream = null;
+
+ for (let index in selectedLogSchema) {
+ if (
+ selectedLogSchema[index].includes("date") ||
+ selectedLogSchema[index].includes("time")
+ ) {
+ dateStream = selectedLogSchema[index];
+ }
+ }
+
return await post(
QUERY_URL,
{
- query: `select * from ${streamName}`,
+ query: `select * from ${streamName} ${
+ dateStream !== null ? `order by ${dateStream}` : ""
+ } limit 10 ${pageParam === 1 ? "" : `offset ${pageParam * 10}`} `,
startTime: startTime,
endTime: endTime,
},
@@ -14,12 +34,32 @@ const queryLogs = async (streamName, startTime, endTime, signal) => {
);
};
-export const useQueryLogs = (streamName, startTime, endTime, fn, option = {}) =>
- useQuery(
+export const useQueryLogs = (
+ streamName,
+ startTime,
+ endTime,
+ selectedLogSchema,
+ fn,
+ option = {},
+) =>
+ useInfiniteQuery(
[QUERY, streamName, startTime, endTime],
- async ({ signal }) => {
+ async ({ signal, pageParam = 1 }) => {
await fn();
- return await queryLogs(streamName, startTime, endTime, signal);
+ return await queryLogs(
+ streamName,
+ startTime,
+ endTime,
+ signal,
+ pageParam,
+ selectedLogSchema,
+ );
+ },
+ {
+ ...option,
+ getNextPageParam: (lastPage, allPages) => {
+ const nextPage = allPages.length + 1;
+ return lastPage.data.length !== 0 ? nextPage : undefined;
+ },
},
- option,
);