Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Website/components/datamodelview/DatamodelView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ function DatamodelViewContent() {
} else {
// Clear search - reset to show all groups
datamodelDataDispatch({ type: "SET_FILTERED", payload: [] });

// Relocate section
restoreSection();
if (searchValue && searchValue.length === 0) {
restoreSection();
}
}
}
updateURL({ query: { globalsearch: searchValue.length >= 3 ? searchValue : "" } })
Expand Down
78 changes: 10 additions & 68 deletions Website/components/datamodelview/List.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useMemo, useRef, useCallback, useState } from "react";
import { useDatamodelView, useDatamodelViewDispatch } from "@/contexts/DatamodelViewContext";
import React from "react";
import { elementScroll, useVirtualizer, VirtualizerOptions } from '@tanstack/react-virtual';
import { useVirtualizer } from '@tanstack/react-virtual';
import { Section } from "./Section";
import { useDatamodelData } from "@/contexts/DatamodelDataContext";
import { AttributeType, EntityType, GroupType } from "@/lib/Types";
Expand All @@ -24,12 +24,10 @@ export function highlightMatch(text: string, search: string) {

export const List = ({ setCurrentIndex }: IListProps) => {
const dispatch = useDatamodelViewDispatch();
const { currentSection, loading } = useDatamodelView();
const { currentSection } = useDatamodelView();
const { groups, filtered, search } = useDatamodelData();
const { showSnackbar } = useSnackbar();
const parentRef = useRef<HTMLDivElement | null>(null);
const scrollTimeoutRef = useRef<NodeJS.Timeout>();
const scrollingRef = React.useRef<number>()
// used to relocate section after search/filter
const [sectionVirtualItem, setSectionVirtualItem] = useState<string | null>(null);

Expand Down Expand Up @@ -79,34 +77,6 @@ export const List = ({ setCurrentIndex }: IListProps) => {
return items;
}, [filtered, search, groups]);

function easeInOutQuint(t: number) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t
}

const scrollToFn: VirtualizerOptions<HTMLDivElement, HTMLElement>['scrollToFn'] =
React.useCallback((offset, canSmooth, instance) => {
const duration = 2000
const start = parentRef.current?.scrollTop || 0
const startTime = (scrollingRef.current = Date.now())

const run = () => {
if (scrollingRef.current !== startTime) return
const now = Date.now()
const elapsed = now - startTime
const progress = easeInOutQuint(Math.min(elapsed / duration, 1))
const interpolated = start + (offset - start) * progress

if (elapsed < duration) {
elementScroll(interpolated, canSmooth, instance)
requestAnimationFrame(run)
} else {
elementScroll(interpolated, canSmooth, instance)
}
}

requestAnimationFrame(run)
}, [])

