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
2 changes: 2 additions & 0 deletions Generator/DataverseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ await Parallel.ForEachAsync(

private async Task<Dictionary<string, List<SecurityRole>>> GetSecurityRoles(List<Guid> rolesInSolution, Dictionary<string, SecurityPrivilegeMetadata[]> priviledges)
{
if (rolesInSolution.Count == 0) return [];

var query = new QueryExpression("role")
{
ColumnSet = new ColumnSet("name"),
Expand Down
6 changes: 5 additions & 1 deletion Generator/WebsiteBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ internal void AddData()
var sb = new StringBuilder();
sb.AppendLine("import { GroupType } from \"@/lib/Types\";");
sb.AppendLine("");
sb.AppendLine($"export const LastSynched: Date = new Date('{DateTimeOffset.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}')");
sb.AppendLine($"export const LastSynched: Date = new Date('{DateTimeOffset.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}');");
var logoUrl = configuration.GetValue<string?>("Logo", defaultValue: null);
var jsValue = logoUrl != null ? $"\"{logoUrl}\"" : null;
sb.AppendLine($"export const Logo: string | null = {jsValue};");
sb.AppendLine("");
sb.AppendLine("export let Groups: GroupType[] = [");
var groups = records.GroupBy(x => x.Group).OrderBy(x => x.Key);
foreach (var group in groups)
Expand Down
41 changes: 33 additions & 8 deletions Website/components/AppSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { SidebarClose, SidebarOpen } from 'lucide-react'
import { useIsMobile } from '@/hooks/use-mobile'
import SidebarNavRail from './SidebarNavRail'
import clsx from 'clsx'
import { Logo } from '@/generated/Data'
import { Separator } from './ui/separator'

interface IAppSidebarProps {}

Expand All @@ -27,8 +29,8 @@ export const AppSidebar = ({}: IAppSidebarProps) => {
{isMobile && (
<button onClick={toggleSidebar}
className={clsx(
'fixed top-4 z-50 transition-all bg-white border border-gray-300 shadow rounded-full p-2',
isOpen ? 'left-52' : 'left-4'
'fixed top-4 z-[60] transition-all bg-white border border-gray-300 shadow rounded-full p-2',
isOpen ? 'left-[272px]' : 'left-4'
)}
aria-label={isOpen ? 'Close Sidebar' : 'Open Sidebar'}
>
Expand All @@ -39,7 +41,7 @@ export const AppSidebar = ({}: IAppSidebarProps) => {
{/* Overlay for mobile sidebar */}
{isMobile && isOpen && (
<div
className="fixed inset-0 bg-black bg-opacity-30 z-30"
className="fixed inset-0 bg-black bg-opacity-30 z-[35]"
onClick={toggleSidebar}
aria-label="Close sidebar overlay"
/>
Expand All @@ -48,7 +50,7 @@ export const AppSidebar = ({}: IAppSidebarProps) => {
{/* Sidebar */}
<div
className={clsx(
'h-screen bg-sidebar border-r border-sidebar-border z-40',
'h-screen bg-sidebar border-r border-sidebar-border z-[50]',
'transition-all duration-300',
isMobile
? [
Expand All @@ -70,12 +72,35 @@ export const AppSidebar = ({}: IAppSidebarProps) => {
{/* Header */}
<div className="w-full h-16 border-b border-sidebar-border p-2 flex justify-center items-center bg-white relative">
{isMobile ? (
<img src="/DMVLOGO.svg" alt="Logo" className="h-full" draggable={false} />
<>
{Logo ? (
<div className='flex items-center align-center'>
<img src={Logo} alt="Logo" className="h-10 w-10" draggable={false} />
<Separator orientation="vertical" className="mx-2 h-6" />
<img src="/DMVLOGOHORZ.svg" alt="Logo" className="h-10" draggable={false} />
</div>
) : (
<img src="/DMVLOGOHORZ.svg" alt="Logo" className="h-10" draggable={false} />
)}
</>
) : (
showElement ? (
<img src="/DMVLOGOHORZ.svg" alt="Logo" className="h-full" draggable={false} />
<div className='flex items-center justify-center h-full'>
{Logo ? (
<div className='flex items-center align-center'>
<img src={Logo} alt="Logo" className="h-10 w-10" draggable={false} />
<Separator orientation="vertical" className="mx-2 h-6" />
<img src="/DMVLOGOHORZ.svg" alt="Logo" className="h-10" draggable={false} />
</div>
) : (
<img src="/DMVLOGOHORZ.svg" alt="Logo" className="h-10" draggable={false} />
)}
</div>
) : (
<img src="/DMVLOGO.svg" alt="Logo" className="h-full" draggable={false} />
<div className="relative w-full h-full flex items-center justify-center">
<img src="/DMVLOGO.svg" alt="Logo" className="h-full" draggable={false} />
{ Logo && <img src={Logo} className='absolute rounded-md shadow-sm border border-blue-500 -bottom-1 -right-1 h-6 w-6 p-1 bg-white' /> }
</div>
)
)}
</div>
Expand All @@ -84,7 +109,7 @@ export const AppSidebar = ({}: IAppSidebarProps) => {
{!isMobile && (
<button
onClick={toggleElement}
className="absolute right-0 top-1/2 -translate-y-1/2 w-4 h-12 bg-gray-50 border border-gray-300 shadow rounded-sm flex items-center justify-center z-50 hover:bg-blue-50"
className="absolute right-0 top-1/2 -translate-y-1/2 w-4 h-12 bg-gray-50 border border-gray-300 shadow rounded-sm flex items-center justify-center z-[60] hover:bg-blue-50"
style={{ marginRight: '-12px' }}
aria-label={showElement ? 'Hide Details' : 'Show Details'}
>
Expand Down
47 changes: 40 additions & 7 deletions Website/components/datamodelview/TimeSlicedSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import React, { useState, useRef, useCallback, useEffect } from 'react';
import { createPortal } from 'react-dom';
import { Input } from '../ui/input';
import { Search, ChevronUp, ChevronDown } from 'lucide-react';
import { Search, ChevronUp, ChevronDown, X } from 'lucide-react';
import { useSidebar } from '@/contexts/SidebarContext';
import { useIsMobile } from '@/hooks/use-mobile';

interface TimeSlicedSearchProps {
onSearch: (value: string) => void;
Expand All @@ -28,11 +30,16 @@ export const TimeSlicedSearch = ({
const [localValue, setLocalValue] = useState('');
const [isTyping, setIsTyping] = useState(false);
const [portalRoot, setPortalRoot] = useState<HTMLElement | null>(null);
const { isOpen } = useSidebar();
const isMobile = useIsMobile();

const searchTimeoutRef = useRef<number>();
const typingTimeoutRef = useRef<number>();
const frameRef = useRef<number>();

// Hide search on mobile when sidebar is open
const shouldHideSearch = isMobile && isOpen;

// Time-sliced debouncing using requestAnimationFrame
const scheduleSearch = useCallback((value: string) => {
if (searchTimeoutRef.current) {
Expand Down Expand Up @@ -81,6 +88,22 @@ export const TimeSlicedSearch = ({

}, [isTyping, onLoadingChange, scheduleSearch]);

// Handle clear button
const handleClear = useCallback(() => {
setLocalValue('');
onSearch(''); // Clear search immediately
setIsTyping(false);
onLoadingChange(false);

// Clear any pending timeouts
if (searchTimeoutRef.current) {
clearTimeout(searchTimeoutRef.current);
}
if (typingTimeoutRef.current) {
clearTimeout(typingTimeoutRef.current);
}
}, [onSearch, onLoadingChange]);

// Handle keyboard navigation
const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter' && !e.shiftKey) {
Expand Down Expand Up @@ -151,7 +174,7 @@ export const TimeSlicedSearch = ({
}, []);

const searchInput = (
<div className="fixed top-4 right-8 z-50 w-80">
<div className={`fixed top-4 right-8 z-50 w-[280px] transition-opacity duration-200 ${shouldHideSearch ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}>
{/* Search Input Container */}
<div className="flex items-center gap-2">
<div className="relative flex-1">
Expand All @@ -163,16 +186,26 @@ export const TimeSlicedSearch = ({
value={localValue}
onChange={handleChange}
onKeyDown={handleKeyDown}
className="pl-10 pr-8 h-9 text-sm"
className="pl-10 pr-10 h-9 text-sm"
spellCheck={false}
autoComplete="off"
autoCapitalize="off"
/>
{isTyping && (
<div className="absolute right-3 top-1/2 transform -translate-y-1/2">
{/* Clear button or loading indicator */}
<div className="absolute right-3 top-1/2 transform -translate-y-1/2 flex justify-center items-center">
{isTyping ? (
<div className="w-4 h-4 border-2 border-blue-400 border-t-transparent rounded-full animate-spin"></div>
</div>
)}
) : localValue ? (
<button
onClick={handleClear}
className="w-4 h-4 text-gray-400 hover:text-gray-600 transition-colors"
title="Clear search"
aria-label="Clear search"
>
<X className="w-4 h-4" />
</button>
) : null}
</div>
</div>

{/* Navigation Buttons */}
Expand Down
5 changes: 4 additions & 1 deletion Website/stubs/Data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
/// This file is a stub and should not be modified directly.

import { GroupType } from "@/lib/Types";
export const LastSynched: Date = new Date()

export const LastSynched: Date = new Date();
export const Logo: string | null = null;

export let Groups: GroupType[] = [
{
"Name":"Untitled",
Expand Down
24 changes: 0 additions & 24 deletions package-lock.json

This file was deleted.

5 changes: 0 additions & 5 deletions package.json

This file was deleted.

Loading