diff --git a/ui/src/modules/jobs/pages/SchemaConfiguration.tsx b/ui/src/modules/jobs/pages/SchemaConfiguration.tsx index f7cbaf8a..a487c873 100644 --- a/ui/src/modules/jobs/pages/SchemaConfiguration.tsx +++ b/ui/src/modules/jobs/pages/SchemaConfiguration.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState, useMemo, useRef } from "react" import { Input, Empty, Spin, Tooltip } from "antd" +import clsx from "clsx" import { sourceService } from "../../../api" import { useAppStore } from "../../../store" @@ -657,11 +658,12 @@ const SchemaConfiguration: React.FC = ({ {destinationDatabase && (
@@ -710,7 +712,10 @@ const SchemaConfiguration: React.FC = ({
)}
{STREAM_FILTERS.map(filter => ( = ({
-
+
{!loading && apiResponse?.streams ? ( = ({
{activeStreamData ? ( = ({ className={clsx( "flex w-full items-center justify-between border-b border-solid border-[#e5e7eb] py-3 pl-6", isActiveStream - ? "bg-primary-100" - : "border-l border-r bg-white hover:bg-background-primary", + ? "bg-[#D2D8F7]" + : "bg-white hover:bg-background-primary", )} >
( IngestionMode.APPEND, ) + const [sortedGroupedNamespaces, setSortedGroupedNamespaces] = useState< + [string, StreamData[]][] + >([]) + + const prevGroupedStreams = useRef(groupedStreams) useEffect(() => { setIngestionMode(getIngestionMode(selectedStreams)) @@ -60,6 +68,23 @@ const StreamsCollapsibleList = ({ } }, [groupedStreams]) + const dataHasChanged = () => { + const prev = prevGroupedStreams.current + const current = groupedStreams + + const prevKeys = Object.keys(prev) + const currentKeys = Object.keys(current) + + if (prevKeys.length !== currentKeys.length) return true + + for (const key of currentKeys) { + if (!prev[key]) return true + if (prev[key].length !== current[key].length) return true + } + + return false + } + // Update local checked status based on selectedStreams useEffect(() => { const newCheckedStatus = { @@ -112,6 +137,62 @@ const StreamsCollapsibleList = ({ newCheckedStatus.global = allNamespacesSelected setCheckedStatus(newCheckedStatus) + + // sort the namespaces and streams inside it alphabetically on the basis of checked and unchecked status + if (sortedGroupedNamespaces.length === 0 || dataHasChanged()) { + const sortStreamsByCheckedStatus = ( + streams: StreamData[], + namespace: string, + ): StreamData[] => { + const checked: StreamData[] = [] + const unchecked: StreamData[] = [] + + streams.forEach(stream => { + const isChecked = + newCheckedStatus.streams[namespace]?.[stream.stream.name] + if (isChecked) checked.push(stream) + else unchecked.push(stream) + }) + + const sortByStreamName = (a: StreamData, b: StreamData) => + a.stream.name.localeCompare(b.stream.name) + + checked.sort(sortByStreamName) + unchecked.sort(sortByStreamName) + + return [...checked, ...unchecked] + } + + const namespacesWithCheckedStreams: [string, StreamData[]][] = [] + const namespacesWithoutCheckedStreams: [string, StreamData[]][] = [] + + Object.entries(groupedStreams).forEach(([namespace, streams]) => { + const hasAnySelectedStream = streams.some( + stream => newCheckedStatus.streams[namespace]?.[stream.stream.name], + ) + + const sortedStreams = sortStreamsByCheckedStatus(streams, namespace) + + if (hasAnySelectedStream) + namespacesWithCheckedStreams.push([namespace, sortedStreams]) + else namespacesWithoutCheckedStreams.push([namespace, sortedStreams]) + }) + + const sortByNamespaceName = ( + a: [string, StreamData[]], + b: [string, StreamData[]], + ) => a[0].localeCompare(b[0]) + + namespacesWithCheckedStreams.sort(sortByNamespaceName) + namespacesWithoutCheckedStreams.sort(sortByNamespaceName) + + setSortedGroupedNamespaces([ + ...namespacesWithCheckedStreams, + ...namespacesWithoutCheckedStreams, + ]) + + prevGroupedStreams.current = groupedStreams + } }, [selectedStreams, groupedStreams]) const handleToggleNamespace = (ns: string) => { @@ -240,11 +321,11 @@ const StreamsCollapsibleList = ({ return ( <>
- {Object.keys(groupedStreams).length === 0 ? ( + {Object.keys(sortedGroupedNamespaces).length === 0 ? ( ) : ( <> -
+
handleGlobalSyncAll(e.target.checked)} @@ -300,11 +381,11 @@ const StreamsCollapsibleList = ({
- {Object.entries(groupedStreams).map(([ns, streams]) => { + {sortedGroupedNamespaces.map(([ns, streams]) => { return (