const debouncedOnChange = debounce((instance, sync) => {
if (!sync) {
dispatch({ type: 'SET_LOADING_SECTION', payload: null });
Expand Down Expand Up @@ -158,8 +128,11 @@ export const List = ({ setCurrentIndex }: IListProps) => {
}
}

if (mostVisibleEntity && currentSection !== mostVisibleEntity.entity.SchemaName) {
if (mostVisibleEntity && !search) {
setSectionVirtualItem(mostVisibleEntity.entity.SchemaName);
}

if (mostVisibleEntity && currentSection !== mostVisibleEntity.entity.SchemaName) {
updateURL({ query: { group: mostVisibleEntity.group.Name, section: mostVisibleEntity.entity.SchemaName } });
dispatch({ type: "SET_CURRENT_GROUP", payload: mostVisibleEntity.group.Name });
dispatch({ type: "SET_CURRENT_SECTION", payload: mostVisibleEntity.entity.SchemaName });
Expand All @@ -176,15 +149,10 @@ export const List = ({ setCurrentIndex }: IListProps) => {
if (!item) return 200;
return item.type === 'group' ? 100 : 500;
},
scrollToFn,
onChange: debouncedOnChange,
});

const scrollToSection = useCallback((sectionId: string) => {
if (scrollTimeoutRef.current) {
clearTimeout(scrollTimeoutRef.current);
}

const sectionIndex = flatItems.findIndex(item =>
item.type === 'entity' && item.entity.SchemaName === sectionId
);
Expand All @@ -195,16 +163,13 @@ export const List = ({ setCurrentIndex }: IListProps) => {
}

rowVirtualizer.scrollToIndex(sectionIndex, {
align: 'start'
align: 'start',
behavior: 'smooth'
});

}, [flatItems]);

const scrollToGroup = useCallback((groupName: string) => {
if (scrollTimeoutRef.current) {
clearTimeout(scrollTimeoutRef.current);
}

const groupIndex = flatItems.findIndex(item =>
item.type === 'group' && item.group.Name === groupName
);
Expand All @@ -215,7 +180,8 @@ export const List = ({ setCurrentIndex }: IListProps) => {
}

rowVirtualizer.scrollToIndex(groupIndex, {
align: 'start'
align: 'start',
behavior: 'smooth'
});
}, [flatItems]);

Expand All @@ -229,12 +195,6 @@ export const List = ({ setCurrentIndex }: IListProps) => {
dispatch({ type: 'SET_SCROLL_TO_SECTION', payload: scrollToSection });
dispatch({ type: 'SET_SCROLL_TO_GROUP', payload: scrollToGroup });
dispatch({ type: 'SET_RESTORE_SECTION', payload: restoreSection });

return () => {
if (scrollTimeoutRef.current) {
clearTimeout(scrollTimeoutRef.current);
}
};
}, [dispatch, scrollToSection, scrollToGroup]);

// Callback to handle section content changes (for tab switches, expansions, etc.)
Expand All @@ -250,24 +210,6 @@ export const List = ({ setCurrentIndex }: IListProps) => {
return (
<div ref={parentRef} style={{ height: 'calc(100vh - var(--layout-header-desktop-height))', overflow: 'auto' }} className="p-6 relative no-scrollbar">

{/* Show skeleton loading state only when initially loading */}
{flatItems.length === 0 && loading && (!search || search.length < 3) && (
<div className="space-y-8">
{[...Array(5)].map((_, i) => (
<div key={i} className="bg-white rounded-lg border border-gray-300 shadow-md animate-pulse">
<div className="h-32 p-6 flex flex-col">
<div className="h-6 bg-gray-200 rounded w-1/3 mb-4"></div>
<div className="h-4 bg-gray-200 rounded w-1/2"></div>
</div>
<div className="p-4 border-t">
<div className="h-4 bg-gray-200 rounded w-full mb-3"></div>
<div className="h-4 bg-gray-200 rounded w-5/6"></div>
</div>
</div>
))}
</div>
)}

{/* Show no results message when searching but no items found */}
{flatItems.length === 0 && search && search.length >= 3 && (
<div className="flex flex-col items-center justify-center h-64 text-gray-500">
Expand Down
2 changes: 1 addition & 1 deletion Website/components/datamodelview/SidebarDatamodelView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const SidebarDatamodelView = ({ }: ISidebarDatamodelViewProps) => {
Entities: group.Entities.filter(entity =>
(entity.SchemaName.toLowerCase().includes(searchTerm.toLowerCase()) ||
entity.DisplayName.toLowerCase().includes(searchTerm.toLowerCase())) &&
filtered.some(f => f.type === 'entity' && f.entity.SchemaName === entity.SchemaName)
(!search || filtered.some(f => f.type === 'entity' && f.entity.SchemaName === entity.SchemaName))
)
})).filter(group => group.Entities.length > 0);
}, [groups, searchTerm, filtered]);
Expand Down
2 changes: 1 addition & 1 deletion Website/components/datamodelview/TimeSlicedSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export const TimeSlicedSearch = ({
if (typingTimeoutRef.current) {
clearTimeout(typingTimeoutRef.current);
}
}, [onSearch, onLoadingChange]);
}, [onSearch, onLoadingChange, localValue]);

// Cleanup
useEffect(() => {
Expand Down
Loading