diff --git a/Infrastructure/main.bicep b/Infrastructure/main.bicep index c3fa9ac..7e32d13 100644 --- a/Infrastructure/main.bicep +++ b/Infrastructure/main.bicep @@ -34,7 +34,7 @@ resource webApp 'Microsoft.Web/sites@2021-02-01' = { serverFarmId: appServicePlan.id httpsOnly: true siteConfig: { - linuxFxVersion: 'NODE|20-lts' + linuxFxVersion: 'NODE|24-lts' appSettings: [ { diff --git a/Website/.claude/settings.local.json b/Website/.claude/settings.local.json new file mode 100644 index 0000000..47115b5 --- /dev/null +++ b/Website/.claude/settings.local.json @@ -0,0 +1,12 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run lint:*)", + "Bash(npm install:*)", + "Bash(npm run build:*)", + "Bash(npx tsc:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/Website/app/metadata/page.tsx b/Website/app/metadata/page.tsx index bacc9af..5e5f38f 100644 --- a/Website/app/metadata/page.tsx +++ b/Website/app/metadata/page.tsx @@ -2,14 +2,17 @@ import { DatamodelView } from "@/components/datamodelview/DatamodelView"; import Layout from "@/components/shared/Layout"; import { Suspense } from "react"; import { DatamodelViewProvider } from "@/contexts/DatamodelViewContext"; +import { EntityFiltersProvider } from "@/contexts/EntityFiltersContext"; export default function Data() { return ( - - - + + + + + ) diff --git a/Website/components/datamodelview/Attributes.tsx b/Website/components/datamodelview/Attributes.tsx index 0136830..e4e424e 100644 --- a/Website/components/datamodelview/Attributes.tsx +++ b/Website/components/datamodelview/Attributes.tsx @@ -1,7 +1,7 @@ 'use client' import { EntityType, AttributeType } from "@/lib/Types" -import { useState } from "react" +import { useState, useEffect } from "react" import { AttributeDetails } from "./entity/AttributeDetails" import BooleanAttribute from "./attributes/BooleanAttribute" import ChoiceAttribute from "./attributes/ChoiceAttribute" @@ -15,18 +15,20 @@ import StatusAttribute from "./attributes/StatusAttribute" import StringAttribute from "./attributes/StringAttribute" import React from "react" import { highlightMatch } from "../datamodelview/List"; -import { Box, Button, FormControl, InputAdornment, InputLabel, MenuItem, Select, Table, TableBody, TableCell, TableHead, TableRow, TextField, Typography, useTheme } from "@mui/material" +import { Box, Button, FormControl, InputAdornment, InputLabel, MenuItem, Select, Table, TableBody, TableCell, TableHead, TableRow, TextField, Tooltip, Typography, useTheme } from "@mui/material" import { ClearRounded, SearchRounded, Visibility, VisibilityOff, ArrowUpwardRounded, ArrowDownwardRounded } from "@mui/icons-material" +import { useEntityFiltersDispatch } from "@/contexts/EntityFiltersContext" type SortDirection = 'asc' | 'desc' | null type SortColumn = 'displayName' | 'schemaName' | 'type' | 'description' | null interface IAttributeProps { entity: EntityType + search?: string onVisibleCountChange?: (count: number) => void } -export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttributeProps & { search?: string }) => { +export const Attributes = ({ entity, search = "", onVisibleCountChange }: IAttributeProps) => { const [sortColumn, setSortColumn] = useState("displayName") const [sortDirection, setSortDirection] = useState("asc") const [typeFilter, setTypeFilter] = useState("all") @@ -34,6 +36,19 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri const [searchQuery, setSearchQuery] = useState("") const theme = useTheme(); + const entityFiltersDispatch = useEntityFiltersDispatch(); + + // Report filter state changes to context + useEffect(() => { + entityFiltersDispatch({ + type: "SET_ENTITY_FILTERS", + entitySchemaName: entity.SchemaName, + filters: { + hideStandardFields, + typeFilter + } + }); + }, [hideStandardFields, typeFilter, entity.SchemaName, entityFiltersDispatch]); const handleSort = (column: SortColumn) => { if (sortColumn === column) { @@ -56,13 +71,13 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri const basicMatch = attr.DisplayName.toLowerCase().includes(query) || attr.SchemaName.toLowerCase().includes(query) || (attr.Description && attr.Description.toLowerCase().includes(query)); - + // Check options for ChoiceAttribute and StatusAttribute let optionsMatch = false; if (attr.AttributeType === 'ChoiceAttribute' || attr.AttributeType === 'StatusAttribute') { optionsMatch = attr.Options.some(option => option.Name.toLowerCase().includes(query)); } - + return basicMatch || optionsMatch; }; @@ -70,7 +85,14 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri let filteredAttributes = entity.Attributes if (typeFilter !== "all") { - filteredAttributes = filteredAttributes.filter(attr => attr.AttributeType === typeFilter) + if (typeFilter === "ChoiceAttribute") { + // When Choice is selected, show both ChoiceAttribute and StatusAttribute + filteredAttributes = filteredAttributes.filter(attr => + attr.AttributeType === "ChoiceAttribute" || attr.AttributeType === "StatusAttribute" + ) + } else { + filteredAttributes = filteredAttributes.filter(attr => attr.AttributeType === typeFilter) + } } if (searchQuery) { @@ -124,12 +146,10 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri const sortedAttributes = getSortedAttributes(); const highlightTerm = searchQuery || search; // Use internal search or parent search for highlighting - // Notify parent of visible count - React.useEffect(() => { - if (onVisibleCountChange) { - onVisibleCountChange(sortedAttributes.length); - } - }, [onVisibleCountChange, sortedAttributes.length]); + // Notify parent of visible count changes + useEffect(() => { + onVisibleCountChange?.(sortedAttributes.length); + }, [sortedAttributes.length, onVisibleCountChange]); const SortIcon = ({ column }: { column: SortColumn }) => { if (sortColumn !== column) return @@ -146,16 +166,15 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri "IntegerAttribute", "LookupAttribute", "DecimalAttribute", - "StatusAttribute", "StringAttribute", "BooleanAttribute", "FileAttribute" ] return <> - ) } - }} + }} /> Filter by type - - + + + {(searchQuery || typeFilter !== "all") && (