diff --git a/Generator/DTO/Analyzeable.cs b/Generator/DTO/Analyzeable.cs new file mode 100644 index 0000000..c0b34d7 --- /dev/null +++ b/Generator/DTO/Analyzeable.cs @@ -0,0 +1,3 @@ +namespace Generator.DTO; + +public record Analyzeable { } diff --git a/Generator/DTO/AttributeUsage.cs b/Generator/DTO/AttributeUsage.cs new file mode 100644 index 0000000..60aff26 --- /dev/null +++ b/Generator/DTO/AttributeUsage.cs @@ -0,0 +1,27 @@ +namespace Generator.DTO; + +public enum ComponentType +{ + PowerAutomateFlow, + Plugin, + WebResource, + WorkflowActivity, + CustomApi +} + +public enum OperationType +{ + Create, + Read, + Update, + Delete, + List, + Other +} + +public record AttributeUsage( + string Name, + string Usage, + OperationType OperationType, + ComponentType ComponentType +); diff --git a/Generator/DTO/Attributes/Attribute.cs b/Generator/DTO/Attributes/Attribute.cs index 47886c9..fe5ba77 100644 --- a/Generator/DTO/Attributes/Attribute.cs +++ b/Generator/DTO/Attributes/Attribute.cs @@ -7,8 +7,7 @@ public abstract class Attribute public bool IsStandardFieldModified { get; set; } public bool IsCustomAttribute { get; set; } public bool IsPrimaryId { get; set; } - public HashSet PluginTypeNames { get; set; } = new HashSet(); - public bool HasPluginStep => PluginTypeNames.Count > 0; + public List AttributeUsages { get; set; } = new List(); public string DisplayName { get; } public string SchemaName { get; } public string Description { get; } diff --git a/Generator/DTO/PowerAutomateFlow.cs b/Generator/DTO/PowerAutomateFlow.cs new file mode 100644 index 0000000..ba1aadb --- /dev/null +++ b/Generator/DTO/PowerAutomateFlow.cs @@ -0,0 +1,6 @@ +namespace Generator.DTO; + +public record PowerAutomateFlow( + string Id, + string Name, + string ClientData) : Analyzeable(); diff --git a/Generator/DTO/SDKStep.cs b/Generator/DTO/SDKStep.cs new file mode 100644 index 0000000..b1a0a48 --- /dev/null +++ b/Generator/DTO/SDKStep.cs @@ -0,0 +1,10 @@ +using Microsoft.Xrm.Sdk; + +namespace Generator.DTO; + +public record SDKStep( + string Id, + string Name, + string FilteringAttributes, + string PrimaryObjectTypeCode, + OptionSetValue State) : Analyzeable(); diff --git a/Generator/DataverseService.cs b/Generator/DataverseService.cs index ccdeca3..259974c 100644 --- a/Generator/DataverseService.cs +++ b/Generator/DataverseService.cs @@ -2,6 +2,9 @@ using Azure.Identity; using Generator.DTO; using Generator.DTO.Attributes; +using Generator.Queries; +using Generator.Services; +using Generator.Services.Plugins; using Microsoft.Crm.Sdk.Messages; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; @@ -22,6 +25,9 @@ internal class DataverseService private readonly IConfiguration configuration; private readonly ILogger logger; + private readonly PluginAnalyzer pluginAnalyzer; + private readonly PowerAutomateFlowAnalyzer flowAnalyzer; + public DataverseService(IConfiguration configuration, ILogger logger) { this.configuration = configuration; @@ -38,6 +44,9 @@ public DataverseService(IConfiguration configuration, ILogger client = new ServiceClient( instanceUrl: new Uri(dataverseUrl), tokenProviderFunction: url => TokenProviderFunction(url, cache, logger)); + + pluginAnalyzer = new PluginAnalyzer(client); + flowAnalyzer = new PowerAutomateFlowAnalyzer(client); } public async Task> GetFilteredMetadata() @@ -84,7 +93,18 @@ public async Task> GetFilteredMetadata() var attributeLogicalToSchema = allEntityMetadata.ToDictionary(x => x.LogicalName, x => x.Attributes?.ToDictionary(attr => attr.LogicalName, attr => attr.DisplayName.UserLocalizedLabel?.Label ?? attr.SchemaName) ?? []); var entityIconMap = await GetEntityIconMap(allEntityMetadata); - var pluginStepAttributeMap = await GetPluginStepAttributes(logicalToSchema.Keys.ToHashSet(), pluginStepsInSolution); + // Processes analysis + var attributeUsages = new Dictionary>>(); + // Plugins + var pluginCollection = await client.GetSDKMessageProcessingStepsAsync(solutionIds); + logger.LogInformation($"There are {pluginCollection.Count()} plugin sdk steps in the environment."); + foreach (var plugin in pluginCollection) + await pluginAnalyzer.AnalyzeComponentAsync(plugin, attributeUsages); + // Flows + var flowCollection = await client.GetPowerAutomateFlowsAsync(solutionIds); + logger.LogInformation($"There are {flowCollection.Count()} Power Automate flows in the environment."); + foreach (var flow in flowCollection) + await flowAnalyzer.AnalyzeComponentAsync(flow, attributeUsages); var records = entitiesInSolutionMetadata @@ -120,7 +140,7 @@ public async Task> GetFilteredMetadata() securityRoles ?? [], keys ?? [], entityIconMap, - pluginStepAttributeMap, + attributeUsages, configuration); }); } @@ -135,16 +155,14 @@ private static Record MakeRecord( List securityRoles, List keys, Dictionary entityIconMap, - Dictionary>> pluginStepAttributeMap, + Dictionary>> attributeUsages, IConfiguration configuration) { var attributes = relevantAttributes .Select(metadata => { - pluginStepAttributeMap.TryGetValue(entity.LogicalName, out var entityPluginAttributes); - var pluginTypeNames = entityPluginAttributes?.GetValueOrDefault(metadata.LogicalName) ?? new HashSet(); - var attr = GetAttribute(metadata, entity, logicalToSchema, pluginTypeNames, logger); + var attr = GetAttribute(metadata, entity, logicalToSchema, attributeUsages, logger); attr.IsStandardFieldModified = MetadataExtensions.StandardFieldHasChanged(metadata, entity.DisplayName.UserLocalizedLabel?.Label ?? string.Empty); return attr; }) @@ -220,7 +238,7 @@ private static Record MakeRecord( iconBase64); } - private static Attribute GetAttribute(AttributeMetadata metadata, EntityMetadata entity, Dictionary logicalToSchema, HashSet pluginTypeNames, ILogger logger) + private static Attribute GetAttribute(AttributeMetadata metadata, EntityMetadata entity, Dictionary logicalToSchema, Dictionary>> attributeUsages, ILogger logger) { Attribute attr = metadata switch { @@ -239,7 +257,12 @@ private static Attribute GetAttribute(AttributeMetadata metadata, EntityMetadata FileAttributeMetadata fileAttribute => new FileAttribute(fileAttribute), _ => new GenericAttribute(metadata) }; - attr.PluginTypeNames = pluginTypeNames; + + var schemaname = attributeUsages.GetValueOrDefault(entity.LogicalName)?.GetValueOrDefault(metadata.LogicalName) ?? []; + // also check the plural name, as some workflows like Power Automate use collectionname + var pluralname = attributeUsages.GetValueOrDefault(entity.LogicalCollectionName)?.GetValueOrDefault(metadata.LogicalName) ?? []; + + attr.AttributeUsages = [.. schemaname, .. pluralname]; return attr; } @@ -356,7 +379,7 @@ await Parallel.ForEachAsync( { Conditions = { - new ConditionExpression("componenttype", ConditionOperator.In, new List() { 1, 2, 20, 92 }), // entity, attribute, role, pluginstep (https://learn.microsoft.com/en-us/power-apps/developer/data-platform/reference/entities/solutioncomponent) + new ConditionExpression("componenttype", ConditionOperator.In, new List() { 1, 2, 20, 92 }), // entity, attribute, role, sdkpluginstep (https://learn.microsoft.com/en-us/power-apps/developer/data-platform/reference/entities/solutioncomponent) new ConditionExpression("solutionid", ConditionOperator.In, solutionIds) } } @@ -548,101 +571,6 @@ private static string GetCoreUrl(string url) return $"{uri.Scheme}://{uri.Host}"; } - private async Task>>> GetPluginStepAttributes(HashSet relevantLogicalNames, List pluginStepsInSolution) - { - logger.LogInformation("Retrieving plugin step attributes..."); - - var pluginStepAttributeMap = new Dictionary>>(); - - try - { - // Query sdkmessageprocessingstep table for steps with filtering attributes - var stepQuery = new QueryExpression("sdkmessageprocessingstep") - { - ColumnSet = new ColumnSet("filteringattributes", "sdkmessagefilterid", "sdkmessageprocessingstepid"), - Criteria = new FilterExpression - { - Conditions = - { - new ConditionExpression("filteringattributes", ConditionOperator.NotNull), - new ConditionExpression("filteringattributes", ConditionOperator.NotEqual, ""), - new ConditionExpression("statecode", ConditionOperator.Equal, 0) // Only active steps - } - }, - LinkEntities = - { - new LinkEntity - { - LinkFromEntityName = "sdkmessageprocessingstep", - LinkFromAttributeName = "sdkmessagefilterid", - LinkToEntityName = "sdkmessagefilter", - LinkToAttributeName = "sdkmessagefilterid", - Columns = new ColumnSet("primaryobjecttypecode"), - EntityAlias = "filter" - }, - new LinkEntity - { - LinkFromEntityName = "sdkmessageprocessingstep", - LinkFromAttributeName = "plugintypeid", - LinkToEntityName = "plugintype", - LinkToAttributeName = "plugintypeid", - Columns = new ColumnSet("name"), - EntityAlias = "plugintype" - } - } - }; - - // Add solution filtering if plugin steps in solution are specified - if (pluginStepsInSolution.Count > 0) - { - stepQuery.Criteria.Conditions.Add( - new ConditionExpression("sdkmessageprocessingstepid", ConditionOperator.In, pluginStepsInSolution)); - } - - var stepResults = await client.RetrieveMultipleAsync(stepQuery); - - foreach (var step in stepResults.Entities) - { - var filteringAttributes = step.GetAttributeValue("filteringattributes"); - var entityLogicalName = step.GetAttributeValue("filter.primaryobjecttypecode")?.Value as string; - var pluginTypeName = step.GetAttributeValue("plugintype.name")?.Value as string; - - if (string.IsNullOrEmpty(filteringAttributes) || string.IsNullOrEmpty(entityLogicalName) || string.IsNullOrEmpty(pluginTypeName)) - continue; - - // Get entity logical name from metadata mapping - if (!relevantLogicalNames.Contains(entityLogicalName)) - { - logger.LogDebug("Unknown entity type code: {TypeCode}", entityLogicalName); - continue; - } - - if (!pluginStepAttributeMap.ContainsKey(entityLogicalName)) - pluginStepAttributeMap[entityLogicalName] = new Dictionary>(); - - // Parse comma-separated attribute names - var attributeNames = filteringAttributes.Split(',', StringSplitOptions.RemoveEmptyEntries); - foreach (var attributeName in attributeNames) - { - var trimmedAttributeName = attributeName.Trim(); - if (!pluginStepAttributeMap[entityLogicalName].ContainsKey(trimmedAttributeName)) - pluginStepAttributeMap[entityLogicalName][trimmedAttributeName] = new HashSet(); - - var pluginTypeNameParts = pluginTypeName.Split('.'); - pluginStepAttributeMap[entityLogicalName][trimmedAttributeName].Add(pluginTypeNameParts[pluginTypeNameParts.Length - 1]); - } - } - - logger.LogInformation("Found {Count} entities with plugin step attributes.", pluginStepAttributeMap.Count); - } - catch (Exception ex) - { - logger.LogWarning("Failed to retrieve plugin step attributes: {Message}", ex.Message); - } - - return pluginStepAttributeMap; - } - private static async Task FetchAccessToken(TokenCredential credential, string scope, ILogger logger) { var tokenRequestContext = new TokenRequestContext(new[] { scope }); diff --git a/Generator/Queries/PluginQueries.cs b/Generator/Queries/PluginQueries.cs new file mode 100644 index 0000000..b82df17 --- /dev/null +++ b/Generator/Queries/PluginQueries.cs @@ -0,0 +1,86 @@ +using Generator.DTO; +using Microsoft.PowerPlatform.Dataverse.Client; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Query; +using System.Data; + +namespace Generator.Queries; + +public static class PluginQueries +{ + + public static async Task> GetSDKMessageProcessingStepsAsync(this ServiceClient service, List? solutionIds = null) + { + // Retrieve the SDK Message Processing Step entity using the componentId + var query = new QueryExpression("solutioncomponent") + { + ColumnSet = new ColumnSet("objectid"), + Criteria = new FilterExpression(LogicalOperator.And) + { + Conditions = + { + new ConditionExpression("solutionid", ConditionOperator.In, solutionIds), + new ConditionExpression("componenttype", ConditionOperator.Equal, 92) + } + }, + LinkEntities = + { + new LinkEntity( + "solutioncomponent", + "sdkmessageprocessingstep", + "objectid", + "sdkmessageprocessingstepid", + JoinOperator.Inner) + { + Columns = new ColumnSet("sdkmessageprocessingstepid", "name", "filteringattributes", "sdkmessageid", "statecode"), + EntityAlias = "step", + LinkEntities = + { + new LinkEntity( + "sdkmessageprocessingstep", + "sdkmessagefilter", + "sdkmessagefilterid", + "sdkmessagefilterid", + JoinOperator.LeftOuter) + { + Columns = new ColumnSet("primaryobjecttypecode"), + EntityAlias = "filter" + } + //new LinkEntity + //{ + // LinkFromEntityName = "sdkmessageprocessingstep", + // LinkFromAttributeName = "plugintypeid", + // LinkToEntityName = "plugintype", + // LinkToAttributeName = "plugintypeid", + // Columns = new ColumnSet("name"), + // EntityAlias = "plugintype" + //} + } + } + } + }; + + + //if (solutionIds is not null) query.Criteria.Conditions.Add(new ConditionExpression("solutionid", ConditionOperator.In, solutionIds)); + var result = await service.RetrieveMultipleAsync(query); + + var steps = result.Entities.Select(e => + { + var sdkMessageId = e.GetAttributeValue("step.sdkmessageid")?.Value as EntityReference; + var sdkMessageName = e.GetAttributeValue("step.name")?.Value as string; + var sdkFilterAttributes = e.GetAttributeValue("step.filteringattributes")?.Value as string; + var sdkState = e.GetAttributeValue("step.statecode")?.Value as OptionSetValue; + var filterTypeCode = e.GetAttributeValue("filter.primaryobjecttypecode")?.Value as string; + + return new SDKStep( + sdkMessageId.Id.ToString(), + sdkMessageName ?? "Unknown Name", + sdkFilterAttributes ?? "", + filterTypeCode, + sdkState + ); + }); + + return steps; + } +} diff --git a/Generator/Queries/PowerAutomateQueries.cs b/Generator/Queries/PowerAutomateQueries.cs new file mode 100644 index 0000000..d20b302 --- /dev/null +++ b/Generator/Queries/PowerAutomateQueries.cs @@ -0,0 +1,58 @@ +using Generator.DTO; +using Microsoft.PowerPlatform.Dataverse.Client; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Query; + +namespace Generator.Queries; +public static class PowerAutomateQueries +{ + public static async Task> GetPowerAutomateFlowsAsync(this ServiceClient service, List? solutionIds = null) + { + var query = new QueryExpression("solutioncomponent") + { + ColumnSet = new ColumnSet("objectid"), + Criteria = new FilterExpression(LogicalOperator.And) + { + Conditions = + { + new ConditionExpression("solutionid", ConditionOperator.In, solutionIds), + new ConditionExpression("componenttype", ConditionOperator.Equal, 29) + } + }, + LinkEntities = + { + new LinkEntity( + "solutioncomponent", + "workflow", + "objectid", + "workflowid", + JoinOperator.Inner) + { + Columns = new ColumnSet("workflowid", "name", "clientdata"), + EntityAlias = "flow", + LinkCriteria = new FilterExpression + { + Conditions = + { + new ConditionExpression("category", ConditionOperator.Equal, 5), // 5 = Flow + new ConditionExpression("statecode", ConditionOperator.Equal, 1) // 1 = Activated + } + } + } + } + }; + + var result = await service.RetrieveMultipleAsync(query); + + var flows = result.Entities.Select(e => + { + return new PowerAutomateFlow( + e.GetAttributeValue("flow.workflowid").Value as string, + e.GetAttributeValue("flow.name").Value as string, + e.GetAttributeValue("flow.clientdata").Value as string + ); + }); + + return flows; + } +} diff --git a/Generator/Services/ComponentAnalyzerBase.cs b/Generator/Services/ComponentAnalyzerBase.cs new file mode 100644 index 0000000..fd6d260 --- /dev/null +++ b/Generator/Services/ComponentAnalyzerBase.cs @@ -0,0 +1,28 @@ +using Generator.DTO; +using Microsoft.PowerPlatform.Dataverse.Client; +using System.Text.RegularExpressions; + +namespace Generator.Services; + +public abstract class BaseComponentAnalyzer(ServiceClient service) : IComponentAnalyzer where T : Analyzeable +{ + protected readonly ServiceClient _service = service; + + public abstract ComponentType SupportedType { get; } + public abstract Task AnalyzeComponentAsync(T component, Dictionary>> attributeUsages); + + protected List ExtractFieldsFromODataFilter(string filter) + { + var fields = new List(); + + var fieldPattern = @"(\w+)\s+(?:eq|ne|gt|ge|lt|le|contains|startswith|endswith)"; + var matches = Regex.Matches(filter, fieldPattern, RegexOptions.IgnoreCase); + + foreach (Match match in matches) + { + fields.Add(match.Groups[1].Value); + } + + return fields.Distinct().ToList(); + } +} diff --git a/Generator/Services/IComponentAnalyzer.cs b/Generator/Services/IComponentAnalyzer.cs new file mode 100644 index 0000000..ce5b0f0 --- /dev/null +++ b/Generator/Services/IComponentAnalyzer.cs @@ -0,0 +1,9 @@ +using Generator.DTO; + +namespace Generator.Services; + +public interface IComponentAnalyzer where T : Analyzeable +{ + public ComponentType SupportedType { get; } + public Task AnalyzeComponentAsync(T component, Dictionary>> attributeUsages); +} diff --git a/Generator/Services/Plugins/PluginAnalyzer.cs b/Generator/Services/Plugins/PluginAnalyzer.cs new file mode 100644 index 0000000..745b4d6 --- /dev/null +++ b/Generator/Services/Plugins/PluginAnalyzer.cs @@ -0,0 +1,53 @@ +using Generator.DTO; +using Microsoft.PowerPlatform.Dataverse.Client; +using Microsoft.Xrm.Sdk; + +namespace Generator.Services.Plugins; + +public class PluginAnalyzer : BaseComponentAnalyzer +{ + public PluginAnalyzer(ServiceClient service) : base(service) { } + + public override ComponentType SupportedType => ComponentType.Plugin; + + public override async Task AnalyzeComponentAsync(SDKStep sdkStep, Dictionary>> attributeUsages) + { + try + { + // Extract filtering attributes and plugin name + var filteringAttributes = sdkStep.FilteringAttributes?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty(); + var pluginName = sdkStep.Name; + + // Retrieve the logical name of the entity from the linked SDK Message entity + var logicalTableName = sdkStep.PrimaryObjectTypeCode; + + // Populate the attributeUsages dictionary + foreach (var attribute in filteringAttributes) + { + if (!attributeUsages.ContainsKey(logicalTableName)) + attributeUsages[logicalTableName] = new Dictionary>(); + + if (!attributeUsages[logicalTableName].ContainsKey(attribute)) + attributeUsages[logicalTableName][attribute] = new List(); + + // Add the usage information (assuming AttributeUsage is a defined class) + + attributeUsages[logicalTableName][attribute].Add(new AttributeUsage(pluginName, $"Used in filterattributes", OperationType.Other, SupportedType)); + } + } + catch (Exception ex) + { + // Log the exception (assuming a logging mechanism is in place) + Console.WriteLine($"Error analyzing component: {ex.Message}"); + } + } + + private async Task AnalyzePluginCode(Entity plugin, List attributeUsages, string componentName) + { + // TODO later + // This would require access to the plugin assembly code + // Could potentially analyze if assembly source is available or through reflection + // For now, this is a placeholder for future implementation + await Task.CompletedTask; + } +} diff --git a/Generator/Services/Power Automate/PowerAutomateFlowAnalyzer.cs b/Generator/Services/Power Automate/PowerAutomateFlowAnalyzer.cs new file mode 100644 index 0000000..b295d1a --- /dev/null +++ b/Generator/Services/Power Automate/PowerAutomateFlowAnalyzer.cs @@ -0,0 +1,467 @@ +using Generator.DTO; +using Microsoft.PowerPlatform.Dataverse.Client; +using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.RegularExpressions; + +namespace Generator.Services; + +public class PowerAutomateFlowAnalyzer : BaseComponentAnalyzer +{ + // Common Dataverse connector identifiers + private static readonly HashSet ValidPowerAutomateConnectors = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "OpenApiConnection" + }; + + public PowerAutomateFlowAnalyzer(ServiceClient service) : base(service) { } + + public override ComponentType SupportedType => ComponentType.PowerAutomateFlow; + + public override async Task AnalyzeComponentAsync(PowerAutomateFlow flow, Dictionary>> attributeUsages) + { + try + { + // Get the flow definition from clientdata attribute + var clientData = flow.ClientData; + if (string.IsNullOrEmpty(clientData)) return; + + // Parse the JSON + var flowDefinition = JObject.Parse(clientData); + + // Analyze the flow definition + await AnalyzeFlowDefinition(flowDefinition, flow, attributeUsages); + } + catch (JsonException ex) { Console.WriteLine($"Error parsing flow definition for {flow.Name}: {ex.Message}"); } + catch (Exception ex) { Console.WriteLine($"Error analyzing flow {flow.Name}: {ex.Message}"); } + } + + private async Task AnalyzeFlowDefinition(JObject flowDefinition, PowerAutomateFlow flow, Dictionary>> attributeUsages) + { + // Look for actions in the flow definition + var actions = ExtractActions(flowDefinition); + + foreach (var action in actions) + await AnalyzeAction(action, flow, attributeUsages); + + // Also check for dynamic content references that might reference Dataverse fields + AnalyzeDynamicContent(flowDefinition, flow, attributeUsages); + } + + private IEnumerable ExtractActions(JObject flowDefinition) + { + var actions = new List(); + + // Actions can be nested in different places in the flow definition + // Check properties.definition.actions + var definitionActions = flowDefinition.SelectTokens("$.properties.definition.actions.*"); + actions.AddRange(definitionActions); + + // Check for triggers + var triggers = flowDefinition.SelectTokens("$.properties.definition.triggers.*"); + actions.AddRange(triggers); + + // Check for nested actions in conditions, loops, etc. + var nestedActions = flowDefinition.SelectTokens("$..actions.*"); + actions.AddRange(nestedActions); + + return actions.Distinct(); + } + + private async Task AnalyzeAction(JToken action, PowerAutomateFlow flow, Dictionary>> attributeUsages) + { + try + { + var actionType = action.SelectToken("type")?.ToString(); + + // Check if this is a Dataverse/CDS action + if (IsDataverseAction(actionType)) + await AnalyzeDataverseAction(action, flow, attributeUsages); + } + catch (Exception ex) { Console.WriteLine($"Error analyzing action: {ex.Message}"); } + } + private string ExtractConnectorId(JToken action) + { + // Try different paths where connector ID might be stored + var connectorId = action.SelectToken("metadata.apiDefinitionUrl")?.ToString(); + if (!string.IsNullOrEmpty(connectorId)) + { + // Extract connector name from API definition URL + var match = Regex.Match(connectorId, @"/providers/Microsoft\.PowerApps/apis/([^/]+)"); + if (match.Success) + return match.Groups[1].Value; + + } + + // Try alternative paths + connectorId = action.SelectToken("metadata.connectionReference.connectionName")?.ToString(); + if (!string.IsNullOrEmpty(connectorId)) + { + return connectorId; + } + + // Check for direct connector reference + var operationId = action.SelectToken("metadata.operationMetadataId")?.ToString(); + if (!string.IsNullOrEmpty(operationId)) + { + return operationId; + } + + return string.Empty; + } + + private bool IsDataverseAction(string actionType) + { + return ValidPowerAutomateConnectors.Contains(actionType ?? string.Empty); + } + + private async Task AnalyzeDataverseAction(JToken action, PowerAutomateFlow flow, Dictionary>> attributeUsages) + { + var flowName = flow.Name ?? "Unknown Flow"; + + var actionName = action.Parent.Path.Split('.').Last(); + + // Extract entity name + var entityName = ExtractEntityName(action); + if (string.IsNullOrEmpty(entityName)) return; + + // Extract field references from inputs + var inputs = action.SelectToken("inputs"); + if (inputs != null) + { + ExtractAttributeUsagesFromInputs(inputs, entityName, flowName, actionName, attributeUsages); + } + + // Extract field references from outputs/dynamic content + var outputs = action.SelectToken("outputs"); + if (outputs != null) + { + ExtractAttributeUsagesFromOutputs(outputs, entityName, flowName, actionName, attributeUsages); + } + } + + private string ExtractEntityName(JToken action) + { + // Try different paths where entity name might be stored + + // Check inputs for entity name + var entityLogicalName = action.SelectToken("inputs.parameters.entityName")?.ToString(); + if (!string.IsNullOrEmpty(entityLogicalName)) return entityLogicalName; + + + // Check for entity set name + var entitySetName = action.SelectToken("inputs.parameters.entitySetName")?.ToString(); + if (!string.IsNullOrEmpty(entitySetName)) return entitySetName; + + // Try to extract from URL path + var url = action.SelectToken("inputs.uri")?.ToString() ?? action.SelectToken("inputs.path")?.ToString(); + if (!string.IsNullOrEmpty(url)) + { + var match = Regex.Match(url, @"\/([a-zA-Z_][a-zA-Z0-9_]*)\("); + if (match.Success) + { + return match.Groups[1].Value; + } + } + + return string.Empty; + } + + private void ExtractAttributeUsagesFromInputs(JToken inputs, string entityName, string flowName, string actionName, Dictionary>> attributeUsages) + { + // Look for field mappings in the inputs + var item = inputs.SelectToken("item") ?? inputs.SelectToken("parameters.item"); + if (item != null) + { + ExtractFieldsFromObject(item, entityName, flowName, actionName, "Input", attributeUsages); + } + + // Look for individual field parameters + var parameters = inputs.SelectToken("parameters"); + if (parameters is JObject paramsObj) + { + foreach (var prop in paramsObj.Properties()) + { + // CDS Updates + if (prop.Name.StartsWith("item/") && prop.Value.Type == JTokenType.String) + { + var fieldName = prop.Name.Substring("item/".Length); + AddAttributeUsage(attributeUsages, entityName, fieldName, new AttributeUsage(flowName, $"Input parameter in action '{actionName}'", DetermineOperationTypeFromAction(actionName), SupportedType)); + } + + if (IsLikelyFieldName(prop.Name) && !IsSystemParameter(prop.Name)) + { + AddAttributeUsage(attributeUsages, entityName, prop.Name, new AttributeUsage(flowName, $"Input parameter in action '{actionName}'", DetermineOperationTypeFromAction(actionName), SupportedType)); + } + } + } + + // Look for OData select/expand parameters + ExtractODataParameters(inputs, entityName, flowName, actionName, attributeUsages); + } + + private void ExtractAttributeUsagesFromOutputs(JToken outputs, string entityName, string flowName, string actionName, Dictionary>> attributeUsages) + { + // Outputs typically define the schema of returned data + var schema = outputs.SelectToken("schema"); + if (schema != null) + { + ExtractFieldsFromSchema(schema, entityName, flowName, actionName, attributeUsages); + } + } + + private void ExtractFieldsFromObject(JToken obj, string entityName, string flowName, string actionName, string context, Dictionary>> attributeUsages) + { + if (obj is JObject jObj) + { + foreach (var prop in jObj.Properties()) + { + if (IsLikelyFieldName(prop.Name)) + { + AddAttributeUsage(attributeUsages, entityName, prop.Name, new AttributeUsage(flowName, $"{context} in action '{actionName}'", DetermineOperationTypeFromAction(actionName), SupportedType)); + } + } + } + } + + private void ExtractFieldsFromSchema(JToken schema, string entityName, string flowName, string actionName, Dictionary>> attributeUsages) + { + var properties = schema.SelectToken("properties"); + if (properties is JObject propsObj) + { + foreach (var prop in propsObj.Properties()) + { + if (IsLikelyFieldName(prop.Name)) + { + AddAttributeUsage(attributeUsages, entityName, prop.Name, new AttributeUsage(flowName, $"Output schema in action '{actionName}'", DetermineOperationTypeFromAction(actionName), SupportedType)); + } + } + } + } + + private void ExtractODataParameters(JToken inputs, string entityName, string flowName, string actionName, Dictionary>> attributeUsages) + { + // Check for $select parameter + var select = inputs.SelectToken("parameters.$select")?.ToString(); + if (!string.IsNullOrEmpty(select)) + { + var fields = select.Split(',').Select(f => f.Trim()).Where(f => !string.IsNullOrEmpty(f)); + foreach (var field in fields) + { + AddAttributeUsage(attributeUsages, entityName, field, new AttributeUsage(flowName, $"OData $select in action '{actionName}'", DetermineOperationTypeFromAction(actionName), SupportedType)); + } + } + + // Check for $expand parameter (might contain field references) + var expand = inputs.SelectToken("parameters.$expand")?.ToString(); + if (!string.IsNullOrEmpty(expand)) + { + // Parse expand expressions like "field1,field2($select=subfield1,subfield2)" + var expandFields = ParseExpandParameter(expand); + foreach (var field in expandFields) + { + AddAttributeUsage(attributeUsages, entityName, field, new AttributeUsage(flowName, $"OData $expand in action '{actionName}'", OperationType.Read, SupportedType)); + } + } + } + + private void AnalyzeDynamicContent(JObject flowDefinition, PowerAutomateFlow flow, Dictionary>> attributeUsages) + { + var flowName = flow.Name ?? "Unknown Flow"; + + // Look for dynamic content expressions that reference Dataverse fields + // These typically look like @{outputs('Get_record')?['body/fieldname']} + var dynamicExpressions = ExtractDynamicExpressions(flowDefinition); + + foreach (var expression in dynamicExpressions) + { + var fieldReferences = ParseDynamicExpression(expression); + foreach (var (entityName, fieldName) in fieldReferences) + { + if (!string.IsNullOrEmpty(entityName) && !string.IsNullOrEmpty(fieldName)) + { + AddAttributeUsage(attributeUsages, entityName, fieldName, new AttributeUsage(flowName, $"Dynamic content reference: {expression}", OperationType.Read, SupportedType)); + } + } + } + } + + private IEnumerable ExtractDynamicExpressions(JToken token) + { + var expressions = new List(); + + if (token is JValue value && value.Type == JTokenType.String) + { + var stringValue = value.ToString(); + if (stringValue.Contains("@{") || stringValue.Contains("outputs(")) + { + expressions.Add(stringValue); + } + } + else if (token is JContainer container) + { + foreach (var child in container) + { + expressions.AddRange(ExtractDynamicExpressions(child)); + } + } + + return expressions; + } + + private IEnumerable<(string entityName, string fieldName)> ParseDynamicExpression(string expression) + { + var results = new List<(string, string)>(); + + // Look for patterns like outputs('Action_name')?['body/fieldname'] + var matches = Regex.Matches(expression, @"outputs\('([^']+)'\)\?\['body/([^']+)'\]", RegexOptions.IgnoreCase); + foreach (Match match in matches) + { + var actionName = match.Groups[1].Value; + var fieldName = match.Groups[2].Value; + + // Try to infer entity name from action name or use a placeholder + var entityName = InferEntityNameFromActionName(actionName); + results.Add((entityName, fieldName)); + } + + // Look for other patterns like body('action')?['fieldname'] + matches = Regex.Matches(expression, @"body\('([^']+)'\)\?\['([^']+)'\]", RegexOptions.IgnoreCase); + foreach (Match match in matches) + { + var actionName = match.Groups[1].Value; + var fieldName = match.Groups[2].Value; + + var entityName = InferEntityNameFromActionName(actionName); + results.Add((entityName, fieldName)); + } + + return results; + } + + private string InferEntityNameFromActionName(string actionName) + { + // Try to extract entity name from action names like "Get_contact_record" or "Create_account" + var cleanName = actionName.Replace("_", "").ToLower(); + + // Common patterns + if (cleanName.Contains("contact")) return "contact"; + if (cleanName.Contains("account")) return "account"; + if (cleanName.Contains("lead")) return "lead"; + if (cleanName.Contains("opportunity")) return "opportunity"; + if (cleanName.Contains("case") || cleanName.Contains("incident")) return "incident"; + + // Return a placeholder if we can't determine the entity + return "unknown_entity"; + } + + private IEnumerable ParseExpandParameter(string expand) + { + var fields = new List(); + + // Simple comma-separated fields + var parts = expand.Split(','); + foreach (var part in parts) + { + var trimmed = part.Trim(); + if (trimmed.Contains('(')) + { + // Extract the field name before the parenthesis + var fieldName = trimmed.Substring(0, trimmed.IndexOf('(')); + fields.Add(fieldName); + + // Also extract any nested $select fields + var match = Regex.Match(trimmed, @"\$select=([^)]+)"); + if (match.Success) + { + var nestedFields = match.Groups[1].Value.Split(',').Select(f => f.Trim()); + fields.AddRange(nestedFields); + } + } + else + { + fields.Add(trimmed); + } + } + + return fields.Where(f => !string.IsNullOrEmpty(f) && IsLikelyFieldName(f)); + } + + private bool IsLikelyFieldName(string name) + { + if (string.IsNullOrEmpty(name)) return false; + + // Exclude common system parameters and metadata fields + var systemFields = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "@odata.context", "@odata.etag", "@odata.id", "@odata.type", + "entityName", "entitySetName", "uri", "path", "method", "headers", + "authentication", "retryPolicy", "pagination", "timeout" + }; + + if (systemFields.Contains(name)) return false; + + // Must start with a letter or underscore + if (!char.IsLetter(name[0]) && name[0] != '_') return false; + + // Should contain only letters, numbers, and underscores + return name.All(c => char.IsLetterOrDigit(c) || c == '_'); + } + + private bool IsSystemParameter(string name) + { + var systemParams = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "entityName", "entitySetName", "$select", "$expand", "$filter", "$orderby", "$top", "$skip" + }; + + return systemParams.Contains(name); + } + + private OperationType DetermineOperationTypeFromAction(string actionName) + { + if (string.IsNullOrEmpty(actionName)) + return OperationType.Other; + + var lowerActionName = actionName.ToLowerInvariant(); + + // Create operations + if (lowerActionName.Contains("create") || lowerActionName.Contains("add") || lowerActionName.Contains("insert")) + return OperationType.Create; + + // Update operations + if (lowerActionName.Contains("update") || lowerActionName.Contains("modify") || lowerActionName.Contains("patch")) + return OperationType.Update; + + // Delete operations + if (lowerActionName.Contains("delete") || lowerActionName.Contains("remove")) + return OperationType.Delete; + + // List operations (multiple records) + if (lowerActionName.Contains("list") || lowerActionName.Contains("getitems") || lowerActionName.Contains("listrecords")) + return OperationType.List; + + // Read operations (single record) + if (lowerActionName.Contains("get") || lowerActionName.Contains("retrieve") || lowerActionName.Contains("read")) + return OperationType.Read; + + // Default to Other for unknown actions + return OperationType.Other; + } + + private void AddAttributeUsage(Dictionary>> attributeUsages, + string entityName, string attributeName, AttributeUsage usage) + { + if (!attributeUsages.ContainsKey(entityName)) + { + attributeUsages[entityName] = new Dictionary>(); + } + + if (!attributeUsages[entityName].ContainsKey(attributeName)) + { + attributeUsages[entityName][attributeName] = new List(); + } + + attributeUsages[entityName][attributeName].Add(usage); + } +} diff --git a/Website/.github/instructions/copilot.instructions.md b/Website/.github/instructions/copilot.instructions.md index 2d000e6..6575040 100644 --- a/Website/.github/instructions/copilot.instructions.md +++ b/Website/.github/instructions/copilot.instructions.md @@ -1,4 +1,7 @@ ---- -applyTo: '**' ---- -Read file at `ai-rules/README.md` for instructions on how to use this file. \ No newline at end of file +# 🧠 AI Agent Rules for DataModelViewer Codebase + +You are an expert in **TypeScript**, **Node.js**, **Next.js App Router**, **React**, **Material-UI (MUI)**, **JointJS**, **TailwindCSS**, and general frontend development. + + +# Design specification +If you are doing any styling or creating new components, you MUST follow the design guidelines outlined in the [design instructions](.github/instructions/design/design.instructions.md). diff --git a/Website/.github/instructions/design/design.instructions.md b/Website/.github/instructions/design/design.instructions.md new file mode 100644 index 0000000..cdc0e67 --- /dev/null +++ b/Website/.github/instructions/design/design.instructions.md @@ -0,0 +1,52 @@ +# Introduction +This document provides guidelines how to design components for the project. +The project uses Tailwind CSS for styling. And MUI UI for elements. +You must always follow the design specifications outlined in this document. + +# Styling +Always use Tailwind classes for styling (EXPECT FOR COLORS USE SX FOR CORRECT MUI COLORING). +Always implement responsive design using Tailwind's responsive utilities. +Always add `aria-label` attributes to interactive elements. +Always use tailwind classes over the `sx` prop. +Always use MUI elements where possible. +- Replace `div` with `Box` from MUI. +Always use `Paper` from MUI for card-like components. +Always use `Typography` from MUI for text elements. +Always use MUI Icons for icons. +Never use custom CSS unless absolutely necessary. +- Prioritize Tailwind CSS classes for all styling needs. +- For colors u must use the `sx` prop to ensure correct theming in MUI. +- If you need to add custom CSS, it must be approved first. + +## Colors +Always use the colors from the Tailwind CSS color palette, and ensure that they are applied consistently across both light and dark themes. +You must use colors from the `tailwind.config.ts` file. If you introduce new colors you MUST ask for approval. + +## Typography +For titles nouns must be `font-bold` and use the `font-tdn` font. +The default font must be `font-context`. + +# New components +If you are creating a new component, make sure to follow these guidelines: +- Use MUI components where applicable. +- Use Tailwind CSS classes for styling. +- New TSX components should be placed in the related component folder. E.g. a diagram component should be placed in `components/diagramview` +Components must follow this structure: +``` +import React from 'react'; + +interface ComponentNameProps { + // Define your props here +} + +const ComponentName = ({ }: ComponentNameProps) => { + return ( +
+ {/* Your JSX here */} +
+ ); +}; + +export default ComponentName; +``` + diff --git a/Website/.github/instructions/design/mui.instructions.md b/Website/.github/instructions/design/mui.instructions.md new file mode 100644 index 0000000..6b445ac --- /dev/null +++ b/Website/.github/instructions/design/mui.instructions.md @@ -0,0 +1,156 @@ +# Material UI + +This is the documentation for the Material UI package. +It contains comprehensive guides, components, and utilities for building user interfaces. + +## Components + +- [App Bar React component](https://mui.com/material-ui/react-app-bar.md): The App Bar displays information and actions relating to the current screen. +- [Backdrop React Component](https://mui.com/material-ui/react-backdrop.md): The Backdrop component narrows the user's focus to a particular element on the screen. +- [Bottom Navigation React component](https://mui.com/material-ui/react-bottom-navigation.md): The Bottom Navigation bar allows movement between primary destinations in an app. +- [Circular, Linear progress React components](https://mui.com/material-ui/react-progress.md): Progress indicators commonly known as spinners, express an unspecified wait time or display the length of a process. +- [CSS Baseline](https://mui.com/material-ui/react-css-baseline.md): The CssBaseline component helps to kickstart an elegant, consistent, and simple baseline to build upon. +- [Detect click outside React component](https://mui.com/material-ui/react-click-away-listener.md): The Click-Away Listener component detects when a click event happens outside of its child element. +- [How to customize](https://mui.com/material-ui/customization/how-to-customize.md): Learn how to customize Material UI components by taking advantage of different strategies for specific use cases. +- [Image List React component](https://mui.com/material-ui/react-image-list.md): The Image List displays a collection of images in an organized grid. +- [InitColorSchemeScript component](https://mui.com/material-ui/react-init-color-scheme-script.md): The InitColorSchemeScript component eliminates dark mode flickering in server-side-rendered applications. +- [No SSR React component](https://mui.com/material-ui/react-no-ssr.md): The No-SSR component defers the rendering of children components from the server to the client. +- [React Accordion component](https://mui.com/material-ui/react-accordion.md): The Accordion component lets users show and hide sections of related content on a page. +- [React Alert component](https://mui.com/material-ui/react-alert.md): Alerts display brief messages for the user without interrupting their use of the app. +- [React Autocomplete component](https://mui.com/material-ui/react-autocomplete.md): The autocomplete is a normal text input enhanced by a panel of suggested options. +- [React Avatar component](https://mui.com/material-ui/react-avatar.md): Avatars are found throughout material design with uses in everything from tables to dialog menus. +- [React Box](https://mui.com/material-ui/react-box.md): The Box component is a generic, theme-aware container with access to CSS utilities from MUI System. +- [React Breadcrumbs component](https://mui.com/material-ui/react-breadcrumbs.md): A breadcrumbs is a list of links that help visualize a page's location within a site's hierarchical structure, it allows navigation up to any of the ancestors. +- [React Button component](https://mui.com/material-ui/react-button.md): Buttons allow users to take actions, and make choices, with a single tap. +- [React Button Group component](https://mui.com/material-ui/react-button-group.md): The ButtonGroup component can be used to group related buttons. +- [React Card component](https://mui.com/material-ui/react-card.md): Cards contain content and actions about a single subject. +- [React Checkbox component](https://mui.com/material-ui/react-checkbox.md): Checkboxes allow the user to select one or more items from a set. +- [React Chip component](https://mui.com/material-ui/react-chip.md): Chips are compact elements that represent an input, attribute, or action. +- [React Container component](https://mui.com/material-ui/react-container.md): The container centers your content horizontally. It's the most basic layout element. +- [React Dialog component](https://mui.com/material-ui/react-dialog.md): Dialogs inform users about a task and can contain critical information, require decisions, or involve multiple tasks. +- [React Divider component](https://mui.com/material-ui/react-divider.md): The Divider component provides a thin, unobtrusive line for grouping elements to reinforce visual hierarchy. +- [React Drawer component](https://mui.com/material-ui/react-drawer.md): The navigation drawers (or "sidebars") provide ergonomic access to destinations in a site or app functionality such as switching accounts. +- [React Floating Action Button (FAB) component](https://mui.com/material-ui/react-floating-action-button.md): A Floating Action Button (FAB) performs the primary, or most common, action on a screen. +- [React Grid component](https://mui.com/material-ui/react-grid.md): The responsive layout grid adapts to screen size and orientation, ensuring consistency across layouts. +- [React GridLegacy component](https://mui.com/material-ui/react-grid-legacy.md): The Material Design responsive layout grid adapts to screen size and orientation, ensuring consistency across layouts. +- [React Icon Component](https://mui.com/material-ui/icons.md): Guidance and suggestions for using icons with Material UI. +- [React List component](https://mui.com/material-ui/react-list.md): Lists are continuous, vertical indexes of text or images. +- [React Masonry component](https://mui.com/material-ui/react-masonry.md): Masonry lays out contents of varying dimensions as blocks of the same width and different height with configurable gaps. +- [React Menu component](https://mui.com/material-ui/react-menu.md): Menus display a list of choices on temporary surfaces. +- [React Modal component](https://mui.com/material-ui/react-modal.md): The modal component provides a solid foundation for creating dialogs, popovers, lightboxes, or whatever else. +- [React Pagination component](https://mui.com/material-ui/react-pagination.md): The Pagination component enables the user to select a specific page from a range of pages. +- [React Popover component](https://mui.com/material-ui/react-popover.md): A Popover can be used to display some content on top of another. +- [React Portal component](https://mui.com/material-ui/react-portal.md): The Portal component lets you render its children into a DOM node that exists outside of the Portal's own DOM hierarchy. +- [React Radio Group component](https://mui.com/material-ui/react-radio-button.md): The Radio Group allows the user to select one option from a set. +- [React Rating component](https://mui.com/material-ui/react-rating.md): Ratings provide insight regarding others' opinions and experiences, and can allow the user to submit a rating of their own. +- [React Select component](https://mui.com/material-ui/react-select.md): Select components are used for collecting user provided information from a list of options. +- [React Skeleton component](https://mui.com/material-ui/react-skeleton.md): Display a placeholder preview of your content before the data gets loaded to reduce load-time frustration. +- [React Slider component](https://mui.com/material-ui/react-slider.md): Sliders allow users to make selections from a range of values. +- [React Snackbar component](https://mui.com/material-ui/react-snackbar.md): Snackbars (also known as toasts) are used for brief notifications of processes that have been or will be performed. +- [React Speed Dial component](https://mui.com/material-ui/react-speed-dial.md): When pressed, a floating action button can display three to six related actions in the form of a Speed Dial. +- [React Stack component](https://mui.com/material-ui/react-stack.md): Stack is a container component for arranging elements vertically or horizontally. +- [React Stepper component](https://mui.com/material-ui/react-stepper.md): Steppers convey progress through numbered steps. It provides a wizard-like workflow. +- [React Switch component](https://mui.com/material-ui/react-switch.md): Switches toggle the state of a single setting on or off. +- [React Table component](https://mui.com/material-ui/react-table.md): Tables display sets of data. They can be fully customized. +- [React Tabs component](https://mui.com/material-ui/react-tabs.md): Tabs make it easy to explore and switch between different views. +- [React Text Field component](https://mui.com/material-ui/react-text-field.md): Text Fields let users enter and edit text. +- [React Timeline component](https://mui.com/material-ui/react-timeline.md): The timeline displays a list of events in chronological order. +- [React Tooltip component](https://mui.com/material-ui/react-tooltip.md): Tooltips display informative text when users hover over, focus on, or tap an element. +- [React Transition component](https://mui.com/material-ui/transitions.md): Transitions help to make a UI expressive and easy to use. +- [Textarea Autosize React component](https://mui.com/material-ui/react-textarea-autosize.md): The Textarea Autosize component automatically adjusts its height to match the length of the content within. +- [Toggle Button React component](https://mui.com/material-ui/react-toggle-button.md): A Toggle Button can be used to group related options. + +## Getting Started + +- [Design resources](https://mui.com/material-ui/getting-started/design-resources.md): Be more efficient designing and developing with the same library. +- [Example projects](https://mui.com/material-ui/getting-started/example-projects.md): A collection of examples and scaffolds integrating Material UI with popular libraries and frameworks. +- [Frequently Asked Questions](https://mui.com/material-ui/getting-started/faq.md): Stuck on a particular problem? Check some of these common gotchas first in the FAQ. +- [Installation](https://mui.com/material-ui/getting-started/installation.md): Install Material UI, the world's most popular React UI framework. +- [Learning resources](https://mui.com/material-ui/getting-started/learn.md): New to Material UI? Get up to speed quickly with our curated list of learning resources. +- [Model Context Protocol (MCP) for MUI](https://mui.com/material-ui/getting-started/mcp.md): Access the official Material UI docs and code examples in your AI client. +- [Overview](https://mui.com/material-ui/getting-started/overview.md): Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box. +- [Support](https://mui.com/material-ui/getting-started/support.md): Learn how to get support for Material UI components, including feature requests, bug fixes, and technical support from the team. +- [Supported components](https://mui.com/material-ui/getting-started/supported-components.md): The following is a list of Material Design components & features. +- [Supported platforms](https://mui.com/material-ui/getting-started/supported-platforms.md): Learn about the platforms, from modern to old, that are supported by Material UI. +- [New Free React Templates](https://mui.com/material-ui/getting-started/templates.md): Browse our collection of free React templates to get started building your app with Material UI, including a React dashboard, React marketing page, and more. +- [Usage](https://mui.com/material-ui/getting-started/usage.md): Learn the basics of working with Material UI components. + +## Templates + +- [Blog template](https://mui.com/material-ui/getting-started/templates/blog.md) +- [Checkout template](https://mui.com/material-ui/getting-started/templates/checkout.md) +- [CRUD dashboard template](https://mui.com/material-ui/getting-started/templates/crud-dashboard.md) +- [Dashboard template](https://mui.com/material-ui/getting-started/templates/dashboard.md) +- [Marketing page template](https://mui.com/material-ui/getting-started/templates/marketing-page.md) +- [Sign-in template](https://mui.com/material-ui/getting-started/templates/sign-in.md) +- [Sign-in side template](https://mui.com/material-ui/getting-started/templates/sign-in-side.md) +- [Sign-up template](https://mui.com/material-ui/getting-started/templates/sign-up.md) + +## Customization + +- [Breakpoints](https://mui.com/material-ui/customization/breakpoints.md): API that enables the use of breakpoints in a wide variety of contexts. +- [Color](https://mui.com/material-ui/customization/color.md): Convey meaning through color. Out of the box you get access to all colors in the Material Design guidelines. +- [Container queries](https://mui.com/material-ui/customization/container-queries.md): Material UI provides a utility function for creating CSS container queries based on theme breakpoints. +- [Creating themed components](https://mui.com/material-ui/customization/creating-themed-components.md): Learn how to create fully custom components that accept your app's theme. +- [CSS Layers](https://mui.com/material-ui/customization/css-layers.md): Learn how to generate Material UI styles with cascade layers. +- [CSS theme variables - Configuration](https://mui.com/material-ui/customization/css-theme-variables.md): A guide for configuring CSS theme variables in Material UI. +- [CSS theme variables - Native color](https://mui.com/material-ui/customization/css-theme-variables.md): Learn how to use native color with CSS theme variables. +- [CSS theme variables](https://mui.com/material-ui/customization/css-theme-variables.md): An overview of adopting CSS theme variables in Material UI. +- [CSS theme variables - Usage](https://mui.com/material-ui/customization/css-theme-variables.md): Learn how to adopt CSS theme variables. +- [Dark mode](https://mui.com/material-ui/customization/dark-mode.md): Material UI comes with two palette modes: light (the default) and dark. +- [Default theme viewer](https://mui.com/material-ui/customization/default-theme.md): This tree view allows you to explore how the theme object looks like with the default values. +- [Density](https://mui.com/material-ui/customization/density.md): How to apply density to Material UI components. +- [How to customize](https://mui.com/material-ui/customization/how-to-customize.md): Learn how to customize Material UI components by taking advantage of different strategies for specific use cases. +- [Overriding component structure](https://mui.com/material-ui/customization/overriding-component-structure.md): Learn how to override the default DOM structure of Material UI components. +- [Palette](https://mui.com/material-ui/customization/palette.md): The palette enables you to modify the color of the components to suit your brand. +- [Right-to-left support](https://mui.com/material-ui/customization/right-to-left.md): Learn how to implement right-to-left (RTL) text with Material UI to support languages such as Arabic, Persian, and Hebrew. +- [Shadow DOM](https://mui.com/material-ui/customization/shadow-dom.md): The shadow DOM lets you encapsulate parts of an app to keep them separate from global styles that target the regular DOM tree. +- [Spacing](https://mui.com/material-ui/customization/spacing.md): Use the theme.spacing() helper to create consistent spacing between the elements of your UI. +- [Themed components](https://mui.com/material-ui/customization/theme-components.md): You can customize a component's styles, default props, and more by using its component key inside the theme. +- [Theming](https://mui.com/material-ui/customization/theming.md): Customize Material UI with your theme. You can change the colors, the typography and much more. +- [Transitions](https://mui.com/material-ui/customization/transitions.md): These theme helpers allow you to create custom CSS transitions, you can customize the durations, easings and more. +- [Typography](https://mui.com/material-ui/customization/typography.md): The theme provides a set of type sizes that work well together, and also with the layout grid. +- [z-index](https://mui.com/material-ui/customization/z-index.md): z-index is the CSS property that helps control layout by providing a third axis to arrange content. + +## Experimental Api + +- [ClassName generator](https://mui.com/material-ui/experimental-api/classname-generator.md): Configure classname generation at build time. +- [Getting started with Pigment CSS](https://mui.com/material-ui/experimental-api/pigment-css.md): Learn how to get started customizing your components using Pigment CSS. + +## Guides + +- [API design approach](https://mui.com/material-ui/guides/api.md): We have learned a great deal regarding how Material UI is used, and the v1 rewrite allowed us to completely rethink the component API. +- [Composition](https://mui.com/material-ui/guides/composition.md): Material UI tries to make composition as easy as possible. +- [Content Security Policy (CSP)](https://mui.com/material-ui/guides/content-security-policy.md): This section covers the details of setting up a CSP. +- [Localization](https://mui.com/material-ui/guides/localization.md): Localization (also referred to as "l10n") is the process of adapting a product or content to a specific locale or market. +- [Minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size.md): Learn how to reduce your bundle size and improve development performance by avoiding costly import patterns. +- [Responsive UI](https://mui.com/material-ui/guides/responsive-ui.md): Material Design layouts encourage consistency across platforms, environments, and screen sizes by using uniform elements and spacing. +- [Server rendering](https://mui.com/material-ui/guides/server-rendering.md): The most common use case for server-side rendering is to handle the initial render when a user (or search engine crawler) first requests your app. +- [Testing](https://mui.com/material-ui/guides/testing.md): Write tests to prevent regressions and write better code. +- [TypeScript](https://mui.com/material-ui/guides/typescript.md): You can add static typing to JavaScript to improve developer productivity and code quality thanks to TypeScript. + +## Integrations + +- [Style library interoperability](https://mui.com/material-ui/integrations/interoperability.md): While you can use the Emotion-based styling solution provided by Material UI, you can also use the one you already know, from plain CSS to styled-components. +- [Next.js integration](https://mui.com/material-ui/integrations/nextjs.md): Learn how to use Material UI with Next.js. +- [Routing libraries](https://mui.com/material-ui/integrations/routing.md): By default, the navigation is performed with a native <a> element. You can customize it, for instance, using Next.js's Link or react-router. +- [Using styled-components](https://mui.com/material-ui/integrations/styled-components.md): Learn how to use styled-components instead of Emotion with Material UI. +- [Tailwind CSS v4 integration](https://mui.com/material-ui/integrations/tailwindcss.md): Learn how to use Material UI with Tailwind CSS v4. +- [Theme scoping](https://mui.com/material-ui/integrations/theme-scoping.md): Learn how to use multiple styling solutions in a single Material UI app. + +## Migration + +- [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis.md): Learn how to migrate away from recently deprecated APIs before they become breaking changes. +- [Migration from v0.x to v1](https://mui.com/material-ui/migration/migration-v0x.md): Yeah, v1 has been released! Take advantage of 2 years worth of effort. +- [Migration from v3 to v4](https://mui.com/material-ui/migration/migration-v3.md): Yeah, v4 has been released! +- [Migrating from JSS (optional)](https://mui.com/material-ui/migration/migration-v4.md): This guide explains how to migrate from JSS to Emotion when updating from Material UI v4 to v5. +- [Migrating to v5: getting started](https://mui.com/material-ui/migration/migration-v4.md): This guide explains how and why to migrate from Material UI v4 to v5. +- [Troubleshooting](https://mui.com/material-ui/migration/migration-v4.md): This document covers known issues and common problems encountered when migrating from Material UI v4 to v5. +- [Breaking changes in v5, part two: core components](https://mui.com/material-ui/migration/migration-v4.md): This is a reference guide to the breaking changes introduced in Material UI v5, and how to migrating from v4. This part covers changes to components. +- [Breaking changes in v5, part one: styles and themes](https://mui.com/material-ui/migration/migration-v4.md): This is a reference guide to the breaking changes introduced in Material UI v5, and how to migrating from v4. This part covers changes to styling and theming. +- [Migration from @material-ui/pickers](https://mui.com/material-ui/migration/pickers-migration.md):

@material-ui/pickers was moved to the @mui/lab.

+- [Upgrade to Grid v2](https://mui.com/material-ui/migration/upgrade-to-grid-v2.md): This guide explains how and why to migrate from the GridLegacy component to the Grid component. +- [Migrating to Pigment CSS](https://mui.com/material-ui/migration/upgrade-to-v6.md): This guide helps you integrate Pigment CSS with Material UI. +- [Upgrade to v6](https://mui.com/material-ui/migration/upgrade-to-v6.md): This guide explains why and how to upgrade from Material UI v5 to v6. +- [Upgrade to native color](https://mui.com/material-ui/migration/upgrade-to-v7.md): This guide explains how to upgrade from JavaScript color manipulation to native color. +- [Upgrade to v7](https://mui.com/material-ui/migration/upgrade-to-v7.md): This guide explains how to upgrade from Material UI v6 to v7. \ No newline at end of file diff --git a/Website/.gitignore b/Website/.gitignore index d38a02d..52090fa 100644 --- a/Website/.gitignore +++ b/Website/.gitignore @@ -41,3 +41,6 @@ next-env.d.ts # attachments /public/.attachments + +# VS Settings +/.vscode \ No newline at end of file diff --git a/Website/ai-rules/README.md b/Website/ai-rules/README.md deleted file mode 100644 index 7e87b82..0000000 --- a/Website/ai-rules/README.md +++ /dev/null @@ -1,416 +0,0 @@ -# 🧠 AI Agent Rules for DataModelViewer Codebase - -You are an expert in **TypeScript**, **Node.js**, **Next.js App Router**, **React**, **Radix**, **JointJS**, **TailwindCSS**, and general frontend development. - ---- - -## 📘 Project Overview - -This is a **DataModelViewer** built with Next.js 15, React 19, TypeScript, and JointJS for data model visualization. It uses a modern tech stack including **shadcn/ui**, **Tailwind CSS**, and follows React best practices. - ---- - -## 🛠 Core Technologies & Dependencies - -- **Framework**: Next.js 15 (App Router) -- **UI Library**: React 19 -- **Language**: TypeScript (strict mode) -- **Styling**: Tailwind CSS + shadcn/ui -- **Diagram Library**: JointJS (@joint/core v4.1.3) -- **Icons**: Lucide React -- **Utilities**: Lodash, clsx, tailwind-merge -- **Authentication**: jose (JWT) - ---- - -## 🏗 Architecture Patterns - -### 📂 1. File Structure -``` -Website/ -├── app/ # Next.js App Router -├── components/ # Reusable components -│ ├── ui/ # shadcn/ui components -│ ├── diagram/ # Diagram-specific -│ └── entity/ # Entity components -├── contexts/ # React Context -├── hooks/ # Custom hooks -├── lib/ # Utilities/constants -├── routes/ # Route components -└── public/ # Static assets -``` - ---- - -### 🧩 2. Component Architecture -- Use **functional components** and hooks. -- Always **strictly type** props and state. -- Define **props interfaces**. -- Use destructuring with defaults. - ---- - -### ⚙️ 3. State Management -- **React Context** for global state (e.g., `DiagramContext`). -- **Custom Hooks** for complex logic (`useDiagram`, `useEntitySelection`). -- **useState** for local state. -- **useRef** for mutable values not requiring re-renders. - ---- - -## 🧑‍💻 Coding Standards - -### 1️⃣ TypeScript Conventions -```typescript -interface ComponentProps { - data: EntityData; - onSelect?: (id: string) => void; - className?: string; -} - -const handleClick = (e: React.MouseEvent) => { - // handler logic -}; - -const useCustomHook = (): CustomHookReturn => { - // hook logic -}; -``` - ---- - -### 2️⃣ Component Patterns -```typescript -interface IComponentName { - data: number[]; - onSelect: () => void; - className: string; -} - -function ComponentName({ data, onSelect, className }: IComponentName) { - const [state, setState] = useState(); - - useEffect(() => { - // effect - }, [dependencies]); - - const handleAction = useCallback(() => { - // action - }, [dependencies]); - - return ( -
- {/* content */} -
- ); -} -``` - ---- - -### 3️⃣ Styling Conventions -- Use **Tailwind utility classes**. -- For variants, use **class-variance-authority**. -- Ensure **responsive design**. - ---- - -## 🟢 Diagram-Specific Rules - -### 1️⃣ JointJS Integration - -1. **Model and View Separation** - - Keep model logic separate from view rendering. - - Define `joint.dia.Element` and `joint.dia.Link` for business data. - - Use `joint.shapes` for reusable shapes. - - Use `ElementView` for rendering/UI. - -2. **Graph as Single Source of Truth** - - Always store state in `joint.dia.Graph`. - - Never rely on paper alone. - - Use `element.set()` to trigger events. - -3. **Batch Operations** - ```typescript - graph.startBatch('batch-updates'); - graph.addCells([cell1, cell2, link]); - cell1.resize(100, 80); - graph.stopBatch('batch-updates'); - ``` - -4. **Unique IDs** - - Ensure each element/link has a unique `id`. - -5. **Paper Events** - - Use events (`cell:pointerdown`, `element:pointerclick`) for interactions. - - Avoid mixing DOM events. - -6. **Memory Cleanup** - - Call `paper.remove()` and `graph.clear()` when destroying. - - Remove listeners. - -7. **Debounce/Throttle** - - Throttle high-frequency handlers (`cell:position`). - -8. **Styling** - - Use Tailwind classes over hardcoded styles. - ---- - -### 2️⃣ Entity Element Patterns -- **Custom Elements**: Extend JointJS. -- **Ports**: Consistent naming. -- **Data Binding**: Link model data to visuals. -- **Events**: Proper interaction handling. - ---- - -## 📝 File Naming - -- **Components**: PascalCase (`DiagramCanvas.tsx`) -- **Hooks**: camelCase with `use` (`useDiagram.ts`) -- **Utilities**: camelCase (`utils.ts`) -- **Shared Types**: `types.ts` - ---- - -## 🧷 Import & Export - -### Import Organization -```typescript -// React & Next.js -import React, { useState } from 'react'; -import { useRouter } from 'next/navigation'; - -// Third-party -import { dia } from '@joint/core'; -import { Button } from '@/components/ui/button'; - -// Local -import { useDiagramContext } from '@/contexts/DiagramContext'; -import { cn } from '@/lib/utils'; - -// Relative -import { EntityElement } from './entity/entity'; -``` - ---- - -### Export Patterns -```typescript -// Named component -export const ComponentName: React.FC = () => {}; - -// Default page -export default function PageName() {} - -// Utilities -export function utilityFunction() {} -export const CONSTANT_VALUE = 'value'; -``` - ---- - -## 🚀 Performance Guidelines - -### React -- `useCallback` for handlers. -- `useMemo` for expensive computations. -- `React.memo` for frequently re-rendered components. -- Always include dependencies in hooks. - ---- - -### Diagram -- **Debounce** expensive handlers. -- **Clean up** listeners. -- **Refs over state** for mutable values. -- **Batch** updates. - ---- - -### Bundle -- Use **dynamic imports** for large components. -- Ensure **tree shaking**. -- Leverage **Next.js code splitting**. - ---- - -## ⚠️ Error Handling - -### TypeScript -- Strict mode. -- Type guards. -- Optional chaining. -- Null checks. - ---- - -### Runtime -- Error boundaries. -- Try/catch for async. -- Validate all props and data. - ---- - -## 🧪 Testing - -### Components -- Unit tests. -- Integration tests. -- Accessibility tests. - ---- - -### Diagram -- Mock JointJS. -- Test interactions and state. - ---- - -## 🔒 Security - -### Authentication -- Use **jose** for JWT. -- Protect routes. -- Validate inputs. - ---- - -### Data -- Sanitize before rendering. -- Escape output (prevent XSS). -- Use CSRF protection if needed. - ---- - -## 🗂 Documentation Standards - -- Use **JSDoc** for complex logic. -- Add **inline comments** where necessary. -- Include **TODOs** for incomplete work. -- Document setup, usage, and architecture in README. - ---- - -## 🏷 Common Patterns - -### Custom Hook -```typescript -export const useCustomHook = (): HookReturn => { - const [state, setState] = useState(initialState); - - const action = useCallback(() => { - // logic - }, []); - - useEffect(() => { - // setup - return () => { - // cleanup - }; - }, []); - - return { state, action }; -}; -``` - ---- - -### Context Provider -```typescript -const Context = createContext(null); - -export const Provider: React.FC = ({ children }) => { - const value = useCustomHook(); - return {children}; -}; - -export const useContext = (): ContextType => { - const context = useContext(Context); - if (!context) throw new Error('Must be used within Provider'); - return context; -}; -``` - ---- - -### Component Composition -```typescript -const ParentComponent = () => ( - - - -); - -const ChildComponent = () => { - const context = useContext(); - return
{/* Use context */}
; -}; -``` - ---- - -## 🚫 Anti-Patterns to Avoid - -### React -- Avoid `useState` for refs—use `useRef`. -- Don’t create objects in render—use `useMemo`. -- Always clean up effects. -- Never mutate state directly. - ---- - -### Diagram -- Don’t reinitialize `paper` unnecessarily—use refs. -- Always clean up event listeners. -- Avoid storing zoom/pan in React state. -- Debounce expensive ops. - ---- - -### TypeScript -- Avoid `any`. -- Fix all errors—don’t ignore them. -- Use type guards over assertions. -- Always check for `null`. - ---- - -## 🧭 Migration Guidelines - -### Updating Dependencies -- Review changelogs for breaking changes. -- Update gradually. -- Test thoroughly. -- Verify TypeScript compatibility. - ---- - -### Refactoring -- Preserve functionality. -- Update tests. -- Document changes. -- Validate performance. - ---- - -## 🆘 Emergency Procedures - -### When Things Break -- Check console errors. -- Inspect network requests. -- Verify React state/context. -- Roll back via Git if needed. - ---- - -### Performance Issues -- Profile with React DevTools. -- Check for excessive re-renders. -- Analyze bundle size. -- Apply optimizations. - ---- - -**Remember:** Prioritize clarity and maintainability. When in doubt, follow established patterns and documented practices. diff --git a/Website/app/about/page.tsx b/Website/app/about/page.tsx index 7cf8725..a564229 100644 --- a/Website/app/about/page.tsx +++ b/Website/app/about/page.tsx @@ -1,15 +1,13 @@ import { AboutView } from '@/components/aboutview/AboutView'; -import { TouchProvider } from '@/components/shared/ui/hybridtooltop'; -import { Loading } from '@/components/shared/ui/loading'; -import { TooltipProvider } from '@/components/shared/ui/tooltip'; +import Layout from '@/components/shared/Layout'; import React, { Suspense } from 'react' export default function About() { - return }> - - - - - - + return ( + + + + + + ) } diff --git a/Website/app/api/auth/logout/route.ts b/Website/app/api/auth/logout/route.ts new file mode 100644 index 0000000..cd99ace --- /dev/null +++ b/Website/app/api/auth/logout/route.ts @@ -0,0 +1,18 @@ +'use server'; + +import { NextResponse } from "next/server"; +import { deleteSession } from "@/lib/session"; + +export async function POST() { + try { + await deleteSession(); + // Return success response instead of redirect since we handle navigation client-side + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Logout error:', error); + return NextResponse.json( + { error: 'Failed to logout' }, + { status: 500 } + ); + } +} diff --git a/Website/app/api/auth/session/route.ts b/Website/app/api/auth/session/route.ts new file mode 100644 index 0000000..360f73b --- /dev/null +++ b/Website/app/api/auth/session/route.ts @@ -0,0 +1,20 @@ +import { NextResponse } from "next/server"; +import { getSession } from "@/lib/session"; + +export async function GET() { + try { + const session = await getSession(); + const isAuthenticated = session !== null; + + return NextResponse.json({ + isAuthenticated, + user: isAuthenticated ? { authenticated: true } : null + }); + } catch (error) { + console.error('Session check error:', error); + return NextResponse.json( + { isAuthenticated: false, user: null }, + { status: 500 } + ); + } +} diff --git a/Website/app/diagram/page.tsx b/Website/app/diagram/page.tsx index f079359..bbda9bd 100644 --- a/Website/app/diagram/page.tsx +++ b/Website/app/diagram/page.tsx @@ -1,17 +1,18 @@ "use client"; -import { TouchProvider } from "@/components/shared/ui/hybridtooltop"; -import { Loading } from "@/components/shared/ui/loading"; import DiagramView from "@/components/diagramview/DiagramView"; +import Layout from "@/components/shared/Layout"; +import { DiagramViewProvider } from "@/contexts/DiagramViewContext"; import { Suspense } from "react"; -import { TooltipProvider } from "@/components/shared/ui/tooltip"; export default function Home() { - return }> - - + return ( + + + - - + + + ) } \ No newline at end of file diff --git a/Website/app/fonts/GeistMonoVF.woff b/Website/app/fonts/GeistMonoVF.woff deleted file mode 100644 index f2ae185..0000000 Binary files a/Website/app/fonts/GeistMonoVF.woff and /dev/null differ diff --git a/Website/app/fonts/GeistVF.woff b/Website/app/fonts/GeistVF.woff deleted file mode 100644 index 1b62daa..0000000 Binary files a/Website/app/fonts/GeistVF.woff and /dev/null differ diff --git a/Website/app/globals.css b/Website/app/globals.css index 627a47d..5918581 100644 --- a/Website/app/globals.css +++ b/Website/app/globals.css @@ -1,94 +1,164 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@layer theme, base, mui, components, utilities; +@import 'tailwindcss'; -body { - font-family: Arial, Helvetica, sans-serif; +@theme { + --breakpoint-md: 56.25rem; /* 900px to match use-mobile.tsx MOBILE_BREAKPOINT */ } -@layer base { +@layer theme { :root { - --background: 0 0% 100%; - --foreground: 240 10% 3.9%; - --card: 0 0% 100%; - --card-foreground: 240 10% 3.9%; - --popover: 0 0% 100%; - --popover-foreground: 240 10% 3.9%; - --primary: 240 5.9% 10%; - --primary-foreground: 0 0% 98%; - --secondary: 240 4.8% 95.9%; - --secondary-foreground: 240 5.9% 10%; - --muted: 240 4.8% 95.9%; - --muted-foreground: 240 3.8% 46.1%; - --accent: 240 4.8% 95.9%; - --accent-foreground: 240 5.9% 10%; - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 0 0% 98%; - --border: 240 5.9% 90%; - --input: 240 5.9% 90%; - --ring: 240 10% 3.9%; - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; - --radius: 0.5rem; - --sidebar-background: 0 0% 98%; - --sidebar-foreground: 240 5.3% 26.1%; - --sidebar-primary: 240 5.9% 10%; - --sidebar-primary-foreground: 0 0% 98%; - --sidebar-accent: 240 4.8% 95.9%; - --sidebar-accent-foreground: 240 5.9% 10%; - --sidebar-border: 220 13% 91%; - --sidebar-ring: 217.2 91.2% 59.8%; - } - .dark { - --background: 240 10% 3.9%; - --foreground: 0 0% 98%; - --card: 240 10% 3.9%; - --card-foreground: 0 0% 98%; - --popover: 240 10% 3.9%; - --popover-foreground: 0 0% 98%; - --primary: 0 0% 98%; - --primary-foreground: 240 5.9% 10%; - --secondary: 240 3.7% 15.9%; - --secondary-foreground: 0 0% 98%; - --muted: 240 3.7% 15.9%; - --muted-foreground: 240 5% 64.9%; - --accent: 240 3.7% 15.9%; - --accent-foreground: 0 0% 98%; - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 0% 98%; - --border: 240 3.7% 15.9%; - --input: 240 3.7% 15.9%; - --ring: 240 4.9% 83.9%; - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - --sidebar-background: 240 5.9% 10%; - --sidebar-foreground: 240 4.8% 95.9%; - --sidebar-primary: 224.3 76.3% 48%; - --sidebar-primary-foreground: 0 0% 100%; - --sidebar-accent: 240 3.7% 15.9%; - --sidebar-accent-foreground: 240 4.8% 95.9%; - --sidebar-border: 240 3.7% 15.9%; - --sidebar-ring: 217.2 91.2% 59.8%; + --font-family-sans: "Roboto", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + + --layout-sidebar-desktop-width: 72px; + --layout-sidebar-desktop-expanded-width: 332px; + --layout-header-desktop-height: 72px; } } @layer base { * { - @apply border-border; + border-color: hsl(var(--border)); } + body { - @apply bg-background text-foreground; + color: hsl(var(--foreground)); + background: hsl(var(--background)); + font-feature-settings: "rlig" 1, "calt" 1; + } + + /* Disable uppercase text transformation for all buttons */ + button, + .MuiButton-root { + text-transform: none !important; } } @layer utilities { - .striped tr:nth-child(even) { - @apply bg-gray-100 + .no-scrollbar::-webkit-scrollbar { + display: none; + } + + .no-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; + } + + .h-header { + height: var(--layout-header-desktop-height); + } + + .max-h-header { + max-height: var(--layout-header-desktop-height); + } + + .min-h-header { + min-height: var(--layout-header-desktop-height); + } + + .mt-header { + margin-top: var(--layout-header-desktop-height); + } + + .w-sidebar { + width: var(--layout-sidebar-desktop-width); + } + + .w-sidebar-expanded { + width: var(--layout-sidebar-desktop-expanded-width); + } + + /* Fix autocomplete styling */ + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 30px white inset !important; + -webkit-text-fill-color: inherit !important; + transition: background-color 5000s ease-in-out 0s; + } + + /* Dark mode autocomplete fix */ + @media (prefers-color-scheme: dark) { + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 30px #1a1a1a inset !important; + } + } + + /* Carousel slide animations */ + @keyframes slideInRight { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } + } + + @keyframes slideInLeft { + from { + transform: translateX(-100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } + } + + @keyframes slideOutRight { + from { + transform: translateX(0); + opacity: 1; + } + to { + transform: translateX(100%); + opacity: 0; + } + } + + @keyframes slideOutLeft { + from { + transform: translateX(0); + opacity: 1; + } + to { + transform: translateX(-100%); + opacity: 0; + } + } + + .animate-slideInRight { + animation: slideInRight 0.5s ease-out forwards; + } + + .animate-slideInLeft { + animation: slideInLeft 0.5s ease-out forwards; + } + + .animate-slideOutRight { + animation: slideOutRight 0.5s ease-out forwards; + } + + .animate-slideOutLeft { + animation: slideOutLeft 0.5s ease-out forwards; + } + + /* Custom slow spin animation */ + .animate-spin-slow { + animation: spin 5s linear infinite; + } + + @keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } } \ No newline at end of file diff --git a/Website/app/layout.tsx b/Website/app/layout.tsx index 4cad0a8..599e2b6 100644 --- a/Website/app/layout.tsx +++ b/Website/app/layout.tsx @@ -1,18 +1,10 @@ import type { Metadata } from "next"; -import localFont from "next/font/local"; import "./globals.css"; import { SidebarProvider } from "@/contexts/SidebarContext"; - -const geistSans = localFont({ - src: "./fonts/GeistVF.woff", - variable: "--font-geist-sans", - weight: "100 900", -}); -const geistMono = localFont({ - src: "./fonts/GeistMonoVF.woff", - variable: "--font-geist-mono", - weight: "100 900", -}); +import { SettingsProvider } from "@/contexts/SettingsContext"; +import { AuthProvider } from "@/contexts/AuthContext"; +import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter'; +import { DatamodelViewProvider } from "@/contexts/DatamodelViewContext"; export const metadata: Metadata = { title: "Data Model Viewer", @@ -24,14 +16,26 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { + return ( - - - {children} - + + + + + + + + + + + + {children} + + + + + ); diff --git a/Website/app/login/page.tsx b/Website/app/login/page.tsx index c15bffa..8abf24c 100644 --- a/Website/app/login/page.tsx +++ b/Website/app/login/page.tsx @@ -1,122 +1,12 @@ 'use client'; -import { Button } from "@/components/shared/ui/button"; -import { Input } from "@/components/shared/ui/input"; -import { createSession } from "@/lib/session"; -import { useRouter } from "next/navigation"; -import { FormEvent, useState, useEffect } from "react"; -import { Eye, EyeOff } from "lucide-react"; -import { LastSynched } from "@/generated/Data"; +import LoginView from "@/components/loginview/LoginView"; +import Layout from "@/components/shared/Layout"; export default function LoginPage() { - const router = useRouter(); - const [showPassword, setShowPassword] = useState(false); - const [version, setVersion] = useState(null); - - useEffect(() => { - fetch('/api/version') - .then((res) => res.json()) - .then((data) => setVersion(data.version)) - .catch(() => setVersion('Unknown')) - }, []); - - async function handleSubmit(event: FormEvent) { - event.preventDefault(); - - const formData = new FormData(event.currentTarget); - const password = formData.get("password") - - const response = await fetch("/api/auth/login", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ password }), - }); - - if (response.ok) { - await createSession(password?.valueOf() as string); - router.push("/"); - } else { - alert("Failed to login"); - } - } - return ( -
-
- - {/* Logo and Header */} -
-
- Data Model Viewer Logo -
-
- - {/* Login Form */} -
- -

Enter model password

-

Welcome back

- - -
-
-
- - -
-
- - -
-
- - {/* Footer Information */} -
-
- Last synchronization: {LastSynched ? LastSynched.toLocaleString('en-DK', { - timeZone: 'Europe/Copenhagen', - timeZoneName: 'short', - year: 'numeric', - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit' - }) : '...'} -
-
- Version: {version ?? '...'} -
-
-
-
- ); + + + + ) } \ No newline at end of file diff --git a/Website/app/metadata/page.tsx b/Website/app/metadata/page.tsx index 0c0b5b9..b422cff 100644 --- a/Website/app/metadata/page.tsx +++ b/Website/app/metadata/page.tsx @@ -1,18 +1,16 @@ import { DatamodelView } from "@/components/datamodelview/DatamodelView"; -import { TouchProvider } from "@/components/shared/ui/hybridtooltop"; -import { Loading } from "@/components/shared/ui/loading"; -import { TooltipProvider } from "@/components/shared/ui/tooltip"; import { DatamodelDataProvider } from "@/contexts/DatamodelDataContext"; +import Layout from "@/components/shared/Layout"; import { Suspense } from "react"; export default function Data() { - return }> - - - - - - - + return ( + + + + + + + ) } diff --git a/Website/app/page.tsx b/Website/app/page.tsx index a52da11..89ae9a8 100644 --- a/Website/app/page.tsx +++ b/Website/app/page.tsx @@ -1,15 +1,14 @@ import { HomeView } from "@/components/homeview/HomeView"; -import { TouchProvider } from "@/components/shared/ui/hybridtooltop"; -import { Loading } from "@/components/shared/ui/loading"; -import { TooltipProvider } from "@/components/shared/ui/tooltip"; +import Layout from "@/components/shared/Layout"; import { Suspense } from "react"; export default function Data() { - return }> - - - - - + // TODO - loading component fallback={} + return ( + + + + + ); } diff --git a/Website/app/processes/page.tsx b/Website/app/processes/page.tsx new file mode 100644 index 0000000..dc2d539 --- /dev/null +++ b/Website/app/processes/page.tsx @@ -0,0 +1,16 @@ +import { ProcessesView } from '@/components/processesview/ProcessesView'; +import { DatamodelDataProvider } from "@/contexts/DatamodelDataContext"; +import Layout from '@/components/shared/Layout'; +import React, { Suspense } from 'react' + +export default function Processes() { + return ( + + + + + + + + ) +} diff --git a/Website/components/aboutview/AboutView.tsx b/Website/components/aboutview/AboutView.tsx index c50c2fb..6f6e0e4 100644 --- a/Website/components/aboutview/AboutView.tsx +++ b/Website/components/aboutview/AboutView.tsx @@ -1,110 +1,150 @@ 'use client' import React, { useEffect, useState } from 'react' -import { AppSidebar } from '../shared/AppSidebar' -import { useSidebarDispatch } from '@/contexts/SidebarContext' -import { TooltipProvider } from '@radix-ui/react-tooltip' +import { useSidebar } from '@/contexts/SidebarContext' import { LastSynched } from '@/generated/Data' +import { Box, Typography, Link, Paper } from '@mui/material' interface IAboutViewProps {} export const AboutView = ({}: IAboutViewProps) => { - const dispatch = useSidebarDispatch() + const { setElement, dispatch, close } = useSidebar() const [version, setVersion] = useState(null) useEffect(() => { - dispatch({ type: 'SET_ELEMENT', payload: <> }) - dispatch({ type: 'SET_SHOW_ELEMENT', payload: false }); + setElement(null); + close(); fetch('/api/version') .then((res) => res.json()) .then((data) => setVersion(data.version)) - }, []) + }, [setElement, dispatch]) return ( -
- - -
- -
+ + + {/* Logo */} -
- + -
+
{/* What is DMV */} -
-
-

+ + + What is Data Model Viewer? -

-

- Data Model Viewer is your centralized tool for exploring and understanding your Dataverse metadata. Designed with clarity and efficiency in mind, it gives you a single, streamlined access point to view and navigate your data tables. -

-

- Developed by Delegate, it helps organizations save time, reduce complexity, and gain insights into their Dataverse environments—even without full access. It’s a powerful tool for developers, analysts, and administrators alike. -

-
-
- + + Data Model Viewer is your centralized tool for exploring and understanding your Dataverse metadata. Designed with clarity and efficiency in mind, it gives you a single, streamlined access point to view and navigate your data tables. + + + Developed by Delegate, it helps organizations save time, reduce complexity, and gain insights into their Dataverse environments—even without full access. It's a powerful tool for developers, analysts, and administrators alike. + + + + -
-
+
+ {/* Setup and Features */} -
-
-

+ + + Setup and Features -

-

- All setup instructions, feature details, and known issues for Data Model Viewer are available on GitHub. Whether you’re just getting started or tracking updates, GitHub serves as the central hub for all project information. -

- + + All setup instructions, feature details, and known issues for Data Model Viewer are available on GitHub. Whether you're just getting started or tracking updates, GitHub serves as the central hub for all project information. + + github.com/delegateas/DataModelViewer - -
-
- + + + -
-
+
+ {/* Version */} -
- Version {version ?? '...'} -
+ + + Version {version ?? '...'} + + {/* Data Sync */} -
- Last synchronization: {LastSynched ? LastSynched.toLocaleString('en-DK', { - timeZone: 'Europe/Copenhagen', - timeZoneName: 'short', - year: 'numeric', - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit' - }) : '...'} -
-
-
-
-
+ + + Last synchronization: + {LastSynched ? LastSynched.toLocaleString('en-DK', { + timeZone: 'Europe/Copenhagen', + timeZoneName: 'short', + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }) : '...'} + + + + + + ) -} +} \ No newline at end of file diff --git a/Website/components/datamodelview/Attributes.tsx b/Website/components/datamodelview/Attributes.tsx index ef148a4..cebe4f8 100644 --- a/Website/components/datamodelview/Attributes.tsx +++ b/Website/components/datamodelview/Attributes.tsx @@ -1,12 +1,7 @@ 'use client' import { EntityType, AttributeType } from "@/lib/Types" -import { TableHeader, TableRow, TableHead, TableBody, TableCell, Table } from "../shared/ui/table" -import { Button } from "../shared/ui/button" import { useState } from "react" -import { ArrowUpDown, ArrowUp, ArrowDown, EyeOff, Eye, Search, X } from "lucide-react" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../shared/ui/select" -import { Input } from "../shared/ui/input" import { AttributeDetails } from "./entity/AttributeDetails" import BooleanAttribute from "./attributes/BooleanAttribute" import ChoiceAttribute from "./attributes/ChoiceAttribute" @@ -20,6 +15,8 @@ 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 { ClearRounded, SearchRounded, Visibility, VisibilityOff, ArrowUpwardRounded, ArrowDownwardRounded } from "@mui/icons-material" type SortDirection = 'asc' | 'desc' | null type SortColumn = 'displayName' | 'schemaName' | 'type' | 'description' | null @@ -36,6 +33,8 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri const [hideStandardFields, setHideStandardFields] = useState(true) const [searchQuery, setSearchQuery] = useState("") + const theme = useTheme(); + const handleSort = (column: SortColumn) => { if (sortColumn === column) { if (sortDirection === 'asc') { @@ -133,10 +132,10 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri }, [onVisibleCountChange, sortedAttributes.length]); const SortIcon = ({ column }: { column: SortColumn }) => { - if (sortColumn !== column) return - if (sortDirection === 'asc') return - if (sortDirection === 'desc') return - return + if (sortColumn !== column) return + if (sortDirection === 'asc') return + if (sortDirection === 'desc') return + return } const attributeTypes = [ @@ -154,172 +153,252 @@ export const Attributes = ({ entity, onVisibleCountChange, search = "" }: IAttri ] return <> -
-
-
- - setSearchQuery(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Escape') { - setSearchQuery("") - } - }} - className="pl-6 pr-8 h-8 text-xs md:pl-8 md:pr-10 md:h-10 md:text-sm" - /> - {searchQuery && ( - - )} -
- setTypeFilter(e.target.value)} + label="Filter by type" + labelId="relationship-type-filter-label" + sx={{ fontSize: { xs: '0.75rem', md: '0.875rem' } }} + > {attributeTypes.map(type => ( - - {type === "all" ? "All Types" : type.replace("Attribute", "")} - + + {type === "all" ? "All Types" : type.replace("Attribute", "")} + ))} - - + + {(searchQuery || typeFilter !== "all") && ( )} -
+ {search && search.length >= 3 && searchQuery && ( -
- - Warning: Global search "{search}" is also active -
+ + + + Warning: Global search "{search}" is also active + + )} -
- {sortedAttributes.length === 0 ? ( -
- {searchQuery || typeFilter !== "all" ? ( -
-

- {searchQuery && typeFilter !== "all" - ? `No ${typeFilter === "all" ? "" : typeFilter.replace("Attribute", "")} attributes found matching "${searchQuery}"` - : searchQuery - ? `No attributes found matching "${searchQuery}"` - : `No ${typeFilter === "all" ? "" : typeFilter.replace("Attribute", "")} attributes available` - } -

- -
- ) : ( -

No attributes available for this table

- )} -
- ) : ( - - - - handleSort('displayName')} - > -
- Display Name - -
-
- handleSort('schemaName')} - > -
- Schema Name - -
-
- handleSort('type')} - > -
- Type - -
-
- Details - handleSort('description')} - > -
- Description - -
-
-
-
- - {sortedAttributes.map((attribute, index) => ( - - - {highlightMatch(attribute.DisplayName, highlightTerm)} + + + {sortedAttributes.length === 0 ? ( + + {searchQuery || typeFilter !== "all" ? ( + + + {searchQuery && typeFilter !== "all" + ? `No ${typeFilter === "all" ? "" : typeFilter.replace("Attribute", "")} attributes found matching "${searchQuery}"` + : searchQuery + ? `No attributes found matching "${searchQuery}"` + : `No ${typeFilter === "all" ? "" : typeFilter.replace("Attribute", "")} attributes available` + } + + + + ) : ( + No attributes available for this table + )} + + ) : ( + +
+ + + handleSort('displayName')} + sx={{ color: 'text.primary' }} + > + + Display Name + + + + handleSort('schemaName')} + sx={{ color: 'text.primary' }} + > + + Schema Name + + - - {highlightMatch(attribute.SchemaName, highlightTerm)} + handleSort('type')} + sx={{ color: 'text.primary' }} + > + + Type + + - {getAttributeComponent(entity, attribute, highlightMatch, highlightTerm)} - - - {highlightMatch(attribute.Description ?? "", highlightTerm)} + + Details + + handleSort('description')} + sx={{ color: 'text.primary' }} + > + + Description + + - ))} - -
- )} + + + {sortedAttributes.map((attribute, index) => ( + + + {highlightMatch(attribute.DisplayName, highlightTerm)} + + + {highlightMatch(attribute.SchemaName, highlightTerm)} + + {getAttributeComponent(entity, attribute, highlightMatch, highlightTerm)} + + + {highlightMatch(attribute.Description ?? "", highlightTerm)} + + + ))} + + + + )} + } diff --git a/Website/components/datamodelview/DatamodelView.tsx b/Website/components/datamodelview/DatamodelView.tsx index afc8772..afa64af 100644 --- a/Website/components/datamodelview/DatamodelView.tsx +++ b/Website/components/datamodelview/DatamodelView.tsx @@ -1,10 +1,8 @@ 'use client' -import { AppSidebar } from "../shared/AppSidebar"; -import { TooltipProvider } from "../shared/ui/tooltip"; -import { useSidebarDispatch } from "@/contexts/SidebarContext"; +import { useSidebar } from "@/contexts/SidebarContext"; import { SidebarDatamodelView } from "./SidebarDatamodelView"; -import { DatamodelViewProvider, useDatamodelView, useDatamodelViewDispatch } from "@/contexts/DatamodelViewContext"; +import { useDatamodelView, useDatamodelViewDispatch } from "@/contexts/DatamodelViewContext"; import { SearchPerformanceProvider } from "@/contexts/SearchPerformanceContext"; import { List } from "./List"; import { TimeSlicedSearch } from "./TimeSlicedSearch"; @@ -14,18 +12,16 @@ import { updateURL } from "@/lib/url-utils"; import { useSearchParams } from "next/navigation"; export function DatamodelView() { - const dispatch = useSidebarDispatch(); + const { setElement, expand } = useSidebar(); useEffect(() => { - dispatch({ type: "SET_ELEMENT", payload: }); - dispatch({ type: 'SET_SHOW_ELEMENT', payload: true }); - }, []); + setElement(); + expand(); + }, [setElement]); return ( - - - + ); } @@ -193,33 +189,28 @@ function DatamodelViewContent() { } return ( -
- -
-
- {/* LOADING BAR - currently deprecated */} - {/* {loading && ( -
-
-
-
- )} */} - - - - -
+
+
+ {/* LOADING BAR - currently deprecated */} + {/* {loading && ( +
+
+
+
+ )} */} + +
); diff --git a/Website/components/datamodelview/Keys.tsx b/Website/components/datamodelview/Keys.tsx index 440ae91..999546d 100644 --- a/Website/components/datamodelview/Keys.tsx +++ b/Website/components/datamodelview/Keys.tsx @@ -1,13 +1,25 @@ 'use client' import { EntityType } from "@/lib/Types" -import { TableHeader, TableRow, TableHead, TableBody, TableCell, Table } from "../shared/ui/table" import { useState } from "react" -import { ArrowUpDown, ArrowUp, ArrowDown, Search, X } from "lucide-react" -import { Input } from "../shared/ui/input" -import { Button } from "../shared/ui/button" import React from "react" import { highlightMatch } from "../datamodelview/List"; +import { + Button, + TextField, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Box, + Typography, + Alert, + Chip, + InputAdornment, + useTheme +} from "@mui/material" +import { ArrowDownwardRounded, ArrowUpwardRounded, CloseRounded, SearchRounded } from "@mui/icons-material"; type SortColumn = 'name' | 'logicalName' | 'attributes' | null type SortDirection = 'asc' | 'desc' | null @@ -21,6 +33,7 @@ function Keys({ entity, onVisibleCountChange, search = "" }: IKeysProps & { sear const [sortColumn, setSortColumn] = useState("name") const [sortDirection, setSortDirection] = useState("asc") const [searchQuery, setSearchQuery] = useState("") + const theme = useTheme() const handleSort = (column: SortColumn) => { if (sortColumn === column) { @@ -101,143 +114,208 @@ function Keys({ entity, onVisibleCountChange, search = "" }: IKeysProps & { sear }, [onVisibleCountChange, sortedKeys.length]); const SortIcon = ({ column }: { column: SortColumn }) => { - if (sortColumn !== column) return - if (sortDirection === 'asc') return - if (sortDirection === 'desc') return - return + if (sortColumn !== column) return + if (sortDirection === 'asc') return + if (sortDirection === 'desc') return + return } return ( <> -
-
-
- - setSearchQuery(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Escape') { - setSearchQuery("") - } - }} - className="pl-6 pr-8 h-8 text-xs md:pl-8 md:pr-10 md:h-10 md:text-sm" - /> - {searchQuery && ( - - )} -
- {searchQuery && ( - - )} -
+ + + setSearchQuery(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Escape') { + setSearchQuery("") + } + }} + size="small" + className="flex-grow" + sx={{ + '& .MuiInputBase-input': { + fontSize: { xs: '0.75rem', md: '0.875rem' }, + py: { xs: 0.5, md: 1 } + } + }} + InputProps={{ + startAdornment: ( + + + + ), + endAdornment: searchQuery && ( + + + + ) + }} + /> + {search && search.length >= 3 && searchQuery && ( -
- - Warning: Global search "{search}" is also active -
+ + Warning: Global search "{search}" is also active + )} -
-
+ + {sortedKeys.length === 0 ? ( -
+ {searchQuery ? ( -
-

No keys found matching "{searchQuery}"

+ + + No keys found matching "{searchQuery}" + -
+
) : ( -

No keys available for this table

+ No keys available for this table )} -
+
) : ( - - - - +
+ + + handleSort('name')} + sx={{ color: 'text.primary' }} > -
+ Name -
-
- + + handleSort('logicalName')} + sx={{ color: 'text.primary' }} > -
+ Logical Name -
-
- + + handleSort('attributes')} + sx={{ color: 'text.primary' }} > -
+ Key Attributes -
-
+ + - + {sortedKeys.map((key, index) => ( - + {highlightMatch(key.Name, highlightTerm)} - + {highlightMatch(key.LogicalName, highlightTerm)} - -
+ + {key.KeyAttributes.map((attr, i) => ( - - {highlightMatch(attr, highlightTerm)} - + label={highlightMatch(attr, highlightTerm)} + size="small" + variant="outlined" + className="text-xs md:text-sm h-5 md:h-6" + sx={{ + backgroundColor: theme.palette.mode === 'dark' + ? 'rgba(25, 118, 210, 0.12)' + : 'rgba(25, 118, 210, 0.08)', + color: 'primary.main', + borderColor: 'primary.main', + '& .MuiChip-label': { + px: { xs: 0.5, md: 1 }, + fontSize: { xs: '0.65rem', md: '0.75rem' } + } + }} + /> ))} -
+
))}
+ )} -
+ ) } diff --git a/Website/components/datamodelview/List.tsx b/Website/components/datamodelview/List.tsx index 8df6a5c..0555fb9 100644 --- a/Website/components/datamodelview/List.tsx +++ b/Website/components/datamodelview/List.tsx @@ -140,13 +140,22 @@ export const List = ({ }: IListProps) => { setTimeout(() => { setIsScrollingToSection(false); + // Reset intentional scroll flag after scroll is complete + setTimeout(() => { + isIntentionalScroll.current = false; + }, 100); }, 500); } catch (error) { console.warn(`Failed to scroll to section ${sectionId}:`, error); const estimatedOffset = sectionIndex * 300; if (parentRef.current) { + isIntentionalScroll.current = true; parentRef.current.scrollTop = estimatedOffset; + // Reset flags for fallback scroll + setTimeout(() => { + isIntentionalScroll.current = false; + }, 600); } setIsScrollingToSection(false); } @@ -220,15 +229,15 @@ export const List = ({ }: IListProps) => { lastScrollHandleTime.current = now; const scrollElement = parentRef.current; - if (!scrollElement || isScrollingToSection) return; + if (!scrollElement || isScrollingToSection || isIntentionalScroll.current) return; const scrollOffset = scrollElement.scrollTop; const virtualItems = rowVirtualizer.getVirtualItems(); // Find the first visible item - const padding = 16; + const padding = 32; const firstVisibleItem = virtualItems.find(v => { - return v.start <= scrollOffset && (v.end - padding) >= scrollOffset; + return (v.start - padding) <= scrollOffset && v.end >= (scrollOffset + padding); }); if (firstVisibleItem) { @@ -289,7 +298,7 @@ export const List = ({ }: IListProps) => { }, [datamodelView.currentSection, flatItems, rowVirtualizer, dispatch]); return ( -
+
{/* Show skeleton loading state only when initially loading */} {flatItems.length === 0 && datamodelView.loading && (!search || search.length < 3) && ( diff --git a/Website/components/datamodelview/Relationships.tsx b/Website/components/datamodelview/Relationships.tsx index c209f9d..458b29d 100644 --- a/Website/components/datamodelview/Relationships.tsx +++ b/Website/components/datamodelview/Relationships.tsx @@ -1,16 +1,13 @@ 'use client' import { EntityType } from "@/lib/Types" -import { TableHeader, TableRow, TableHead, TableBody, TableCell, Table } from "../shared/ui/table" -import { Button } from "../shared/ui/button" import { CascadeConfiguration } from "./entity/CascadeConfiguration" import { useState } from "react" -import { ArrowUpDown, ArrowUp, ArrowDown, Search, X } from "lucide-react" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../shared/ui/select" -import { Input } from "../shared/ui/input" import { useDatamodelView, useDatamodelViewDispatch } from "@/contexts/DatamodelViewContext" import React from "react" import { highlightMatch } from "../datamodelview/List"; +import { Button, FormControl, InputLabel, MenuItem, Select, Table, TableBody, TableCell, TableHead, TableRow, TextField, InputAdornment, Box, Typography, useTheme } from "@mui/material" +import { SearchRounded, ClearRounded, ArrowUpwardRounded, ArrowDownwardRounded } from "@mui/icons-material" type SortDirection = 'asc' | 'desc' | null type SortColumn = 'name' | 'tableSchema' | 'lookupField' | 'type' | 'behavior' | 'schemaName' | null @@ -25,6 +22,8 @@ export const Relationships = ({ entity, onVisibleCountChange, search = "" }: IRe const [sortDirection, setSortDirection] = useState("asc") const [typeFilter, setTypeFilter] = useState("all") const [searchQuery, setSearchQuery] = useState("") + + const theme = useTheme(); const dispatch = useDatamodelViewDispatch(); const { scrollToSection } = useDatamodelView(); @@ -116,10 +115,10 @@ export const Relationships = ({ entity, onVisibleCountChange, search = "" }: IRe } const SortIcon = ({ column }: { column: SortColumn }) => { - if (sortColumn !== column) return - if (sortDirection === 'asc') return - if (sortDirection === 'desc') return - return + if (sortColumn !== column) return + if (sortDirection === 'asc') return + if (sortDirection === 'desc') return + return } const relationshipTypes = [ @@ -138,179 +137,262 @@ export const Relationships = ({ entity, onVisibleCountChange, search = "" }: IRe }, [onVisibleCountChange, sortedRelationships.length]); return <> -
-
-
- - setSearchQuery(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Escape') { - setSearchQuery("") - } - }} - className="pl-6 pr-8 h-8 text-xs md:pl-8 md:pr-10 md:h-10 md:text-sm" - /> - {searchQuery && ( - - )} -
- setTypeFilter(e.target.value)} + label="Filter by type" + labelId="relationship-type-filter-label" + className="text-xs md:text-sm" + > {relationshipTypes.map(type => ( - + {type.label} - + ))} - - + + {(searchQuery || typeFilter !== "all") && ( )} -
+ {search && search.length >= 3 && searchQuery && ( -
- - Warning: Global search "{search}" is also active -
+ + + + Warning: Global search "{search}" is also active + + )} -
-
+ + {getSortedRelationships().length === 0 ? ( -
+ {searchQuery || typeFilter !== "all" ? ( -
-

+ + {searchQuery && typeFilter !== "all" ? `No ${typeFilter === "many-to-many" ? "many-to-many" : "one-to-many"} relationships found matching "${searchQuery}"` : searchQuery ? `No relationships found matching "${searchQuery}"` : `No ${typeFilter === "many-to-many" ? "many-to-many" : "one-to-many"} relationships available` } -

+ -
+
) : ( -

No relationships available for this table

+ No relationships available for this table )} -
+
) : ( - - - - +
+ + + handleSort('name')} + sx={{ color: 'text.primary' }} > -
+ Name -
-
- + + handleSort('tableSchema')} + sx={{ color: 'text.primary' }} > -
+ Related Table -
-
- + + handleSort('lookupField')} + sx={{ color: 'text.primary' }} > -
+ Lookup Field -
-
- + + handleSort('type')} + sx={{ color: 'text.primary' }} > -
+ Type -
-
- Behavior - + + + Behavior + + handleSort('schemaName')} + sx={{ color: 'text.primary' }} > -
+ Schema Name -
-
+ + - + {sortedRelationships.map((relationship, index) => - + {highlightMatch(relationship.Name, highlightTerm)} - + - {relationship.LookupDisplayName} - {relationship.IsManyToMany ? "N:N" : "1:N"} - - {relationship.RelationshipSchema} + + {relationship.LookupDisplayName} + + + {relationship.IsManyToMany ? "N:N" : "1:N"} + + + + + + {relationship.RelationshipSchema} + )}
+ )} -
+ } \ No newline at end of file diff --git a/Website/components/datamodelview/Section.tsx b/Website/components/datamodelview/Section.tsx index d9a811f..5f58692 100644 --- a/Website/components/datamodelview/Section.tsx +++ b/Website/components/datamodelview/Section.tsx @@ -1,14 +1,15 @@ 'use client' import { EntityType, GroupType } from "@/lib/Types" -import { Tabs, TabsList, TabsTrigger, TabsContent } from "../shared/ui/tabs" import { EntityHeader } from "./entity/EntityHeader" import { SecurityRoles } from "./entity/SecurityRoles" import Keys from "./Keys" -import { KeyRound, Tags, Unplug } from "lucide-react" import { Attributes } from "./Attributes" import { Relationships } from "./Relationships" import React from "react" +import { Box, Paper, Tab, Tabs } from "@mui/material" +import CustomTabPanel from "../shared/elements/TabPanel" +import { KeyRounded, SellRounded, ShareRounded } from "@mui/icons-material" interface ISectionProps { entity: EntityType; @@ -23,14 +24,14 @@ export const Section = React.memo( // Use useRef to track previous props for comparison const prevSearch = React.useRef(search); - const [tab, setTab] = React.useState("attributes"); + const [tab, setTab] = React.useState(0); // Handle tab changes to notify parent component - const handleTabChange = React.useCallback((value: string) => { + const handleTabChange = React.useCallback((event: React.SyntheticEvent, newValue: number) => { if (onTabChange) { onTabChange(true); } - setTab(value); + setTab(newValue); }, [onTabChange]); // Only compute these counts when needed @@ -42,7 +43,7 @@ export const Section = React.memo( React.useEffect(() => { if (onContentChange && (prevSearch.current !== search || - tab !== "attributes")) { + tab !== 0)) { prevSearch.current = search; onContentChange(); } @@ -50,50 +51,78 @@ export const Section = React.memo( return (
-
{/* Removed conditional styling and indicator */} -
+ + {entity.SecurityRoles.length > 0 && (
)} -
+ - -
- - - - Attributes [{visibleAttributeCount}] - - {entity.Relationships.length ? - - - Relationships [{visibleRelationshipCount}] - - : <> - } - {entity.Keys.length ? - - - Keys [{visibleKeyCount}] - - : <> - } - - + + + + + + Attributes [{visibleAttributeCount}] +
+ } + /> + {entity.Relationships.length > 0 && ( + + + Relationships [{visibleRelationshipCount}] +
+ } + /> + )} + {entity.Keys.length > 0 && ( + + + Keys [{visibleKeyCount}] +
+ } + /> + )} + + + - - - - - - - -
- -
+ + {entity.Relationships.length > 0 && ( + 0 ? 1 : 1} className="m-0 p-0"> + + + )} + {entity.Keys.length > 0 && ( + 0 ? 2 : 1} + className="m-0 p-0" + > + + + )} + + +
) }, diff --git a/Website/components/datamodelview/SidebarDatamodelView.tsx b/Website/components/datamodelview/SidebarDatamodelView.tsx index 981ac33..2cc21c6 100644 --- a/Website/components/datamodelview/SidebarDatamodelView.tsx +++ b/Website/components/datamodelview/SidebarDatamodelView.tsx @@ -1,14 +1,14 @@ import { EntityType, GroupType } from "@/lib/Types"; -import { useTouch } from '../shared/ui/hybridtooltop'; -import { useSidebarDispatch } from '@/contexts/SidebarContext'; +import { useSidebar } from '@/contexts/SidebarContext'; import { cn } from "@/lib/utils"; -import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@radix-ui/react-collapsible"; -import { Slot } from "@radix-ui/react-slot"; -import { ExternalLink, Puzzle, Search, X } from "lucide-react"; -import { useState, useEffect } from "react"; -import { Input } from "@/components/shared/ui/input"; +import { Accordion, AccordionSummary, AccordionDetails, Box, InputAdornment, Paper, Typography, Button, CircularProgress } from '@mui/material'; +import { ExpandMore, ExtensionRounded, OpenInNewRounded, SearchRounded } from '@mui/icons-material'; +import { useState, useEffect, useMemo, useCallback } from "react"; +import { TextField } from "@mui/material"; import { useDatamodelView, useDatamodelViewDispatch } from "@/contexts/DatamodelViewContext"; import { useDatamodelData } from "@/contexts/DatamodelDataContext"; +import { useIsMobile } from "@/hooks/use-mobile"; +import { useTheme, alpha } from '@mui/material/styles'; interface ISidebarDatamodelViewProps { @@ -20,24 +20,42 @@ interface INavItemProps { export const SidebarDatamodelView = ({ }: ISidebarDatamodelViewProps) => { - const isTouch = useTouch(); - const dispatch = useSidebarDispatch(); - const { currentSection, currentGroup, scrollToSection } = useDatamodelView(); + const { currentSection, currentGroup, scrollToSection, loadingSection } = useDatamodelView(); + const { close: closeSidebar } = useSidebar(); + const theme = useTheme(); + const isMobile = useIsMobile(); const dataModelDispatch = useDatamodelViewDispatch(); const { groups } = useDatamodelData(); - + const [searchTerm, setSearchTerm] = useState(""); - const [expandedGroups, setExpandedGroups] = useState>(new Set()); + const [displaySearchTerm, setDisplaySearchTerm] = useState(""); + + // Memoize search results to prevent recalculation on every render + const filteredGroups = useMemo(() => { + if (!searchTerm.trim()) return groups; + + return groups.map(group => ({ + ...group, + Entities: group.Entities.filter(entity => + entity.SchemaName.toLowerCase().includes(searchTerm.toLowerCase()) || + entity.DisplayName.toLowerCase().includes(searchTerm.toLowerCase()) + ) + })).filter(group => group.Entities.length > 0); + }, [groups, searchTerm]); + + // Debounced search to reduce performance impact + useEffect(() => { + const timeoutId = setTimeout(() => { + setSearchTerm(displaySearchTerm); + }, 150); + return () => clearTimeout(timeoutId); + }, [displaySearchTerm]); - const setOpen = (state: boolean) => { - dispatch({ type: "SET_OPEN", payload: state }) - } - // Search functionality - const handleSearch = (term: string) => { - setSearchTerm(term); + const handleSearch = useCallback((term: string) => { + setDisplaySearchTerm(term); if (term.trim()) { const newExpandedGroups = new Set(); groups.forEach(group => { @@ -49,24 +67,21 @@ export const SidebarDatamodelView = ({ }: ISidebarDatamodelViewProps) => { newExpandedGroups.add(group.Name); } }); - setExpandedGroups(newExpandedGroups); - } else { - setExpandedGroups(new Set()); } - }; + }, [groups]); - const clearSearch = () => { + const clearSearch = useCallback(() => { setSearchTerm(""); - setExpandedGroups(new Set()); - }; + setDisplaySearchTerm(""); + }, []); - const isEntityMatch = (entity: EntityType) => { + const isEntityMatch = useCallback((entity: EntityType) => { if (!searchTerm.trim()) return false; return entity.SchemaName.toLowerCase().includes(searchTerm.toLowerCase()) || entity.DisplayName.toLowerCase().includes(searchTerm.toLowerCase()); - }; + }, [searchTerm]); - const highlightText = (text: string, searchTerm: string) => { + const highlightText = useCallback((text: string, searchTerm: string) => { if (!searchTerm.trim()) return text; const regex = new RegExp(`(${searchTerm})`, 'gi'); const parts = text.split(regex); @@ -75,153 +90,200 @@ export const SidebarDatamodelView = ({ }: ISidebarDatamodelViewProps) => { {part} : part ); - }; + }, []); - const handleGroupClick = (groupName: string) => { + const handleGroupClick = useCallback((groupName: string) => { dataModelDispatch({ type: "SET_CURRENT_GROUP", payload: groupName }); - }; + }, [dataModelDispatch]); - const handleSectionClick = (sectionId: string) => { - dataModelDispatch({ type: 'SET_LOADING', payload: true }); - dataModelDispatch({ type: 'SET_CURRENT_SECTION', payload: sectionId }); - if (scrollToSection) { - scrollToSection(sectionId); - } - if (isTouch) { setOpen(false); } - clearSearch(); - }; - - const NavItem = ({ group }: INavItemProps) => { - const isCurrentGroup = currentGroup?.toLowerCase() === group.Name.toLowerCase(); - const shouldExpand = expandedGroups.has(group.Name); + const handleSectionClick = useCallback((sectionId: string, groupName: string) => { + // Use requestAnimationFrame to defer heavy operations + requestAnimationFrame(() => { + dataModelDispatch({ type: 'SET_LOADING', payload: true }); + dataModelDispatch({ type: 'SET_LOADING_SECTION', payload: sectionId }); + dataModelDispatch({ type: "SET_CURRENT_GROUP", payload: groupName }); + dataModelDispatch({ type: 'SET_CURRENT_SECTION', payload: sectionId }); - const [isExpanded, setIsExpanded] = useState(false) - - useEffect(() => { - if (searchTerm.trim()) { - setIsExpanded(shouldExpand); - } else { - setIsExpanded(isCurrentGroup); + // On phone - close + if (!!isMobile) { + closeSidebar(); } - }, [isCurrentGroup, shouldExpand, searchTerm]) + + // Defer scroll operation to next frame to prevent blocking + requestAnimationFrame(() => { + if (scrollToSection) { + scrollToSection(sectionId); + } + clearSearch(); + + // Clear loading section after a short delay to show the loading state + setTimeout(() => { + dataModelDispatch({ type: 'SET_LOADING_SECTION', payload: null }); + }, 500); + }); + }); + }, [dataModelDispatch, scrollToSection, clearSearch]); + + const NavItem = useCallback(({ group }: INavItemProps) => { + const isCurrentGroup = currentGroup?.toLowerCase() === group.Name.toLowerCase(); return ( - handleGroupClick(group.Name)} + className={`group/accordion transition-all duration-300 w-full first:rounded-t-lg last:rounded-b-lg shadow-none p-1`} + sx={{ + backgroundColor: "background.paper", + borderColor: 'border.main', + }} > -
- } + className={cn( + "p-2 duration-200 flex items-center rounded-md text-xs font-semibold text-sidebar-foreground/80 outline-none ring-sidebar-ring transition-all focus-visible:ring-2 cursor-pointer w-full min-w-0", + isCurrentGroup ? "font-semibold" : "hover:bg-sidebar-accent hover:text-sidebar-primary" + )} + sx={{ + backgroundColor: isCurrentGroup ? alpha(theme.palette.primary.main, 0.1) : 'transparent', + padding: '4px', + minHeight: '32px !important', + '& .MuiAccordionSummary-content': { + margin: 0, + alignItems: 'center', + minWidth: 0, + overflow: 'hidden' + } + }} + > + - - {group.Name} -

{group.Entities.length}

- { - e.stopPropagation(); - handleGroupClick(group.Name); - if (group.Entities.length > 0) handleSectionClick(group.Entities[0].SchemaName); - }} - aria-label={`Link to first entity in ${group.Name}`} - tabIndex={0} - > - { - e.preventDefault(); - handleGroupClick(group.Name); - if (group.Entities.length > 0) handleSectionClick(group.Entities[0].SchemaName); - }} /> - -
-
- -
- {group.Entities.map(entity => { - const isCurrentSection = currentSection?.toLowerCase() === entity.SchemaName.toLowerCase() - const isMatch = isEntityMatch(entity); - - // If searching and this entity doesn't match, don't render it - if (searchTerm.trim() && !isMatch) { - return null; - } - - return ( - - ) - })} -
-
-
-
+ {group.Name} + + {group.Entities.length} + + { + e.stopPropagation(); + if (group.Entities.length > 0) handleSectionClick(group.Entities[0].SchemaName, group.Name); + }} + aria-label={`Link to first entity in ${group.Name}`} + className="w-4 h-4 flex-shrink-0" + sx={{ + color: isCurrentGroup ? "primary.main" : "default" + }} + /> + + + + {group.Entities.map(entity => { + const isCurrentSection = currentSection?.toLowerCase() === entity.SchemaName.toLowerCase() + const isMatch = isEntityMatch(entity); + const isLoading = loadingSection === entity.SchemaName; + + // If searching and this entity doesn't match, don't render it + if (searchTerm.trim() && !isMatch) { + return null; + } + + return ( + + ) + })} + + + ) - } + }, [currentGroup, currentSection, theme, handleGroupClick, handleSectionClick, isEntityMatch, searchTerm, highlightText]); return ( -
- {/* Search Bar */} -
-
- - handleSearch(e.target.value)} - className="pl-8 pr-8 h-8 text-xs" - /> - {searchTerm && ( - - )} -
-
- -
+ + handleSearch(e.target.value)} + size="small" + variant="outlined" + fullWidth + slotProps={{ + input: { + startAdornment: , + } + }} + + /> + { - groups.map((group) => + filteredGroups.map((group) => ) } -
-
+ + ); } diff --git a/Website/components/datamodelview/TimeSlicedSearch.tsx b/Website/components/datamodelview/TimeSlicedSearch.tsx index 5caed02..634473e 100644 --- a/Website/components/datamodelview/TimeSlicedSearch.tsx +++ b/Website/components/datamodelview/TimeSlicedSearch.tsx @@ -2,10 +2,11 @@ import React, { useState, useRef, useCallback, useEffect } from 'react'; import { createPortal } from 'react-dom'; -import { Input } from '../shared/ui/input'; -import { Search, ChevronUp, ChevronDown, X } from 'lucide-react'; import { useSidebar } from '@/contexts/SidebarContext'; +import { useSettings } from '@/contexts/SettingsContext'; import { useIsMobile } from '@/hooks/use-mobile'; +import { Box, IconButton, InputAdornment, TextField } from '@mui/material'; +import { CloseRounded, SearchRounded } from '@mui/icons-material'; interface TimeSlicedSearchProps { onSearch: (value: string) => void; @@ -25,8 +26,6 @@ export const TimeSlicedSearch = ({ onNavigateNext, onNavigatePrevious, initialLocalValue, - currentIndex = 0, - totalResults = 0, placeholder = "Search attributes...", }: TimeSlicedSearchProps) => { const [localValue, setLocalValue] = useState(initialLocalValue); @@ -34,14 +33,15 @@ export const TimeSlicedSearch = ({ const [portalRoot, setPortalRoot] = useState(null); const [lastValidSearch, setLastValidSearch] = useState(''); const { isOpen } = useSidebar(); + const { isSettingsOpen } = useSettings(); const isMobile = useIsMobile(); const searchTimeoutRef = useRef(); const typingTimeoutRef = useRef(); const frameRef = useRef(); - // Hide search on mobile when sidebar is open - const shouldHideSearch = isMobile && isOpen; + // Hide search on mobile when sidebar is open, or when settings are open + const shouldHideSearch = (isMobile && isOpen) || isSettingsOpen; // Time-sliced debouncing using requestAnimationFrame const scheduleSearch = useCallback((value: string) => { @@ -165,9 +165,6 @@ export const TimeSlicedSearch = ({ } }, [onNavigateNext, onNavigatePrevious, onSearch, onLoadingChange]); - const hasResults = totalResults > 0; - const showNavigation = hasResults && localValue.length >= 3; - // Cleanup useEffect(() => { return () => { @@ -212,82 +209,53 @@ export const TimeSlicedSearch = ({ }, []); const searchInput = ( -
- {/* Search Input Container */} -
-
- - - {/* Clear button or loading indicator */} -
- {isTyping && localValue.length >= 3 ? ( -
- ) : localValue ? ( - - ) : null} -
-
- - {/* Navigation Buttons */} - {showNavigation && ( -
- - - -
- )} -
- - {/* Results Counter */} - {showNavigation && ( -
- - {totalResults > 0 ? ( - `${currentIndex} of ${totalResults} sections` - ) : ( - 'No results' - )} - -
- Enter next section • - Shift+Enter prev section • - Ctrl+↑↓ navigate -
-
- )} -
+ + , + endAdornment: ( + + {isTyping && localValue.length >= 3 ? ( + + ) : localValue ? ( + + + + ) : null} + + ) + } + }} + /> + ); return portalRoot ? createPortal(searchInput, portalRoot) : null; diff --git a/Website/components/datamodelview/attributes/BooleanAttribute.tsx b/Website/components/datamodelview/attributes/BooleanAttribute.tsx index 6570bb1..2fd68bb 100644 --- a/Website/components/datamodelview/attributes/BooleanAttribute.tsx +++ b/Website/components/datamodelview/attributes/BooleanAttribute.tsx @@ -1,54 +1,74 @@ import { useIsMobile } from "@/hooks/use-mobile"; import { BooleanAttributeType } from "@/lib/Types" -import { CheckCircle, Circle } from "lucide-react" +import { Box, Typography, Chip } from "@mui/material" +import { CheckRounded, RadioButtonCheckedRounded, RadioButtonUncheckedRounded } from "@mui/icons-material"; export default function BooleanAttribute({ attribute }: { attribute: BooleanAttributeType }) { const isMobile = useIsMobile(); return ( -
-
- Boolean + + + Boolean {attribute.DefaultValue !== null && !isMobile && ( - - - Default: {attribute.DefaultValue === true ? attribute.TrueLabel : attribute.FalseLabel} - + } + label={`Default: ${attribute.DefaultValue === true ? attribute.TrueLabel : attribute.FalseLabel}`} + size="small" + color="success" + variant="outlined" + /> )} -
-
-
-
+ + + + {attribute.DefaultValue === true ? ( - + ) : ( - + )} - {attribute.TrueLabel} -
-
- - True - -
-
-
-
+ {attribute.TrueLabel} + + + + + + + {attribute.DefaultValue === false ? ( - + ) : ( - + )} - {attribute.FalseLabel} -
-
- - False - -
-
-
-
+ {attribute.FalseLabel} + + + + + + + ) } \ No newline at end of file diff --git a/Website/components/datamodelview/attributes/ChoiceAttribute.tsx b/Website/components/datamodelview/attributes/ChoiceAttribute.tsx index bb5e7c2..74881a8 100644 --- a/Website/components/datamodelview/attributes/ChoiceAttribute.tsx +++ b/Website/components/datamodelview/attributes/ChoiceAttribute.tsx @@ -1,68 +1,87 @@ import { useIsMobile } from "@/hooks/use-mobile" import { ChoiceAttributeType } from "@/lib/Types" import { formatNumberSeperator } from "@/lib/utils" -import { CheckCircle, Circle, Square, CheckSquare } from "lucide-react" +import { Box, Typography, Chip } from "@mui/material" +import { CheckBoxOutlineBlankRounded, CheckBoxRounded, CheckRounded } from "@mui/icons-material" export default function ChoiceAttribute({ attribute, highlightMatch, highlightTerm }: { attribute: ChoiceAttributeType, highlightMatch: (text: string, term: string) => string | React.JSX.Element, highlightTerm: string }) { const isMobile = useIsMobile(); return ( -
-
- {attribute.Type}-select + + + {attribute.Type}-select {attribute.DefaultValue !== null && attribute.DefaultValue !== -1 && !isMobile && ( - - - Default: {attribute.Options.find(o => o.Value === attribute.DefaultValue)?.Name} - + } + label={`Default: ${attribute.Options.find(o => o.Value === attribute.DefaultValue)?.Name}`} + size="small" + color="success" + variant="outlined" + /> )} -
-
+ + {attribute.Options.map(option => ( -
-
-
-
+ + + + {attribute.Type === "Multi" ? ( // For multi-select, show checkboxes option.Value === attribute.DefaultValue ? ( - + ) : ( - + ) ) : ( // For single-select, show radio buttons option.Value === attribute.DefaultValue ? ( - + ) : ( - + ) )} - {highlightMatch(option.Name, highlightTerm)} -
+ {highlightMatch(option.Name, highlightTerm)} + {option.Color && ( -
)} -
-
- - {formatNumberSeperator(option.Value)} - -
-
+ + + + + {option.Description && ( -
+ {option.Description} -
+ )} -
+ ))} -
-
+ + ) } \ No newline at end of file diff --git a/Website/components/datamodelview/attributes/DateTimeAttribute.tsx b/Website/components/datamodelview/attributes/DateTimeAttribute.tsx index 6d6b69c..e04d7b2 100644 --- a/Website/components/datamodelview/attributes/DateTimeAttribute.tsx +++ b/Website/components/datamodelview/attributes/DateTimeAttribute.tsx @@ -1,5 +1,12 @@ import { DateTimeAttributeType } from "@/lib/Types"; +import { Typography } from "@mui/material"; export default function DateTimeAttribute({ attribute } : { attribute: DateTimeAttributeType }) { - return <>{attribute.Format} - {attribute.Behavior} + return ( + <> + {attribute.Format} + {" - "} + {attribute.Behavior} + + ) } \ No newline at end of file diff --git a/Website/components/datamodelview/attributes/DecimalAttribute.tsx b/Website/components/datamodelview/attributes/DecimalAttribute.tsx index cd73150..7397af7 100644 --- a/Website/components/datamodelview/attributes/DecimalAttribute.tsx +++ b/Website/components/datamodelview/attributes/DecimalAttribute.tsx @@ -1,5 +1,6 @@ import { DecimalAttributeType } from "@/lib/Types" import { formatNumberSeperator } from "@/lib/utils" +import { Typography } from "@mui/material" export default function MoneyAttribute({ attribute }: { attribute: DecimalAttributeType }) { const formatNumber = @@ -7,10 +8,16 @@ export default function MoneyAttribute({ attribute }: { attribute: DecimalAttrib ? FormatMoney : FormatDecimal - return <> -

{attribute.Type} ({formatNumber(attribute.MinValue)} to {formatNumber(attribute.MaxValue)})

-

Precision: {attribute.Precision}

- + return ( + <> + + {attribute.Type} + {" "} + ({formatNumber(attribute.MinValue)} to {formatNumber(attribute.MaxValue)}) + + Precision: {attribute.Precision} + + ) } function FormatMoney(number: number) { diff --git a/Website/components/datamodelview/attributes/FileAttribute.tsx b/Website/components/datamodelview/attributes/FileAttribute.tsx index 39ba278..c73f975 100644 --- a/Website/components/datamodelview/attributes/FileAttribute.tsx +++ b/Website/components/datamodelview/attributes/FileAttribute.tsx @@ -1,6 +1,13 @@ import { FileAttributeType } from "@/lib/Types"; import { formatNumberSeperator } from "@/lib/utils"; +import { Typography } from "@mui/material"; export default function FileAttribute({ attribute } : { attribute: FileAttributeType }) { - return <>File (Max {formatNumberSeperator(attribute.MaxSize)}KB) + return ( + <> + File + {" "} + (Max {formatNumberSeperator(attribute.MaxSize)}KB) + + ) } \ No newline at end of file diff --git a/Website/components/datamodelview/attributes/GenericAttribute.tsx b/Website/components/datamodelview/attributes/GenericAttribute.tsx index d0e0db1..88a74da 100644 --- a/Website/components/datamodelview/attributes/GenericAttribute.tsx +++ b/Website/components/datamodelview/attributes/GenericAttribute.tsx @@ -1,5 +1,6 @@ import { GenericAttributeType } from "@/lib/Types"; +import { Typography } from "@mui/material"; export default function GenericAttribute({ attribute } : { attribute: GenericAttributeType }) { - return {attribute.Type} + return {attribute.Type} } \ No newline at end of file diff --git a/Website/components/datamodelview/attributes/IntegerAttribute.tsx b/Website/components/datamodelview/attributes/IntegerAttribute.tsx index 8c72f40..62f9d8b 100644 --- a/Website/components/datamodelview/attributes/IntegerAttribute.tsx +++ b/Website/components/datamodelview/attributes/IntegerAttribute.tsx @@ -1,8 +1,15 @@ import { IntegerAttributeType } from "@/lib/Types" import { formatNumberSeperator } from "@/lib/utils" +import { Typography } from "@mui/material" export default function IntegerAttribute({ attribute } : { attribute: IntegerAttributeType }) { - return <>{attribute.Format} ({FormatNumber(attribute.MinValue)} to {FormatNumber(attribute.MaxValue)}) + return ( + <> + {attribute.Format} + {" "} + ({FormatNumber(attribute.MinValue)} to {FormatNumber(attribute.MaxValue)}) + + ) } function FormatNumber(number: number) { diff --git a/Website/components/datamodelview/attributes/LookupAttribute.tsx b/Website/components/datamodelview/attributes/LookupAttribute.tsx index 4ac5f5d..3cc24bf 100644 --- a/Website/components/datamodelview/attributes/LookupAttribute.tsx +++ b/Website/components/datamodelview/attributes/LookupAttribute.tsx @@ -1,31 +1,55 @@ import { LookupAttributeType } from "@/lib/Types" -import { FileSearch, FileX2 } from "lucide-react" import { useDatamodelView } from "@/contexts/DatamodelViewContext" +import { Box, Typography, Button, Chip } from "@mui/material" +import { ContentPasteOffRounded, ContentPasteSearchRounded } from "@mui/icons-material"; export default function LookupAttribute({ attribute }: { attribute: LookupAttributeType }) { const { scrollToSection } = useDatamodelView(); - return
-

Lookup

-
- {attribute.Targets - .map(target => target.IsInSolution ? - : -
- - {target.Name} -
)} -
-
+ return ( + + Lookup + + {attribute.Targets + .map(target => target.IsInSolution ? + : + } + label={target.Name} + size="small" + disabled + sx={{ + fontSize: { xs: '0.625rem', md: '0.875rem' }, + height: { xs: '16px', md: '24px' }, + backgroundColor: 'grey.100', + color: 'grey.600', + '& .MuiChip-icon': { + fontSize: { xs: '0.5rem', md: '0.75rem' } + } + }} + /> + )} + + + ) } \ No newline at end of file diff --git a/Website/components/datamodelview/attributes/StatusAttribute.tsx b/Website/components/datamodelview/attributes/StatusAttribute.tsx index 4d05c28..425fa41 100644 --- a/Website/components/datamodelview/attributes/StatusAttribute.tsx +++ b/Website/components/datamodelview/attributes/StatusAttribute.tsx @@ -1,6 +1,7 @@ import { StatusAttributeType, StatusOption } from "@/lib/Types"; import { formatNumberSeperator } from "@/lib/utils"; -import { Circle } from "lucide-react"; +import { CircleRounded } from "@mui/icons-material"; +import { Box, Typography, Chip } from "@mui/material"; export default function StatusAttribute({ attribute }: { attribute: StatusAttributeType }) { const groupedOptions = attribute.Options.reduce((acc, option) => { @@ -12,37 +13,45 @@ export default function StatusAttribute({ attribute }: { attribute: StatusAttrib }, {} as Record); return ( -
-
- State/Status + + + State/Status {/* No DefaultValue for StatusAttributeType, so no default badge */} -
+ {Object.entries(groupedOptions).map(([state, options]) => ( -
- {state} -
+ + {state} + {options.map(option => ( -
-
-
-
+ + + + {/* No DefaultValue, so always show Circle icon */} - - {option.Name} -
-
-
- - {formatNumberSeperator(option.Value)} - -
-
+ + {option.Name} + + + + + + {/* No Description property */} -
+
))} -
-
+ + ))} -
+ ); } \ No newline at end of file diff --git a/Website/components/datamodelview/attributes/StringAttribute.tsx b/Website/components/datamodelview/attributes/StringAttribute.tsx index 2c2e461..ce533c7 100644 --- a/Website/components/datamodelview/attributes/StringAttribute.tsx +++ b/Website/components/datamodelview/attributes/StringAttribute.tsx @@ -2,7 +2,16 @@ import { StringAttributeType } from "@/lib/Types"; import { formatNumberSeperator } from "@/lib/utils"; +import { Typography } from "@mui/material"; export default function StringAttribute({ attribute } : { attribute: StringAttributeType }) { - return <>Text ({formatNumberSeperator(attribute.MaxLength)}){attribute.Format !== "Text" ? ` - ${attribute.Format}` : ""}; + return ( + <> + Text + {" "} + + ({formatNumberSeperator(attribute.MaxLength)}){attribute.Format !== "Text" ? ` - ${attribute.Format}` : ""} + + + ); } \ No newline at end of file diff --git a/Website/components/datamodelview/entity/AttributeDetails.tsx b/Website/components/datamodelview/entity/AttributeDetails.tsx index 93298fc..766c50e 100644 --- a/Website/components/datamodelview/entity/AttributeDetails.tsx +++ b/Website/components/datamodelview/entity/AttributeDetails.tsx @@ -1,8 +1,8 @@ 'use client' -import { AttributeType, CalculationMethods, RequiredLevel } from "@/lib/Types"; -import { Calculator, CircleAlert, CirclePlus, Eye, Lock, Sigma, Zap } from "lucide-react"; -import { HybridTooltip, HybridTooltipContent, HybridTooltipTrigger } from "../../shared/ui/hybridtooltop"; +import { AttributeType, CalculationMethods, ComponentType, RequiredLevel } from "@/lib/Types"; +import { AddCircleOutlineRounded, CalculateRounded, ElectricBoltRounded, ErrorRounded, FunctionsRounded, LockRounded, VisibilityRounded } from "@mui/icons-material"; +import { Tooltip } from "@mui/material"; export function AttributeDetails({ attribute }: { attribute: AttributeType }) { const details = []; @@ -10,44 +10,41 @@ export function AttributeDetails({ attribute }: { attribute: AttributeType }) { switch (attribute.RequiredLevel) { case RequiredLevel.SystemRequired: case RequiredLevel.ApplicationRequired: - details.push({ icon: , tooltip: "Required" }); + details.push({ icon: , tooltip: "Required" }); break; case RequiredLevel.Recommended: - details.push({ icon: , tooltip: "Recommended" }); + details.push({ icon: , tooltip: "Recommended" }); break; } switch (attribute.CalculationMethod) { case CalculationMethods.Calculated: - details.push({ icon: , tooltip: "Calculated" }); + details.push({ icon: , tooltip: "Calculated" }); break; case CalculationMethods.Rollup: - details.push({ icon: , tooltip: "Rollup" }); + details.push({ icon: , tooltip: "Rollup" }); break; } if (attribute.IsAuditEnabled) { - details.push({ icon: , tooltip: "Audit Enabled" }); + details.push({ icon: , tooltip: "Audit Enabled" }); } if (attribute.IsColumnSecured) { - details.push({ icon: , tooltip: "Field Security" }); + details.push({ icon: , tooltip: "Field Security" }); } - if (attribute.HasPluginStep) { - const pluginTypesTooltip = attribute.PluginTypeNames.length > 0 - ? `Plugin Steps: ${attribute.PluginTypeNames.join(', ')}` - : "Plugin Step"; - details.push({ icon: , tooltip: pluginTypesTooltip }); + if (attribute.AttributeUsages.some(a => a.ComponentType == ComponentType.Plugin)) { + const tooltip = `Plugins ${attribute.AttributeUsages.map(au => au.Name).join(", ")}`; + details.push({ icon: , tooltip }); } return (
{details.map((detail, index) => ( - - {detail.icon} - {detail.tooltip} - + + {detail.icon} + ))}
); diff --git a/Website/components/datamodelview/entity/EntityDetails.tsx b/Website/components/datamodelview/entity/EntityDetails.tsx index 2d2a564..d3a2291 100644 --- a/Website/components/datamodelview/entity/EntityDetails.tsx +++ b/Website/components/datamodelview/entity/EntityDetails.tsx @@ -1,32 +1,32 @@ 'use client' import { EntityType, OwnershipType } from "@/lib/Types"; -import { Eye, ClipboardList, Paperclip, Building, Users } from "lucide-react"; -import { HybridTooltip, HybridTooltipContent, HybridTooltipTrigger } from "../../shared/ui/hybridtooltop"; +import { AssignmentRounded, AttachmentRounded, BusinessRounded, FaceRounded, VisibilityRounded } from "@mui/icons-material"; +import { Chip, ChipPropsColorOverrides, Tooltip } from "@mui/material"; +import { OverridableStringUnion } from "@mui/types"; type EntityDetailType = { icon: JSX.Element; tooltip: string; - color?: string; + color?: OverridableStringUnion<'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning', ChipPropsColorOverrides>; }; export function EntityDetails({ entity }: { entity: EntityType }) { const details = getEntityDetails(entity); if (details.length === 0) return null; - + return (
{details.map((detail, index) => ( - - -
- {detail.icon} - {detail.tooltip} -
-
- {detail.tooltip} -
+ + + ))}
); @@ -37,40 +37,40 @@ function getEntityDetails(entity: EntityType): EntityDetailType[] { if (entity.IsAuditEnabled) { details.push({ - icon: , + icon: , tooltip: "Audit Enabled", - color: 'bg-purple-50 text-purple-700' + color: "primary" }); } if (entity.IsActivity) { details.push({ - icon: , + icon: , tooltip: "Is Activity", - color: 'bg-green-50 text-green-700' + color: 'success' }); } if (entity.IsNotesEnabled) { details.push({ - icon: , + icon: , tooltip: "Notes Enabled", - color: 'bg-orange-50 text-orange-700' + color: 'warning' }); } switch (entity.Ownership) { case OwnershipType.OrganizationOwned: details.push({ - icon: , + icon: , tooltip: "Organization Owned", - color: 'bg-gray-50 text-gray-700' + color: 'info' }); break; case OwnershipType.UserOwned: case OwnershipType.TeamOwned: details.push({ - icon: , + icon: , tooltip: "User/Team Owned", - color: 'bg-gray-50 text-gray-700' + color: 'info' }); break; } diff --git a/Website/components/datamodelview/entity/EntityHeader.tsx b/Website/components/datamodelview/entity/EntityHeader.tsx index 2236679..9b4fc63 100644 --- a/Website/components/datamodelview/entity/EntityHeader.tsx +++ b/Website/components/datamodelview/entity/EntityHeader.tsx @@ -1,45 +1,96 @@ 'use client' import { EntityType } from "@/lib/Types"; -import { Link } from "lucide-react"; import { EntityDetails } from "./EntityDetails"; +import { Box, Typography, Paper, useTheme } from '@mui/material'; +import { LinkRounded } from "@mui/icons-material"; export function EntityHeader({ entity }: { entity: EntityType }) { + const theme = useTheme(); + return ( -
-
-
+ + + {entity.IconBase64 == null ? - : - + : +
} -
- -
+ {entity.DisplayName} + + + {entity.SchemaName} + + + -
+ -
+ {entity.Description && ( -
-

+ + {entity.Description} -

-
+ + )} -
+ ); } \ No newline at end of file diff --git a/Website/components/datamodelview/entity/SecurityRoles.tsx b/Website/components/datamodelview/entity/SecurityRoles.tsx index 82b5632..de771bc 100644 --- a/Website/components/datamodelview/entity/SecurityRoles.tsx +++ b/Website/components/datamodelview/entity/SecurityRoles.tsx @@ -1,24 +1,58 @@ 'use client' import { SecurityRole, PrivilegeDepth } from "@/lib/Types"; -import { Ban, User, Users, Boxes, Building2, Minus } from "lucide-react"; -import { HybridTooltip, HybridTooltipContent, HybridTooltipTrigger } from "../../shared/ui/hybridtooltop"; +import { AccountTreeRounded, BlockRounded, BusinessRounded, PeopleRounded, PersonRounded, RemoveRounded } from "@mui/icons-material"; +import { Tooltip, Box, Typography, Paper, useTheme } from "@mui/material"; export function SecurityRoles({ roles }: { roles: SecurityRole[] }) { return ( -
+ {roles.map(role => ( ))} -
+ ); } function SecurityRoleRow({ role }: { role: SecurityRole }) { + const theme = useTheme(); + return ( -
-

{role.Name}

-
+ + + {role.Name} + + @@ -27,48 +61,70 @@ function SecurityRoleRow({ role }: { role: SecurityRole }) { -
-
+ + ); } function PrivilegeIcon({ name, depth }: { name: string, depth: PrivilegeDepth | null }) { return ( -
-

{name}

+ + + {name} + -
+ ); } function GetDepthIcon({ depth }: { depth: PrivilegeDepth | null }) { - + const theme = useTheme(); + let icon = null; let tooltip = ""; if (depth === null || depth === undefined) { - icon = ; + icon = ; tooltip = "Unavailable"; } else { switch (depth) { case PrivilegeDepth.None: - icon = ; + icon = ; tooltip = "None"; break; case PrivilegeDepth.Basic: - icon = ; + icon = ; tooltip = "User"; break; case PrivilegeDepth.Local: - icon = ; + icon = ; tooltip = "Business Unit"; break; case PrivilegeDepth.Deep: - icon = ; + icon = ; tooltip = "Parent: Child Business Units"; break; case PrivilegeDepth.Global: - icon = ; + icon = ; tooltip = "Organization"; break; default: @@ -77,9 +133,10 @@ function GetDepthIcon({ depth }: { depth: PrivilegeDepth | null }) { } return ( - - {icon} - {tooltip} - + + + {icon} + + ); } \ No newline at end of file diff --git a/Website/components/diagramview/DiagramControls.tsx b/Website/components/diagramview/DiagramControls.tsx index 9ab53d1..bb3eb26 100644 --- a/Website/components/diagramview/DiagramControls.tsx +++ b/Website/components/diagramview/DiagramControls.tsx @@ -1,16 +1,7 @@ import React from 'react'; -import { Button } from '@/components/shared/ui/button'; -import { Separator } from '@/components/shared/ui/separator'; -import { - ZoomIn, - ZoomOut, - RotateCcw, - Maximize, - Settings, - Layers, - Search -} from 'lucide-react'; +import { Button, Divider, Typography, Box } from '@mui/material'; import { useDiagramViewContext } from '@/contexts/DiagramViewContext'; +import { AspectRatioRounded, LayersRounded, RefreshRounded, SearchRounded, SettingsRounded, ZoomInRounded, ZoomOutRounded } from '@mui/icons-material'; export const DiagramControls: React.FC = () => { const { @@ -19,63 +10,72 @@ export const DiagramControls: React.FC = () => { } = useDiagramViewContext(); return ( -
-
-

View Controls

-
+ + + + View Controls + + -
-
+ + - + -
-

Tools

-
+ + + Tools + + -
-
-
+ + + ); }; @@ -83,9 +83,9 @@ export const DiagramZoomDisplay: React.FC = () => { const { zoom } = useDiagramViewContext(); return ( -
+ Zoom: {Math.round(zoom * 100)}% -
+ ); }; @@ -93,23 +93,21 @@ export const DiagramZoomControls: React.FC = () => { const { zoomIn, zoomOut } = useDiagramViewContext(); return ( -
+ -
+ ); }; \ No newline at end of file diff --git a/Website/components/diagramview/DiagramResetButton.tsx b/Website/components/diagramview/DiagramResetButton.tsx index 21ca7d4..12ab467 100644 --- a/Website/components/diagramview/DiagramResetButton.tsx +++ b/Website/components/diagramview/DiagramResetButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Button } from '@/components/shared/ui/button'; -import { RotateCcw } from 'lucide-react'; +import { Button } from '@mui/material'; +import { RefreshRounded } from '@mui/icons-material'; interface DiagramResetButtonProps { onReset: () => void; @@ -13,13 +13,13 @@ export const DiagramResetButton: React.FC = ({ }) => { return ( ); diff --git a/Website/components/diagramview/DiagramView.tsx b/Website/components/diagramview/DiagramView.tsx index dd2c474..867c6eb 100644 --- a/Website/components/diagramview/DiagramView.tsx +++ b/Website/components/diagramview/DiagramView.tsx @@ -13,12 +13,26 @@ import { SquarePropertiesPane } from '@/components/diagramview/panes/SquarePrope import { TextPropertiesPane } from '@/components/diagramview/panes/TextPropertiesPane'; import { calculateGridLayout, getDefaultLayoutOptions, calculateEntityHeight, estimateEntityDimensions } from '@/components/diagramview/GridLayoutManager'; import { AttributeType } from '@/lib/Types'; -import { AppSidebar } from '../shared/AppSidebar'; -import { DiagramViewProvider, useDiagramViewContext } from '@/contexts/DiagramViewContext'; +import { useDiagramViewContext } from '@/contexts/DiagramViewContext'; import { SidebarDiagramView } from './SidebarDiagramView'; -import { useSidebarDispatch } from '@/contexts/SidebarContext'; +import { useSidebar } from '@/contexts/SidebarContext'; import { SimpleDiagramRenderer } from './renderers/SimpleDiagramRender'; import { DetailedDiagramRender } from './renderers/DetailedDiagramRender'; +import { Alert, Box } from '@mui/material'; +import { Science } from '@mui/icons-material'; + +export default function DiagramView({ }: IDiagramView) { + const { setElement, expand } = useSidebar(); + + useEffect(() => { + setElement(); + expand(); + }, []) + + return ( + + ); +} interface IDiagramView {} @@ -781,44 +795,73 @@ const DiagramContent = () => { return ( <> -
+
{/* Beta Disclaimer Banner */} -
-
-
- β -
-

- Open Beta Feature: This ER Diagram feature is currently in beta. Some functionality may not work fully. we do not recommend more than 20 entities -

-
-
+ + } + sx={{ + borderRadius: 0, + '& .MuiAlert-message': { + display: 'flex', + alignItems: 'center', + gap: 1, + flexWrap: 'wrap' + } + }} + > + + + Open Beta Feature: + {' '}This ER Diagram feature is currently in beta. Some functionality may not work fully. + {' '}We do not recommend more than 20 entities + + + + {/* Diagram Area */} -
+ {isLoading && ( -
-
-
+ theme.palette.mode === 'dark' + ? 'rgba(17, 24, 39, 0.5)' + : 'rgba(248, 250, 252, 0.5)' + }} + > + + {[...Array(3)].map((_, i) => ( -
))} -
-

+ + Loading diagram... -

-
-
+ + + )} {/* Zoom and Coordinate Indicator */} @@ -827,7 +870,7 @@ const DiagramContent = () => { mousePosition={mousePosition} /> -
+
{/* Entity Actions Pane */} @@ -871,21 +914,3 @@ const DiagramContent = () => { ) }; - -export default function DiagramView({ }: IDiagramView) { - const dispatch = useSidebarDispatch(); - - useEffect(() => { - dispatch({ type: "SET_ELEMENT", payload: }) - dispatch({ type: 'SET_SHOW_ELEMENT', payload: true }); - }, []) - - return ( - -
- - -
-
- ); -} diff --git a/Website/components/diagramview/GroupSelector.tsx b/Website/components/diagramview/GroupSelector.tsx deleted file mode 100644 index d49671a..0000000 --- a/Website/components/diagramview/GroupSelector.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import { GroupType } from '@/lib/Types'; -import { Button } from '@/components/shared/ui/button'; -import { Separator } from '@/components/shared/ui/separator'; -import { FolderOpen, Folder } from 'lucide-react'; -import { cn } from '@/lib/utils'; - -interface GroupSelectorProps { - groups: GroupType[]; - selectedGroup: GroupType | null; - onGroupSelect: (group: GroupType) => void; -} - -export const GroupSelector: React.FC = ({ - groups, - selectedGroup, - onGroupSelect -}) => { - return ( -
-
-

Groups

- - {groups.length} total - -
- - - -
-
- {groups.map((group) => { - const isSelected = selectedGroup?.Name === group.Name; - const entityCount = group.Entities.length; - - return ( - - ); - })} -
-
-
- ); -}; \ No newline at end of file diff --git a/Website/components/diagramview/SidebarDiagramView.tsx b/Website/components/diagramview/SidebarDiagramView.tsx index 25c2a46..2ddd67e 100644 --- a/Website/components/diagramview/SidebarDiagramView.tsx +++ b/Website/components/diagramview/SidebarDiagramView.tsx @@ -1,12 +1,19 @@ import React, { useState } from 'react'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/shared/ui/tabs'; -import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/shared/ui/collapsible'; -import { Button } from '@/components/shared/ui/button'; -import { ChevronDown, ChevronRight, Database, Square, Type, Settings, Hammer, Users, Save, Upload, Smartphone, RotateCcw, Trash2 } from 'lucide-react'; +import { + Tabs, + Tab, + Box, + Button, + Collapse, + Typography, + Divider, +} from '@mui/material'; +import { CheckBoxOutlineBlankRounded, ChevronRightRounded, DeleteRounded, DriveFolderUploadRounded, ExpandMoreRounded, FolderRounded, HardwareRounded, PeopleRounded, RttRounded, SaveRounded, SettingsRounded, SmartphoneRounded, SyncRounded } from '@mui/icons-material'; import { useDiagramViewContextSafe } from '@/contexts/DiagramViewContext'; import { AddEntityPane, AddGroupPane, ResetToGroupPane } from '@/components/diagramview/panes'; import { useIsMobile } from '@/hooks/use-mobile'; import { GroupType } from '@/lib/Types'; +import CustomTabPanel from '../shared/elements/TabPanel'; interface ISidebarDiagramViewProps { @@ -20,13 +27,14 @@ export const SidebarDiagramView = ({ }: ISidebarDiagramViewProps) => { const [isEntitySheetOpen, setIsEntitySheetOpen] = useState(false); const [isGroupSheetOpen, setIsGroupSheetOpen] = useState(false); const [isResetSheetOpen, setIsResetSheetOpen] = useState(false); + const [tab, setTab] = useState(0); // If not in diagram context, show a message or return null if (!diagramContext) { return (
- +

Diagram tools are only available on the diagram page.

@@ -58,199 +66,281 @@ export const SidebarDiagramView = ({ }: ISidebarDiagramViewProps) => { return (
- - - - - - - - - - - + + setTab(newValue)} aria-label="Diagram view tabs" variant="fullWidth"> + + + Build + + } + sx={{ minWidth: 0, flex: 1, fontSize: '0.75rem' }} + /> + + + Settings + + } + sx={{ minWidth: 0, flex: 1, fontSize: '0.75rem' }} + /> + + + {/* Mobile Notice */} {isMobile && ( -
-
- -
-

Mobile Mode

-

- Some advanced features may have limited functionality on mobile devices. - For the best experience, use a desktop computer. -

-
-
-
+ + + + + Mobile Mode + + + Some advanced features may have limited functionality on mobile devices. + For the best experience, use a desktop computer. + + + )} {/* Data Section */} - - - + + + + + + + + + {/* General Section */} + + + + + + + + + +
+ + + + + Diagram Type + + + Choose between simple or detailed entity view + + + - - - - - - - - {/* General Section */} - - - - - - - - - - - - -

Layers functionality coming soon...

-
- - -
-
-

Diagram Type

-

- Choose between simple or detailed entity view -

-
- - -
-
- -
-
-

Save & Load

-

- Save your diagram or load an existing one -

-
- - -
-
-
- -
-
-

Current Settings

-
-

Diagram Type: {diagramType}

-

Entities in Diagram: {currentEntities.length}

-
-
-
- -
-
-

Diagram Actions

-

- Reset or clear your diagram -

-
- - -
-
-
-
-
- +
+
+
+ {/* Add Entity Pane */} = (
- + {zoomPercentage}% @@ -26,7 +26,7 @@ export const ZoomCoordinateIndicator: React.FC = ( <>
- + X: {mousePosition.x}, Y: {mousePosition.y} diff --git a/Website/components/diagramview/elements/SimpleEntityElement.ts b/Website/components/diagramview/elements/SimpleEntityElement.ts index f667d93..2c79936 100644 --- a/Website/components/diagramview/elements/SimpleEntityElement.ts +++ b/Website/components/diagramview/elements/SimpleEntityElement.ts @@ -21,7 +21,7 @@ export class SimpleEntityElement extends dia.Element { circle: { r: 6, magnet: true, - fill: '#fff', + fill: 'var(--mui-palette-background-paper)', stroke: '#42a5f5', strokeWidth: 2, visibility: 'hidden', @@ -34,7 +34,7 @@ export class SimpleEntityElement extends dia.Element { circle: { r: 6, magnet: true, - fill: '#fff', + fill: 'var(--mui-palette-background-paper)', stroke: '#42a5f5', strokeWidth: 2, visibility: 'hidden', @@ -47,7 +47,7 @@ export class SimpleEntityElement extends dia.Element { circle: { r: 6, magnet: true, - fill: '#fff', + fill: 'var(--mui-palette-background-paper)', stroke: '#42a5f5', strokeWidth: 2, visibility: 'hidden', @@ -60,7 +60,7 @@ export class SimpleEntityElement extends dia.Element { circle: { r: 6, magnet: true, - fill: '#fff', + fill: 'var(--mui-palette-background-paper)', stroke: '#42a5f5', strokeWidth: 2, visibility: 'hidden', @@ -97,7 +97,7 @@ export class SimpleEntityElement extends dia.Element { body: { refWidth: '100%', refHeight: '100%', - fill: '#fff', + fill: 'var(--mui-palette-background-paper)', stroke: '#d1d5db', rx: 12 }, diff --git a/Website/components/diagramview/panes/AddAttributePane.tsx b/Website/components/diagramview/panes/AddAttributePane.tsx index 6d45ffa..f68be18 100644 --- a/Website/components/diagramview/panes/AddAttributePane.tsx +++ b/Website/components/diagramview/panes/AddAttributePane.tsx @@ -2,30 +2,19 @@ import React, { useState } from 'react'; import { - Sheet, - SheetContent, - SheetHeader, - SheetTitle, - SheetDescription, - SheetFooter -} from '@/components/shared/ui/sheet'; -import { Button } from '@/components/shared/ui/button'; -import { Input } from '@/components/shared/ui/input'; -import { Label } from '@/components/shared/ui/label'; -import { Card, CardContent } from '@/components/shared/ui/card'; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/shared/ui/tooltip'; -import { - Type, - Calendar, - Hash, - Search, - DollarSign, - ToggleLeft, - FileText, - List, - Activity, -} from 'lucide-react'; + Dialog, + DialogContent, + DialogTitle, + DialogActions, + Button, + TextField, + Card, + CardContent, + Typography, + Tooltip +} from '@mui/material'; import { AttributeType } from '@/lib/Types'; +import { AssignmentRounded, AttachmentRounded, AttachMoneyRounded, CalendarMonthRounded, ListRounded, NumbersRounded, RttRounded, SearchRounded, ToggleOffRounded } from '@mui/icons-material'; export interface AddAttributePaneProps { isOpen: boolean; @@ -38,16 +27,16 @@ export interface AddAttributePaneProps { const getAttributeIcon = (attributeType: string) => { switch (attributeType) { - case 'StringAttribute': return Type; - case 'IntegerAttribute': return Hash; - case 'DecimalAttribute': return DollarSign; - case 'DateTimeAttribute': return Calendar; - case 'BooleanAttribute': return ToggleLeft; - case 'ChoiceAttribute': return List; - case 'LookupAttribute': return Search; - case 'FileAttribute': return FileText; - case 'StatusAttribute': return Activity; - default: return Type; + case 'StringAttribute': return RttRounded; + case 'IntegerAttribute': return NumbersRounded; + case 'DecimalAttribute': return AttachMoneyRounded; + case 'DateTimeAttribute': return CalendarMonthRounded; + case 'BooleanAttribute': return ToggleOffRounded; + case 'ChoiceAttribute': return ListRounded; + case 'LookupAttribute': return SearchRounded; + case 'FileAttribute': return AttachmentRounded; + case 'StatusAttribute': return AssignmentRounded; + default: return RttRounded; } }; @@ -90,93 +79,86 @@ export const AddAttributePane: React.FC = ({ }; return ( - - - - - Add Existing Attribute ({availableAttributes.length}) - - {entityName ? `Select an attribute from "${entityName}" to add to the diagram.` : 'Select an attribute to add to the diagram.'} - - + + + Add Existing Attribute ({availableAttributes.length}) + + {entityName ? `Select an attribute from "${entityName}" to add to the diagram.` : 'Select an attribute to add to the diagram.'} + -
- {/* Search */} -
- - setSearchQuery(e.target.value)} - placeholder="Search by attribute name..." - /> -
+
+ {/* Search */} +
+ Search Attributes + ) => setSearchQuery(e.target.value)} + placeholder="Search by attribute name..." + /> +
- {/* Available Attributes */} -
- -
-
- {addableAttributes.length === 0 ? ( -
- {searchQuery ? 'No attributes found matching your search.' : 'No attributes available to add.'} -
- ) : ( -
- {addableAttributes.map((attribute) => { - const AttributeIcon = getAttributeIcon(attribute.AttributeType); - const typeLabel = getAttributeTypeLabel(attribute.AttributeType); - - return ( - handleAddAttribute(attribute)} - > - -
-
- + {/* Available Attributes */} +
+ Available Attributes ({addableAttributes.length}) +
+
+ {addableAttributes.length === 0 ? ( +
+ {searchQuery ? 'No attributes found matching your search.' : 'No attributes available to add.'} +
+ ) : ( +
+ {addableAttributes.map((attribute) => { + const AttributeIcon = getAttributeIcon(attribute.AttributeType); + const typeLabel = getAttributeTypeLabel(attribute.AttributeType); + + return ( + handleAddAttribute(attribute)} + sx={{ cursor: 'pointer', '&:hover': { backgroundColor: 'action.hover' } }} + > + +
+
+ +
+
+
+ {attribute.DisplayName}
-
-
- {attribute.DisplayName} -
-
- {typeLabel} • {attribute.SchemaName} -
+
+ {typeLabel} • {attribute.SchemaName}
- {attribute.Description && ( - - -
- ? -
-
- -

{attribute.Description}

-
-
- )}
- - - ); - })} -
- )} -
+ {attribute.Description && ( + +
+ ? +
+
+ )} +
+ + + ); + })} +
+ )}
- - - -
- - - +
+ + + + + +
); }; diff --git a/Website/components/diagramview/panes/AddEntityPane.tsx b/Website/components/diagramview/panes/AddEntityPane.tsx index 1bfc258..1ebdaca 100644 --- a/Website/components/diagramview/panes/AddEntityPane.tsx +++ b/Website/components/diagramview/panes/AddEntityPane.tsx @@ -1,15 +1,21 @@ 'use client'; import React, { useState, useMemo } from 'react'; -import { Button } from '@/components/shared/ui/button'; -import { Input } from '@/components/shared/ui/input'; -import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/shared/ui/sheet'; -import { Checkbox } from '@/components/shared/ui/checkbox'; -import { Search } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogTitle, + Button, + TextField, + Checkbox, + Typography, + FormControlLabel +} from '@mui/material'; import { Groups } from '@/generated/Data'; import { EntityType, GroupType, AttributeType } from '@/lib/Types'; import { useAttributeSelection } from '@/hooks/useAttributeSelection'; import { AttributeSelectionPanel } from './AttributeSelectionPanel'; +import { SearchRounded } from '@mui/icons-material'; export interface AddEntityPaneProps { isOpen: boolean; @@ -81,12 +87,10 @@ export const AddEntityPane: React.FC = ({ }; return ( - - - - Add Entity to Diagram - -
+ onOpenChange(false)} maxWidth="md" fullWidth> + + Add Entity to Diagram +
{/* Attribute Selection Options */} = ({ {/* Search Input */}
- - + setSearchTerm(e.target.value)} - className="pl-10" + onChange={(e: React.ChangeEvent) => setSearchTerm(e.target.value)} + sx={{ pl: '40px' }} + InputProps={{ style: { paddingLeft: '40px' } }} />
@@ -112,16 +119,16 @@ export const AddEntityPane: React.FC = ({
{filteredData.map((group: GroupType) => (
-

+ {group.Name} -

+
{group.Entities.map((entity: EntityType) => { const isAlreadyInDiagram = currentEntities.some(e => e.SchemaName === entity.SchemaName); return ( @@ -232,7 +253,7 @@ export const AddEntityPane: React.FC = ({
)}
- - + +
); }; diff --git a/Website/components/diagramview/panes/AddGroupPane.tsx b/Website/components/diagramview/panes/AddGroupPane.tsx index de95608..872b743 100644 --- a/Website/components/diagramview/panes/AddGroupPane.tsx +++ b/Website/components/diagramview/panes/AddGroupPane.tsx @@ -1,14 +1,19 @@ 'use client'; import React, { useState, useMemo } from 'react'; -import { Button } from '@/components/shared/ui/button'; -import { Input } from '@/components/shared/ui/input'; -import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/shared/ui/sheet'; -import { Search, Database } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogTitle, + Button, + TextField, + Typography +} from '@mui/material'; import { Groups } from '@/generated/Data'; import { EntityType, GroupType } from '@/lib/Types'; import { useAttributeSelection } from '@/hooks/useAttributeSelection'; import { AttributeSelectionPanel } from './AttributeSelectionPanel'; +import { FolderRounded, SearchRounded } from '@mui/icons-material'; export interface AddGroupPaneProps { isOpen: boolean; @@ -67,12 +72,10 @@ export const AddGroupPane: React.FC = ({ }; return ( - - - - Add Group to Diagram - -
+ onOpenChange(false)} maxWidth="md" fullWidth> + + Add Group to Diagram +
{/* Attribute Selection Options */} = ({ {/* Search Input */}
- - + setSearchTerm(e.target.value)} - className="pl-10" + onChange={(e: React.ChangeEvent) => setSearchTerm(e.target.value)} + slotProps={{ input: { style: { paddingLeft: '40px' } } }} />
@@ -104,18 +109,18 @@ export const AddGroupPane: React.FC = ({
- +
-

{group.Name}

-

+ {group.Name} + {group.Entities.length} entities -

+
-
+ {entitiesInDiagram}/{totalEntities} entities -
+ {isFullyInDiagram && ( All in Diagram @@ -146,16 +151,16 @@ export const AddGroupPane: React.FC = ({ ); })} {group.Entities.length > 5 && ( - + +{group.Entities.length - 5} more - + )}
- - + +
); }; diff --git a/Website/components/diagramview/panes/AttributeSelectionPanel.tsx b/Website/components/diagramview/panes/AttributeSelectionPanel.tsx index cfcefca..7b5a150 100644 --- a/Website/components/diagramview/panes/AttributeSelectionPanel.tsx +++ b/Website/components/diagramview/panes/AttributeSelectionPanel.tsx @@ -1,11 +1,17 @@ 'use client'; import React from 'react'; -import { Button } from '@/components/shared/ui/button'; -import { Label } from '@/components/shared/ui/label'; -import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/shared/ui/collapsible'; -import { ChevronDown, ChevronRight, Settings } from 'lucide-react'; +import { + Button, + Collapse, + RadioGroup, + FormControlLabel, + Radio, + Typography, + Box +} from '@mui/material'; import { AttributeSelectionMode } from '@/hooks/useAttributeSelection'; +import { ChevronRightRounded, ExpandRounded, SettingsRounded } from '@mui/icons-material'; export interface AttributeSelectionPanelProps { attributeMode: AttributeSelectionMode; @@ -23,75 +29,68 @@ export const AttributeSelectionPanel: React.FC = ( getAttributeModeDescription }) => { return ( - - - - - -
- -
-
- setAttributeMode('minimal')} - className="w-4 h-4" - /> - -
-
- setAttributeMode('custom-lookups')} - className="w-4 h-4" - /> - -
-
- setAttributeMode('all-lookups')} - className="w-4 h-4" - /> - -
-
- setAttributeMode('custom')} - className="w-4 h-4" - /> - -
-
-
-
-
+ + + + + + + Default attributes to include: + + ) => setAttributeMode(e.target.value as AttributeSelectionMode)} + > + } + label={ + + {getAttributeModeDescription('minimal')} + + } + /> + } + label={ + + {getAttributeModeDescription('custom-lookups')} + + } + /> + } + label={ + + {getAttributeModeDescription('all-lookups')} + + } + /> + } + label={ + + {getAttributeModeDescription('custom')} + + } + /> + + + + ); }; diff --git a/Website/components/diagramview/panes/EntityActionsPane.tsx b/Website/components/diagramview/panes/EntityActionsPane.tsx index d4e974e..c01f8ad 100644 --- a/Website/components/diagramview/panes/EntityActionsPane.tsx +++ b/Website/components/diagramview/panes/EntityActionsPane.tsx @@ -1,27 +1,21 @@ 'use client'; import React, { useState } from 'react'; -import { Button } from '@/components/shared/ui/button'; -import { Input } from '@/components/shared/ui/input'; -import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/shared/ui/sheet'; -import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/shared/ui/collapsible'; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/shared/ui/tooltip'; import { - Trash2, - Plus, - ChevronDown, - ChevronRight, - Type, - Calendar, - Hash, - Search, - DollarSign, - ToggleLeft, - FileText, - List, - Activity -} from 'lucide-react'; + Dialog, + DialogContent, + DialogTitle, + Button, + TextField, + Collapse, + Box, + Typography, + Card, + CardContent, + Tooltip +} from '@mui/material'; import { EntityType, AttributeType } from '@/lib/Types'; +import { RttRounded, NumbersRounded, AttachMoneyRounded, CalendarMonthRounded, ToggleOffRounded, ListRounded, SearchRounded, AttachmentRounded, AssignmentRounded, ChevronRight, AddRounded, ExpandRounded, DeleteRounded } from '@mui/icons-material'; export interface EntityActionsPaneProps { isOpen: boolean; @@ -36,16 +30,16 @@ export interface EntityActionsPaneProps { const getAttributeIcon = (attributeType: string) => { switch (attributeType) { - case 'StringAttribute': return Type; - case 'IntegerAttribute': return Hash; - case 'DecimalAttribute': return DollarSign; - case 'DateTimeAttribute': return Calendar; - case 'BooleanAttribute': return ToggleLeft; - case 'ChoiceAttribute': return List; - case 'LookupAttribute': return Search; - case 'FileAttribute': return FileText; - case 'StatusAttribute': return Activity; - default: return Type; + case 'StringAttribute': return RttRounded; + case 'IntegerAttribute': return NumbersRounded; + case 'DecimalAttribute': return AttachMoneyRounded; + case 'DateTimeAttribute': return CalendarMonthRounded; + case 'BooleanAttribute': return ToggleOffRounded; + case 'ChoiceAttribute': return ListRounded; + case 'LookupAttribute': return SearchRounded; + case 'FileAttribute': return AttachmentRounded; + case 'StatusAttribute': return AssignmentRounded; + default: return RttRounded; } }; @@ -105,158 +99,193 @@ export const EntityActionsPane: React.FC = ({ ); return ( - - - - - Entity Actions - - - {selectedEntity && ( -
+ onOpenChange(false)} maxWidth="sm" fullWidth> + + {selectedEntity && ( + <> + {selectedEntity.DisplayName} + +
-

{selectedEntity.DisplayName}

-

{selectedEntity.SchemaName}

+ + {selectedEntity.SchemaName} + {selectedEntity.Description && ( -

{selectedEntity.Description}

+ + {selectedEntity.Description} + )}
-

Actions

+ Actions {/* Add Attribute Section */} {onAddAttribute && availableAttributes.length > 0 && ( - - - - - - {/* Search */} -
- + + + + + {/* Search */} + setSearchQuery(e.target.value)} + onChange={(e: React.ChangeEvent) => setSearchQuery(e.target.value)} placeholder="Search attributes..." - className="text-sm" + sx={{ mb: 2 }} /> -
- {/* Available Attributes */} -
- {addableAttributes.length === 0 ? ( -
- {searchQuery ? 'No attributes found.' : 'No attributes available.'} -
- ) : ( - addableAttributes.map((attribute) => { + {/* Available Attributes */} + + {addableAttributes.length === 0 ? ( + + + {searchQuery ? 'No attributes found.' : 'No attributes available.'} + + + ) : ( + + {addableAttributes.map((attribute) => { + const AttributeIcon = getAttributeIcon(attribute.AttributeType); + const typeLabel = getAttributeTypeLabel(attribute.AttributeType); + + return ( + handleAddAttribute(attribute)} + > + + + + + + {attribute.DisplayName} + + + {typeLabel} + + + {attribute.Description && ( + + + ? + + + )} + + + + ); + })} + + )} + + + + + )} + + {/* Remove Attribute Section */} + {onRemoveAttribute && removableAttributes.length > 0 && ( + + + + + + + {removableAttributes.map((attribute) => { const AttributeIcon = getAttributeIcon(attribute.AttributeType); const typeLabel = getAttributeTypeLabel(attribute.AttributeType); return ( -
handleAddAttribute(attribute)} + handleRemoveAttribute(attribute)} > - -
-
- {attribute.DisplayName} -
-
- {typeLabel} -
-
- {attribute.Description && ( - - -
- ? -
-
- -

{attribute.Description}

-
-
- )} -
+ + + + + + {attribute.DisplayName} + + + {typeLabel} + + + + + + ); - }) - )} -
-
-
- )} - - {/* Remove Attribute Section */} - {onRemoveAttribute && removableAttributes.length > 0 && ( - - - - - - {/* Removable Attributes */} -
- {removableAttributes.map((attribute) => { - const AttributeIcon = getAttributeIcon(attribute.AttributeType); - const typeLabel = getAttributeTypeLabel(attribute.AttributeType); - - return ( -
handleRemoveAttribute(attribute)} - > - -
-
- {attribute.DisplayName} -
-
- {typeLabel} -
-
- -
- ); - })} -
-
- Note: Primary key cannot be removed. -
-
-
+ })} + + + Note: Primary key cannot be removed. + + + + )}
@@ -264,19 +293,27 @@ export const EntityActionsPane: React.FC = ({
-

Entity Information

+ Entity Information
-

Attributes: {selectedEntity.Attributes.length}

-

Relationships: {selectedEntity.Relationships?.length || 0}

-

Is Activity: {selectedEntity.IsActivity ? 'Yes' : 'No'}

-

Audit Enabled: {selectedEntity.IsAuditEnabled ? 'Yes' : 'No'}

+ + Attributes: {selectedEntity.Attributes.length} + + + Relationships: {selectedEntity.Relationships?.length || 0} + + + Is Activity: {selectedEntity.IsActivity ? 'Yes' : 'No'} + + + Audit Enabled: {selectedEntity.IsAuditEnabled ? 'Yes' : 'No'} +
- )} - - - + + )} + +
); }; diff --git a/Website/components/diagramview/panes/LinkPropertiesPane.tsx b/Website/components/diagramview/panes/LinkPropertiesPane.tsx index 1fd94c6..2e9d486 100644 --- a/Website/components/diagramview/panes/LinkPropertiesPane.tsx +++ b/Website/components/diagramview/panes/LinkPropertiesPane.tsx @@ -1,13 +1,21 @@ 'use client'; import React, { useState, useEffect } from 'react'; -import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/shared/ui/sheet'; -import { Button } from '@/components/shared/ui/button'; -import { Input } from '@/components/shared/ui/input'; -import { Label } from '@/components/shared/ui/label'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/shared/ui/select'; -import { Separator } from '@/components/shared/ui/separator'; import { dia } from '@joint/core'; +import { + Dialog, + DialogContent, + DialogTitle, + Button, + TextField, + Select, + MenuItem, + FormControl, + InputLabel, + Typography, + Box, + Divider +} from '@mui/material'; import { PRESET_COLORS, LINE_STYLES, STROKE_WIDTHS } from '../shared/DiagramConstants'; interface LinkPropertiesPaneProps { @@ -92,133 +100,138 @@ export const LinkPropertiesPane: React.FC = ({ }; return ( - - - - Link Properties - - Customize the appearance and label of the relationship link. - - - -
+ onOpenChange(false)} maxWidth="sm" fullWidth> + + Link Properties + + Customize the appearance and label of the relationship link. + + + {/* Label Section */} -
- - + Link Label + setLabel(e.target.value)} + onChange={(e: React.ChangeEvent) => setLabel(e.target.value)} /> -
+ -
-

+ + Optional text to display on the link -

-
+ +
- + {/* Color Section */} -
- -
+ + Link Color + {PRESET_COLORS.borders.map((presetColor) => ( ))} -
+ -
- + handleColorChange(e.target.value)} - className="w-12 h-8 p-1 border-2" + onChange={(e: React.ChangeEvent) => handleColorChange(e.target.value)} + sx={{ width: 48, '& .MuiInputBase-input': { p: 0.5 } }} + size="small" /> - handleColorChange(e.target.value)} + onChange={(e: React.ChangeEvent) => handleColorChange(e.target.value)} placeholder="#3b82f6" - className="flex-1 text-sm" /> -
-
+ + - + {/* Line Style Section */} -
- - setLineStyle(e.target.value)} + label="Line Style" + > {LINE_STYLES.map((style) => ( - + {style.name} - + ))} - - -
+ + + {/* Stroke Width Section */} -
- - setStrokeWidth(parseInt(e.target.value as string))} + label="Line Thickness" + > {STROKE_WIDTHS.map((width) => ( - + {width.name} ({width.value}px) - + ))} - - -
- - -
-
-
+ + + + + + ); }; diff --git a/Website/components/diagramview/panes/ResetToGroupPane.tsx b/Website/components/diagramview/panes/ResetToGroupPane.tsx index e996f18..47ec023 100644 --- a/Website/components/diagramview/panes/ResetToGroupPane.tsx +++ b/Website/components/diagramview/panes/ResetToGroupPane.tsx @@ -1,23 +1,20 @@ import React, { useState } from 'react'; -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "@/components/shared/ui/sheet"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/shared/ui/select"; -import { Label } from "@/components/shared/ui/label"; -import { Button } from '@/components/shared/ui/button'; -import { RotateCcw } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogTitle, + DialogActions, + Button, + Select, + MenuItem, + FormControl, + InputLabel, + Typography, + Box +} from '@mui/material'; import { Groups } from '../../../generated/Data'; import { GroupType } from '@/lib/Types'; +import { RefreshRounded } from '@mui/icons-material'; interface IResetToGroupPaneProps { isOpen: boolean; @@ -45,64 +42,59 @@ export const ResetToGroupPane = ({ isOpen, onOpenChange, onResetToGroup }: IRese }; return ( - - - - Reset Diagram to Group - - Choose a group to reset the diagram and show only entities from that group. - This will clear the current diagram and add all entities from the selected group. - - + onOpenChange(false)} maxWidth="sm" fullWidth> + + Reset Diagram to Group + + Choose a group to reset the diagram and show only entities from that group. + This will clear the current diagram and add all entities from the selected group. + -
-
- - setSelectedGroupForReset(e.target.value)} + label="Select Group" > - - - - - {Groups.map((group) => ( - - {group.Name} - - ))} - + {Groups.map((group) => ( + + {group.Name} + + ))} -
+ -
-
-
-

Warning

-

This will clear all current elements from your diagram and replace them with entities from the selected group.

-
-
-
- -
- - -
-
-
-
+ + + Warning + + + This will clear all current elements from your diagram and replace them with entities from the selected group. + + + + + + + + + + ); }; diff --git a/Website/components/diagramview/panes/SquarePropertiesPane.tsx b/Website/components/diagramview/panes/SquarePropertiesPane.tsx index 9d30ded..d3c01f8 100644 --- a/Website/components/diagramview/panes/SquarePropertiesPane.tsx +++ b/Website/components/diagramview/panes/SquarePropertiesPane.tsx @@ -1,13 +1,17 @@ import React, { useState, useEffect } from 'react'; -import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/shared/ui/sheet'; -import { Button } from '@/components/shared/ui/button'; -import { Input } from '@/components/shared/ui/input'; -import { Label } from '@/components/shared/ui/label'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/shared/ui/select'; -import { Separator } from '@/components/shared/ui/separator'; -import { Square, Trash2 } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogTitle, + Button, + TextField, + Typography, + Box, + Divider +} from '@mui/material'; import { SquareElement, SquareElementData } from '../elements/SquareElement'; import { PRESET_COLORS } from '../shared/DiagramConstants'; +import { DeleteRounded, SquareRounded } from '@mui/icons-material'; export interface SquarePropertiesPaneProps { isOpen: boolean; @@ -74,171 +78,186 @@ export const SquarePropertiesPane: React.FC = ({ } return ( - - - - - - Square Properties - - - -
+ onOpenChange(false)} maxWidth="sm" fullWidth> + + + Square Properties + + + {/* Fill Color Section */} -
- -
+ + + Fill Color + + {PRESET_COLORS.fills.map((color) => ( + /> ))} -
-
- + + handleDataChange('fillColor', e.target.value)} - className="w-12 h-8 p-1 border-2" + onChange={(e: React.ChangeEvent) => handleDataChange('fillColor', e.target.value)} + sx={{ width: 48, '& .MuiInputBase-input': { padding: 0.5, height: 32 } }} + size="small" /> - handleDataChange('fillColor', e.target.value)} + onChange={(e: React.ChangeEvent) => handleDataChange('fillColor', e.target.value)} placeholder="#f1f5f9" - className="flex-1 text-sm" + sx={{ flex: 1 }} + size="small" /> -
-
+
+ - + {/* Border Section */} -
- + + + Border + {/* Border Color */} -
- -
+ + + Color + + {PRESET_COLORS.borders.map((color) => ( + /> ))} -
-
- + + handleDataChange('borderColor', e.target.value)} - className="w-12 h-8 p-1 border-2" + onChange={(e: React.ChangeEvent) => handleDataChange('borderColor', e.target.value)} + sx={{ width: 48, '& .MuiInputBase-input': { padding: 0.5, height: 32 } }} + size="small" /> - handleDataChange('borderColor', e.target.value)} + onChange={(e: React.ChangeEvent) => handleDataChange('borderColor', e.target.value)} placeholder="#64748b" - className="flex-1 text-sm" + sx={{ flex: 1 }} + size="small" /> -
-
+
+ {/* Border Width */} -
- - + + Width + + handleDataChange('borderWidth', parseInt(e.target.value) || 0)} - className="text-sm" + onChange={(e: React.ChangeEvent) => handleDataChange('borderWidth', parseInt(e.target.value) || 0)} + size="small" + fullWidth /> -
+ {/* Border Type */} -
- - -
-
- - + + + + + + + + {/* Opacity Section */} -
- -
- + + Opacity + + + handleDataChange('opacity', parseFloat(e.target.value))} - className="w-full" + onChange={(e: React.ChangeEvent) => handleDataChange('opacity', parseFloat(e.target.value))} + fullWidth + size="small" /> -
+ {Math.round((squareData.opacity || 0.7) * 100)}% -
-
-
+ + + - + {/* Delete Section */} -
- + + + Danger Zone + -
-
-
-
+ + + + ); }; diff --git a/Website/components/diagramview/panes/TextPropertiesPane.tsx b/Website/components/diagramview/panes/TextPropertiesPane.tsx index 8b5613b..5ba731e 100644 --- a/Website/components/diagramview/panes/TextPropertiesPane.tsx +++ b/Website/components/diagramview/panes/TextPropertiesPane.tsx @@ -1,12 +1,16 @@ import React, { useState, useEffect } from 'react'; -import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/shared/ui/sheet'; -import { Button } from '@/components/shared/ui/button'; -import { Input } from '@/components/shared/ui/input'; -import { Label } from '@/components/shared/ui/label'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/shared/ui/select'; -import { Separator } from '@/components/shared/ui/separator'; -import { Type, Trash2 } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogTitle, + Button, + TextField, + Typography, + Box, + Divider +} from '@mui/material'; import { TextElement, TextElementData } from '../elements/TextElement'; +import { DeleteRounded, RttRounded } from '@mui/icons-material'; export interface TextPropertiesPaneProps { isOpen: boolean; @@ -24,6 +28,7 @@ const FONT_SIZES = [ ]; const FONT_FAMILIES = [ + { name: 'Roboto', value: 'Roboto, sans-serif' }, { name: 'System Font', value: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif' }, { name: 'Arial', value: 'Arial, sans-serif' }, { name: 'Helvetica', value: 'Helvetica, Arial, sans-serif' }, @@ -88,192 +93,215 @@ export const TextPropertiesPane: React.FC = ({ } return ( - - - - - - Text Properties - - - -
+ onOpenChange(false)} maxWidth="sm" fullWidth> + + + Text Properties + + + {/* Text Content */} -
- - + + Text Content + + ) => handleDataChange('text', e.target.value)} + fullWidth + size="small" /> -
+
- + {/* Typography */} -
- + + + Typography + {/* Font Family */} -
- - -
+ {FONT_FAMILIES.map((font) => ( + + ))} + +
{/* Font Size */} -
- - -
+ {FONT_SIZES.map((size) => ( + + ))} + + {/* Text Alignment */} -
- - -
-
+ + + + + + - + {/* Colors */} -
- + + + Colors + {/* Text Color */} -
- -
- + + Text Color + + + handleDataChange('color', e.target.value)} - className="w-12 h-8 p-1 border-2" + onChange={(e: React.ChangeEvent) => handleDataChange('color', e.target.value)} + sx={{ width: 48, '& .MuiInputBase-input': { padding: 0.5, height: 32 } }} + size="small" /> - handleDataChange('color', e.target.value)} + onChange={(e: React.ChangeEvent) => handleDataChange('color', e.target.value)} placeholder="#000000" - className="flex-1 text-sm" + sx={{ flex: 1 }} + size="small" /> -
-
+
+ {/* Background Color */} -
- -
- + + Background Color + + + handleDataChange('backgroundColor', e.target.value)} - className="w-12 h-8 p-1 border-2" + onChange={(e: React.ChangeEvent) => handleDataChange('backgroundColor', e.target.value)} + sx={{ width: 48, '& .MuiInputBase-input': { padding: 0.5, height: 32 } }} + size="small" /> - handleDataChange('backgroundColor', e.target.value)} + onChange={(e: React.ChangeEvent) => handleDataChange('backgroundColor', e.target.value)} placeholder="transparent" - className="flex-1 text-sm" + sx={{ flex: 1 }} + size="small" /> -
-
-
+ + + - + {/* Layout */} -
- + + + Layout + {/* Padding */} -
- - + + Padding + + handleDataChange('padding', parseInt(e.target.value) || 0)} - className="text-sm" + onChange={(e: React.ChangeEvent) => handleDataChange('padding', parseInt(e.target.value) || 0)} + size="small" + fullWidth /> -
+
{/* Border Radius */} -
- - + + Border Radius + + handleDataChange('borderRadius', parseInt(e.target.value) || 0)} - className="text-sm" + onChange={(e: React.ChangeEvent) => handleDataChange('borderRadius', parseInt(e.target.value) || 0)} + size="small" + fullWidth /> -
-
+ + - + {/* Delete Section */} {onDeleteText && ( -
- + + + Danger Zone + -
+ )} -
-
-
+ + + ); }; diff --git a/Website/components/homeview/HomeView.tsx b/Website/components/homeview/HomeView.tsx index 6d9468c..b31520d 100644 --- a/Website/components/homeview/HomeView.tsx +++ b/Website/components/homeview/HomeView.tsx @@ -1,53 +1,136 @@ 'use client' import { useEffect, useState } from 'react'; -import { AppSidebar } from '../shared/AppSidebar' -import { useSidebarDispatch } from '@/contexts/SidebarContext' +import { useSidebar } from '@/contexts/SidebarContext' import Markdown from 'react-markdown' +import { Box, Button, Grid, IconButton, Paper, Typography } from '@mui/material'; +import NotchedBox from '@/components/shared/elements/NotchedBox'; +import Carousel, { CarouselItem } from '@/components/shared/elements/Carousel'; +import { ChevronLeftRounded, ChevronRightRounded } from '@mui/icons-material'; +import { useRouter } from 'next/navigation'; interface IHomeViewProps { } export const HomeView = ({ }: IHomeViewProps) => { - const dispatch = useSidebarDispatch(); + const { setElement, close } = useSidebar(); + + const router = useRouter(); const [wikipage, setWikipage] = useState(''); + const [currentCarouselIndex, setCurrentCarouselIndex] = useState(0); + const [slideDirection, setSlideDirection] = useState<'left' | 'right' | null>(null); + + // Carousel data + const carouselItems: CarouselItem[] = [ + { + image: '/processes.jpg', + title: 'Process Explorer!', + text: "Work has started on the process explorer! This will be a place to figure out what processes are touching your fields. Everything from server- to client side.", + type: '(v2.0.0) Alpha Feature', + actionlabel: 'Try it out', + action: () => router.push('/processes') + }, + { + image: '/upgrade.jpg', + title: 'Data Model Viewer 2.0.0!', + text: "The UI has been refreshed for an even cleaner, more modern look with enhanced functionality. And we've upgraded the tech stack to ensure easier maintainability.", + type: '(v2.0.0) Announcement' + }, + { + image: '/documentation.jpg', + title: 'Home WIKI ADO Page', + text: 'Display your own wiki page from your ADO instance. Use it, to give your organisation a special introduction to DMV. Now also supports images!', + type: '(v1.4.1) Feature', + actionlabel: 'Read how', + action: () => window.open("https://github.com/delegateas/DataModelViewer", '_blank') + } + ]; + + const goToPrevious = () => { + setSlideDirection('left'); + setCurrentCarouselIndex((prevIndex) => + prevIndex === 0 ? carouselItems.length - 1 : prevIndex - 1 + ); + }; + + const goToNext = () => { + setSlideDirection('right'); + setCurrentCarouselIndex((prevIndex) => + prevIndex === carouselItems.length - 1 ? 0 : prevIndex + 1 + ); + }; useEffect(() => { - dispatch({ type: 'SET_ELEMENT', payload: <> }); - dispatch({ type: 'SET_SHOW_ELEMENT', payload: false }); + setElement(null); + close(); fetch('/api/markdown') .then(res => res.json()) .then(data => setWikipage(data.fileContent.replace(/\\n/g, '\n'))); }, []); return ( -
- - -
-
-

Welcome back to your datamodel!

-
-
- {/* Add loading state */} - {wikipage ? ( -

, - h2: ({ ...props }) =>

, - h3: ({ ...props }) =>

, - h4: ({ ...props }) =>

, - p: ({ ...props }) =>

, - a: ({ ...props }) => , - li: ({ ...props }) =>

  • , - span: ({ ...props }) => , - img: ({ ...props }) => , - }}>{wikipage} - ) : ( -
    Loading wiki...
    - )} -
  • -
    -
    + + + + + + Welcome back! + Explore your metadata model with ease. If this is your first time using Data Model Viewer, make sure to check out the documentation on Git. + + + + + + + + + + + + + + } + backgroundImage={carouselItems[currentCarouselIndex]?.image} + className='h-96' + > + + + + + + {wikipage ? ( +

    , + h2: ({ ...props }) =>

    , + h3: ({ ...props }) =>

    , + h4: ({ ...props }) =>

    , + p: ({ ...props }) =>

    , + a: ({ ...props }) => , + li: ({ ...props }) =>

  • , + span: ({ ...props }) => , + img: ({ ...props }) => , + }}>{wikipage} + ) : ( +
    Loading wiki...
    + )} + + + + ) } diff --git a/Website/components/loginview/LoginView.tsx b/Website/components/loginview/LoginView.tsx new file mode 100644 index 0000000..9694574 --- /dev/null +++ b/Website/components/loginview/LoginView.tsx @@ -0,0 +1,171 @@ +import React, { FormEvent, useEffect, useState } from 'react' +import LoadingOverlay from '../shared/LoadingOverlay' +import { useLoading } from '@/hooks/useLoading' +import { useAuth } from '@/contexts/AuthContext' +import { Alert, Box, Button, Container, FormControl, IconButton, InputAdornment, InputLabel, OutlinedInput, Typography, CircularProgress } from '@mui/material' +import { Info, Visibility, VisibilityOff, Warning } from '@mui/icons-material' +import { createSession } from '@/lib/session' +import { LastSynched } from '@/stubs/Data' +import { useRouter } from 'next/navigation' + +interface LoginViewProps { + +} + +const LoginView = ({ }: LoginViewProps) => { + + const router = useRouter(); + const { setAuthenticated } = useAuth(); + const { + isAuthenticating, + isRedirecting, + startAuthentication, + startRedirection, + stopAuthentication, + resetAuthState + } = useLoading(); + + const [showPassword, setShowPassword] = useState(false); + const [version, setVersion] = useState(null); + const [showIncorrectPassword, setShowIncorrectPassword] = useState(false); + const [animateError, setAnimateError] = useState(false); + + useEffect(() => { + fetch('/api/version') + .then((res) => res.json()) + .then((data) => setVersion(data.version)) + .catch(() => setVersion('Unknown')) + }, []); + + const handleClickShowPassword = () => setShowPassword((show) => !show); + + async function handleSubmit(event: FormEvent) { + event.preventDefault(); + + startAuthentication(); + setShowIncorrectPassword(false); + setAnimateError(false); + + const formData = new FormData(event.currentTarget); + const password = formData.get("password") + + try { + const response = await fetch("/api/auth/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ password }), + }); + + if (response.ok) { + await createSession(password?.valueOf() as string); + setAuthenticated(true); // Update auth context immediately + startRedirection(); + router.push("/"); + } else { + setShowIncorrectPassword(true); + setTimeout(() => setAnimateError(true), 10); + stopAuthentication(); + } + } catch (error) { + console.error('Login error:', error); + setShowIncorrectPassword(true); + setTimeout(() => setAnimateError(true), 10); + resetAuthState(); + } + } + + return ( + + + + + Hi, Welcome back + More effective with transparency + + + + Sign in to your organization + } severity="info" className='w-full rounded-lg'> + Last synchronization: {LastSynched ? LastSynched.toLocaleString('en-DK', { + timeZone: 'Europe/Copenhagen', + timeZoneName: 'short', + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }) : '...'} + + {showIncorrectPassword && ( + } + severity="warning" + className={`w-full rounded-lg mt-4 transition-all duration-300 ease-out ${ + animateError + ? 'translate-x-0 opacity-100' + : 'translate-x-4 opacity-0' + }`} + > + The password is incorrect. + + )} +
    + + Password + + + {showPassword ? : } + + + } + label="Password" + /> + + +
    + + + Version: {version ?? '...'} + +
    +
    +
    + ) +} + +export default LoginView diff --git a/Website/components/processesview/ProcessesView.tsx b/Website/components/processesview/ProcessesView.tsx new file mode 100644 index 0000000..ecf100f --- /dev/null +++ b/Website/components/processesview/ProcessesView.tsx @@ -0,0 +1,505 @@ +'use client' + +import React, { useEffect, useState, useMemo, useCallback } from 'react' +import { useSidebar } from '@/contexts/SidebarContext' +import { useDatamodelData } from '@/contexts/DatamodelDataContext' +import { Box, Typography, Paper, TextField, InputAdornment, Grid, List, ListItem, ListItemButton, ListItemText, Chip, IconButton, Table, TableHead, TableBody, TableRow, TableCell, useTheme, Alert } from '@mui/material' +import { AccountTreeRounded, CloseRounded, ExtensionRounded, SearchRounded } from '@mui/icons-material' +import { AttributeType, EntityType, ComponentType, OperationType } from '@/lib/Types' +import LoadingOverlay from '@/components/shared/LoadingOverlay' +import NotchedBox from '../shared/elements/NotchedBox' +import { ResponsivePie } from '@nivo/pie' + +interface IProcessesViewProps { } + +interface AttributeSearchResult { + attribute: AttributeType + entity: EntityType + group: string +} + +export const ProcessesView = ({ }: IProcessesViewProps) => { + const { setElement, close } = useSidebar() + const { groups } = useDatamodelData() + const theme = useTheme() + const [searchTerm, setSearchTerm] = useState('') + const [isSearching, setIsSearching] = useState(false) + const [selectedAttribute, setSelectedAttribute] = useState(null) + + useEffect(() => { + setElement(null); + close(); + }, [setElement, close]) + + const chartData = useMemo(() => { + if (!selectedAttribute) return []; + + const data = Object.values( + selectedAttribute.attribute.AttributeUsages.reduce((acc, au) => { + const componentTypeName = ComponentType[au.ComponentType]; + if (acc[componentTypeName]) { + acc[componentTypeName].value += 1; + } else { + acc[componentTypeName] = { + id: componentTypeName, + label: componentTypeName, + value: 1 + }; + } + return acc; + }, {} as Record) + ); + + return data; + }, [selectedAttribute]) + + // Search through all attributes across all entities + const searchResults = useMemo(() => { + if (!searchTerm.trim() || searchTerm.length < 2) { + return [] + } + + const results: AttributeSearchResult[] = [] + const query = searchTerm.toLowerCase() + + groups.forEach(group => { + group.Entities.forEach(entity => { + entity.Attributes.forEach(attribute => { + if (attribute.AttributeUsages.length === 0) return; // Only search attributes with usages + const basicMatch = + attribute.DisplayName.toLowerCase().includes(query) || + attribute.SchemaName.toLowerCase().includes(query) || + (attribute.Description && attribute.Description.toLowerCase().includes(query)) + + // Check options for ChoiceAttribute and StatusAttribute + let optionsMatch = false + if (attribute.AttributeType === 'ChoiceAttribute' || attribute.AttributeType === 'StatusAttribute') { + optionsMatch = attribute.Options.some(option => + option.Name.toLowerCase().includes(query) + ) + } + + if (basicMatch || optionsMatch) { + results.push({ + attribute, + entity, + group: group.Name + }) + } + }) + }) + }) + + return results.slice(0, 50) // Limit results for performance + }, [searchTerm, groups]) + + // Simulate search delay for UX + useEffect(() => { + if (searchTerm.trim() && searchTerm.length >= 2) { + setIsSearching(true) + const timer = setTimeout(() => { + setIsSearching(false) + }, 300) + return () => clearTimeout(timer) + } else { + setIsSearching(false) + } + }, [searchTerm]) + + const handleAttributeSelect = useCallback((result: AttributeSearchResult) => { + setSelectedAttribute(result); + setSearchTerm(''); + }, []) + + const getAttributeTypeLabel = (attributeType: string) => { + switch (attributeType) { + case 'ChoiceAttribute': return 'Choice' + case 'DateTimeAttribute': return 'Date Time' + case 'LookupAttribute': return 'Lookup' + case 'StringAttribute': return 'Text' + case 'IntegerAttribute': return 'Number' + case 'DecimalAttribute': return 'Decimal' + case 'BooleanAttribute': return 'Yes/No' + case 'StatusAttribute': return 'Status' + case 'FileAttribute': return 'File' + default: return attributeType.replace('Attribute', '') + } + } + + const getProcessChip = (componentType: ComponentType) => { + switch (componentType) { + case ComponentType.Plugin: + return } />; + case ComponentType.PowerAutomateFlow: + return } />; + } + } + + return ( + <> + + + + + {/* Page Title */} + + Processes + + + {/* Search Bar */} + + setSearchTerm(e.target.value)} + slotProps={{ + input: { + startAdornment: ( + + + + ), + } + }} + sx={{ + '& .MuiOutlinedInput-root': { + backgroundColor: 'background.paper', + '& fieldset': { + borderColor: 'divider', + }, + '&:hover fieldset': { + borderColor: 'primary.main', + }, + '&.Mui-focused fieldset': { + borderColor: 'primary.main', + }, + }, + '& .MuiInputBase-input': { + fontSize: '1.1rem', + padding: '14px 16px', + }, + }} + /> + + + {/* Search Results */} + {searchTerm.trim() && searchTerm.length >= 2 && !isSearching && ( + + + Attribute Search Results ({searchResults.length}) + + + {searchResults.length > 0 ? ( + + + {searchResults.map((result, index) => ( + + handleAttributeSelect(result)} + selected={selectedAttribute?.attribute.SchemaName === result.attribute.SchemaName && + selectedAttribute?.entity.SchemaName === result.entity.SchemaName} + > + + + {result.attribute.DisplayName} + + + {result.attribute.IsCustomAttribute && ( + + )} + + } + secondary={ + + + {result.entity.DisplayName} • {result.group} + + + {result.attribute.SchemaName} + + + } + /> + + + ))} + + + ) : ( + + No attributes found matching "{searchTerm}" + + )} + + )} + + {searchTerm.trim() && searchTerm.length < 2 && ( + + Enter at least 2 characters to search attributes + + )} + + + + Currently only supports Plugin triggers and CDS Power Automate Actions + + + + {!selectedAttribute && ( + + Welcome to the processes search. Please search and select an attribute to see related processes. + + )} + + {/* GRID WITH SELECTED ATTRIBUTE */} + {selectedAttribute && ( + + + setSelectedAttribute(null)}>} + className='flex flex-col items-center justify-center h-full w-full' + > + + + Selected Attribute + + + [{selectedAttribute.group} ({selectedAttribute.entity.DisplayName})]: {selectedAttribute.attribute.DisplayName} + + + + {chartData.length > 0 ? ( + + ) : ( + + No usage data available + + )} + + + + + + + Processes + + + {selectedAttribute?.attribute.AttributeUsages.length === 0 ? ( + + No process usage data available for this attribute + + ) : ( + + + + + + Process + + + Name + + + Type + + + Usage + + + + + {selectedAttribute?.attribute.AttributeUsages.map((usage, idx) => ( + + + {getProcessChip(usage.ComponentType)} + + + {usage.Name} + + + {OperationType[usage.OperationType]} + + + {usage.Usage} + + + ))} + +
    +
    + )} +
    +
    +
    +
    )} +
    +
    +
    + + ) +} \ No newline at end of file diff --git a/Website/components/shared/AppSidebar.tsx b/Website/components/shared/AppSidebar.tsx deleted file mode 100644 index 19ae815..0000000 --- a/Website/components/shared/AppSidebar.tsx +++ /dev/null @@ -1,128 +0,0 @@ -'use client' - -import { useSidebar, useSidebarDispatch } from '@/contexts/SidebarContext' -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 {} - -export const AppSidebar = ({}: IAppSidebarProps) => { - const { element, isOpen, showElement } = useSidebar() - const dispatch = useSidebarDispatch() - const isMobile = useIsMobile() - - const toggleSidebar = () => { - dispatch({ type: 'SET_OPEN', payload: !isOpen }) - } - - const toggleElement = () => { - dispatch({ type: 'SET_SHOW_ELEMENT', payload: !showElement }) - } - - return ( - <> - {/* Toggle Button (mobile only) */} - {isMobile && ( - - )} - - {/* Overlay for mobile sidebar */} - {isMobile && isOpen && ( -
    - )} - - {/* Sidebar */} -
    - {/* Header */} -
    - {isMobile ? ( - <> - {Logo ? ( -
    - Logo - - Logo -
    - ) : ( - Logo - )} - - ) : ( - showElement ? ( -
    - {Logo ? ( -
    - Logo - - Logo -
    - ) : ( - Logo - )} -
    - ) : ( -
    - Logo - { Logo && } -
    - ) - )} -
    - - {/* Vertically centered sidebar toggle button (desktop only) */} - {!isMobile && ( - - )} - - {/* Content */} -
    - - {(isMobile || showElement) && element} -
    -
    - - ) -} diff --git a/Website/components/shared/Header.tsx b/Website/components/shared/Header.tsx new file mode 100644 index 0000000..c8449d6 --- /dev/null +++ b/Website/components/shared/Header.tsx @@ -0,0 +1,147 @@ +import { useLoading } from '@/hooks/useLoading'; +import { useAuth } from '@/contexts/AuthContext'; +import { useSettings } from '@/contexts/SettingsContext'; +import { useRouter } from 'next/navigation'; +import { AppBar, Toolbar, Box, LinearProgress, Button, Badge, Stack } from '@mui/material'; +import SettingsPane from './elements/SettingsPane'; +import { useIsMobile } from '@/hooks/use-mobile'; +import { useSidebar } from '@/contexts/SidebarContext'; + +interface HeaderProps { + +} + +const Header = ({ }: HeaderProps) => { + const { isSettingsOpen, setSettingsOpen } = useSettings(); + const { isAuthenticated, logout } = useAuth(); + const { isOpen: sidebarOpen, expand } = useSidebar(); + const isMobile = useIsMobile(); + const router = useRouter(); + + const { + isAuthenticating, + isRedirecting, + } = useLoading(); + + const handleSettingsClick = () => { + setSettingsOpen(true); + }; + + const handleSettingsClose = () => { + setSettingsOpen(false); + }; + + const handleLogout = async () => { + try { + // Call the API to clear the server-side session + await fetch('/api/auth/logout', { method: 'POST' }); + // Update the auth context immediately + logout(); + // Navigate to login page + router.push('/login'); + } catch (error) { + console.error('Logout error:', error); + // Still navigate to login even if API call fails + logout(); + router.push('/login'); + } + }; + + return ( + + + + {/* Logo section */} + + {!isAuthenticated && ( + + )} + {isMobile && !sidebarOpen && isAuthenticated && ( + + )} + + + {/* Right side - navigation buttons */} + + + {isAuthenticated && ( + <> + + + + )} + + + + {/* Loading bar at the bottom of the header */} + {(isAuthenticating || isRedirecting) && ( + + + + )} + + + {/* Settings Pane */} + + + ); +}; + +export default Header; \ No newline at end of file diff --git a/Website/components/shared/Layout.tsx b/Website/components/shared/Layout.tsx new file mode 100644 index 0000000..a7b2f75 --- /dev/null +++ b/Website/components/shared/Layout.tsx @@ -0,0 +1,62 @@ +'use client' + +import React, { ReactNode } from 'react'; +import { Box, Container } from '@mui/material'; +import Sidebar from './Sidebar'; +import Header from './Header'; +import { useSidebar } from '@/contexts/SidebarContext'; +import { useIsMobile } from '@/hooks/use-mobile'; +import { useAuth } from '@/contexts/AuthContext'; + +interface LayoutProps { + children: ReactNode; + className?: string; + showSidebarContent?: boolean; +} + +const Layout = ({ children }: LayoutProps) => { + const { isOpen: sidebarOpen, close } = useSidebar(); + const isMobile = useIsMobile(); + const { isAuthenticated } = useAuth(); + + return ( + + {isAuthenticated && ( + + + + )} + + {/* Mobile overlay */} + {isMobile && isAuthenticated && ( + + )} + + +
    + + + {children} + + + + + ); +}; + +export default Layout; diff --git a/Website/components/shared/LoadingOverlay.tsx b/Website/components/shared/LoadingOverlay.tsx new file mode 100644 index 0000000..55c7d67 --- /dev/null +++ b/Website/components/shared/LoadingOverlay.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { CircularProgress, Typography, Backdrop, Box } from '@mui/material'; + +interface LoadingOverlayProps { + open: boolean; + message?: string; +} + +const LoadingOverlay = ({ open, message = 'Loading...' }: LoadingOverlayProps) => { + return ( + + + + + {message} + + + + ); +}; + +export default LoadingOverlay; diff --git a/Website/components/shared/Sidebar.tsx b/Website/components/shared/Sidebar.tsx new file mode 100644 index 0000000..a09c7ad --- /dev/null +++ b/Website/components/shared/Sidebar.tsx @@ -0,0 +1,206 @@ +import React from 'react'; +import { IconButton, Box, Typography, alpha, Badge, Tooltip } from '@mui/material'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { useSidebar } from '@/contexts/SidebarContext'; +import { useIsMobile } from '@/hooks/use-mobile'; +import { ChevronLeftRounded, ChevronRightRounded } from '@mui/icons-material'; + +interface SidebarProps { + +} + +interface NavItem { + label: string; + href?: string; + icon: React.ReactNode; + active?: boolean; + disabled?: boolean; + external?: boolean; + caption?: string; + new?: boolean; + action?: () => void; +} + +const Sidebar = ({ }: SidebarProps) => { + const { isOpen, element, toggleExpansion, close } = useSidebar(); + const isMobile = useIsMobile(); + + const pathname = usePathname(); + + const navItems: NavItem[] = [ + { + label: 'Home', + href: '/', + icon: , + active: pathname === '/', + new: true, + }, + { + label: 'Insights', + href: '/insight', + icon: , + active: pathname === '/insight', + disabled: true + }, + { + label: 'Metadata', + href: '/metadata', + icon: , + active: pathname === '/metadata', + }, + { + label: 'Diagram', + href: '/diagram', + icon: , + active: pathname === '/diagram', + }, + { + label: 'Processes', + href: '/processes', + icon: , + active: pathname === '/processes', + new: true, + } + ]; + + const handleNavClick = () => { + if (isMobile) { + close(); + } + }; + + return ( + + + {element !== null && !isMobile && ( + + {isOpen ? : } + + )} + + {/* Mobile close button */} + {isMobile && ( + + + + + + )} + + + + + + {navItems.map((item, itemIndex) => ( + + + + { + if (item.action) { + item.action(); + } + if (!item.disabled) { + handleNavClick(); + } + }} + > + alpha(theme.palette.primary.main, 0.12) + : 'transparent', + transition: 'all 0.2s ease-in-out', + '&:hover': { + backgroundColor: item.disabled + ? 'transparent' + : item.active + ? (theme) => alpha(theme.palette.primary.main, 0.16) + : 'action.hover', + color: item.disabled ? 'text.disabled' : 'text.primary', + } + }} + > + {item.icon} + + {item.label} + + + + + + + ))} + + {isOpen && element != null && ( + + {element} + + )} + + + ) +}; + +export default Sidebar; diff --git a/Website/components/shared/SidebarNavRail.tsx b/Website/components/shared/SidebarNavRail.tsx deleted file mode 100644 index c6125a2..0000000 --- a/Website/components/shared/SidebarNavRail.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import React from "react"; -import { useRouter, usePathname } from "next/navigation"; -import { LogOut, Info, Database, PencilRuler, PlugZap, Sparkles, Home, ChartPie } from "lucide-react"; -import { Button } from "@/components/shared/ui/button"; -import { useSidebarDispatch } from "@/contexts/SidebarContext"; -import { Tooltip, TooltipContent } from "./ui/tooltip"; -import { TooltipTrigger } from "@radix-ui/react-tooltip"; - -const navItems = [ - { - label: "Home", - icon: , - href: "/", - active: true, - disabled: false, - new: true, - }, - { - label: "Insight viewer", - icon: , - href: "/insight", - active: false, - disabled: true, - new: false, - }, - { - label: "Metadata viewer", - icon: , - href: "/metadata", - active: false, - disabled: false, - new: false, - }, - { - label: "Diagram viewer", - icon: , - href: "/diagram", - active: false, - disabled: false, - new: false, - }, - { - label: "Process viewer", - icon: , - href: "/process", - active: false, - disabled: true, - new: false, - }, -]; - -export default function SidebarNavRail() { - const router = useRouter(); - const pathname = usePathname(); - - const dispatch = useSidebarDispatch(); - - return ( - - ); -} \ No newline at end of file diff --git a/Website/components/shared/TopLoadingBar.tsx b/Website/components/shared/TopLoadingBar.tsx new file mode 100644 index 0000000..3b0a3d7 --- /dev/null +++ b/Website/components/shared/TopLoadingBar.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Box, LinearProgress } from '@mui/material'; + +interface TopLoadingBarProps { + loading: boolean; +} + +const TopLoadingBar = ({ loading }: TopLoadingBarProps) => { + if (!loading) return null; + + return ( + + + + ); +}; + +export default TopLoadingBar; diff --git a/Website/components/shared/elements/Carousel.tsx b/Website/components/shared/elements/Carousel.tsx new file mode 100644 index 0000000..ff5f3bd --- /dev/null +++ b/Website/components/shared/elements/Carousel.tsx @@ -0,0 +1,119 @@ +'use client' + +import React, { useEffect, useState } from 'react'; +import { Box, Button, Typography } from '@mui/material'; + +export interface CarouselItem { + image?: string; + title: string; + text: string; + type: string; + actionlabel?: string; + action?: () => void; +} + +interface CarouselProps { + items: CarouselItem[]; + currentIndex?: number; + slideDirection?: 'left' | 'right' | null; + className?: string; +} + +const Carousel = ({ items, currentIndex = 0, slideDirection = null, className }: CarouselProps) => { + const [animationState, setAnimationState] = useState<'idle' | 'sliding'>('idle'); + const [prevIndex, setPrevIndex] = useState(currentIndex); + const [showPrevious, setShowPrevious] = useState(false); + + useEffect(() => { + if (currentIndex !== prevIndex && slideDirection) { + setAnimationState('sliding'); + setShowPrevious(true); + + const timer = setTimeout(() => { + setPrevIndex(currentIndex); + setAnimationState('idle'); + setShowPrevious(false); + }, 500); + + return () => clearTimeout(timer); + } else if (currentIndex !== prevIndex) { + setPrevIndex(currentIndex); + } + }, [currentIndex, prevIndex, slideDirection]); + + const currentItem = items[currentIndex] || { title: '', text: '' }; + const previousItem = items[prevIndex] || { title: '', text: '' }; + + return ( + + {/* Gradient overlay for text readability */} + + + {/* Content container */} + + {/* Previous item - animating out */} + {showPrevious && animationState === 'sliding' && ( + + + {previousItem.type} + + + {previousItem.title} + + + {previousItem.text} + + + )} + + {/* Current item - animating in or static */} + + + {currentItem.type} + + + {currentItem.title} + + + {currentItem.text} + + {currentItem.actionlabel && currentItem.action && ( + + )} + + + + {/* Pagination dots - stationary, outside animated content */} + + {items.map((_, index) => ( + + ))} + + + ); +}; + +export default Carousel; diff --git a/Website/components/shared/elements/NotchedBox.tsx b/Website/components/shared/elements/NotchedBox.tsx new file mode 100644 index 0000000..e68d43f --- /dev/null +++ b/Website/components/shared/elements/NotchedBox.tsx @@ -0,0 +1,227 @@ +'use client' + +import React from 'react'; +import { Box, BoxProps } from '@mui/material'; + +interface NotchedBoxProps extends Omit { + notchContent?: React.ReactNode; + className?: string; + children?: React.ReactNode; + backgroundImage?: string; + variant?: 'default' | 'outlined'; +} + +const NotchedBox = ({ + notchContent, + className, + children, + backgroundImage, + variant = 'default' +}: NotchedBoxProps) => { + + const contentRef = React.useRef(null); + const [notchWidth, setNotchWidth] = React.useState(0); // as a fraction of width (0..1) + const containerRef = React.useRef(null); + const [prevBackgroundImage, setPrevBackgroundImage] = React.useState(backgroundImage); + const [isTransitioning, setIsTransitioning] = React.useState(false); + + // Generate unique ID for this component instance + const uniqueId = React.useMemo(() => `notch-${Math.random().toString(36).substr(2, 9)}`, []); + + React.useEffect(() => { + if (backgroundImage !== prevBackgroundImage) { + setIsTransitioning(true); + setPrevBackgroundImage(backgroundImage); + + const timer = setTimeout(() => { + setIsTransitioning(false); + }, 500); // Match transition duration + + return () => clearTimeout(timer); + } + }, [backgroundImage, prevBackgroundImage]); + + React.useEffect(() => { + const updateNotchWidth = () => { + if (contentRef.current && containerRef.current) { + const contentWidthPx = contentRef.current.clientWidth + 16; // 8px horizontal padding both sides + const containerWidthPx = containerRef.current.clientWidth || 1; + setNotchWidth(Math.min(1, contentWidthPx / containerWidthPx)); + } + }; + + updateNotchWidth(); + window.addEventListener('resize', updateNotchWidth); + return () => window.removeEventListener('resize', updateNotchWidth); + }, [notchContent]); + + // Compute normalized radii (objectBoundingBox uses 0..1 units) + const cw = containerRef.current?.clientWidth || 1; + const ch = containerRef.current?.clientHeight || 1; + + // 16px corner radius in both axes, normalized + const rx = Math.min(16 / cw, 0.49); + const ry = Math.min(16 / ch, 0.49); + + // Notch size: width is based on content; height fixed to 40px (normalized) + const notchH = Math.min(48 / ch, 1); // normalize 40px + const notchW = Math.min(notchWidth, 1); + + // Inner notch radii cannot exceed half the notch dimensions + const irx = Math.min(rx, Math.max(0, notchW / 2 - 0.001)); + const iry = Math.min(ry, Math.max(0, notchH / 2 - 0.001)); + + // X where the notch starts from the right + const startX = 1 - notchW; + + // Helpful guard so top edge before the notch never goes negative + const preNotchTopX = Math.max(startX - irx, rx); + + // Build the notched path + const d = [ + `M ${rx},0`, + `H ${preNotchTopX}`, + // Inner top-left corner of notch (concave) + `A ${irx} ${iry} 0 0 1 ${startX} ${iry}`, + `V ${Math.max(notchH - iry, iry)}`, + // Inner bottom-left corner of notch (concave) + `A ${irx} ${iry} 0 0 0 ${startX + irx} ${notchH}`, + `H ${1 - rx}`, + // Inner bottom-right corner of notch (concave back to right wall) + `A ${irx} ${iry} 0 0 1 1 ${notchH + iry}`, + `V ${1 - ry}`, + // Outer bottom-right (convex) + `A ${rx} ${ry} 0 0 1 ${1 - rx} 1`, + `H ${rx}`, + // Outer bottom-left (convex) + `A ${rx} ${ry} 0 0 1 0 ${1 - ry}`, + `V ${ry}`, + // Outer top-left (convex) + `A ${rx} ${ry} 0 0 1 ${rx} 0`, + `Z` + ].join(' '); + + // Build inset stroke path (slightly smaller for inward stroke) + const strokeInset = 0.003; // Inset amount + const strokeRx = Math.max(rx - strokeInset, 0.001); + const strokeRy = Math.max(ry - strokeInset, 0.001); + const strokeNotchH = Math.max(notchH - strokeInset, strokeInset); + const strokeNotchW = Math.max(notchW - strokeInset * 2, strokeInset); + const strokeStartX = 1 - strokeNotchW; + const strokeIrx = Math.min(strokeRx, Math.max(0, strokeNotchW / 2 - 0.001)); + const strokeIry = Math.min(strokeRy, Math.max(0, strokeNotchH / 2 - 0.001)); + const strokePreNotchTopX = Math.max(strokeStartX - strokeIrx, strokeRx); + + const strokePath = [ + `M ${strokeRx},${strokeInset}`, + `H ${strokePreNotchTopX}`, + // Inner top-left corner of notch (concave) + `A ${strokeIrx} ${strokeIry} 0 0 1 ${strokeStartX} ${strokeIry}`, + `V ${Math.max(strokeNotchH - strokeIry, strokeIry)}`, + // Inner bottom-left corner of notch (concave) + `A ${strokeIrx} ${strokeIry} 0 0 0 ${strokeStartX + strokeIrx} ${strokeNotchH + strokeInset}`, + `H ${1 - strokeRx}`, + // Inner bottom-right corner of notch (concave back to right wall) + `A ${strokeIrx} ${strokeIry} 0 0 1 ${1 - strokeInset} ${strokeNotchH + strokeIry + strokeInset}`, + `V ${1 - strokeRy}`, + // Outer bottom-right (convex) + `A ${strokeRx} ${strokeRy} 0 0 1 ${1 - strokeRx} ${1 - strokeInset}`, + `H ${strokeRx}`, + // Outer bottom-left (convex) + `A ${strokeRx} ${strokeRy} 0 0 1 ${strokeInset} ${1 - strokeRy}`, + `V ${strokeRy + strokeInset}`, + // Outer top-left (convex) + `A ${strokeRx} ${strokeRy} 0 0 1 ${strokeRx} ${strokeInset}`, + `Z` + ].join(' '); + + return ( + + {/* SVG-based NotchedBox */} + + + + + + + + + {/* Main shape */} + + + {/* Separate stroke for outlined variant */} + {variant === 'outlined' && ( + + )} + + + {/* Background image for default variant */} + {variant === 'default' && backgroundImage && ( + <> + {/* Previous background for crossfade effect */} + {isTransitioning && prevBackgroundImage && prevBackgroundImage !== backgroundImage && ( + + )} + + {/* Current background */} + setIsTransitioning(false)} + /> + + )} + + + {/* Hidden content ref to measure width */} + + {notchContent} + + + {/* Content container - clipped to shape */} + + {children} + + + ); +}; + +export default NotchedBox; diff --git a/Website/components/shared/elements/SettingsPane.tsx b/Website/components/shared/elements/SettingsPane.tsx new file mode 100644 index 0000000..0bba918 --- /dev/null +++ b/Website/components/shared/elements/SettingsPane.tsx @@ -0,0 +1,83 @@ +'use client' + +import React from 'react'; +import { + Drawer, + Box, + Typography, + IconButton, + Switch, + Paper +} from '@mui/material'; +import { Close } from '@mui/icons-material'; +import { useSettings } from '@/contexts/SettingsContext'; + +interface SettingsPaneProps { + open: boolean; + onClose: () => void; +} + +const SettingsPane = ({ open, onClose }: SettingsPaneProps) => { + const { mode, toggleColorMode } = useSettings(); + + const handleThemeToggle = () => { + toggleColorMode(); + }; + + return ( + + + {/* Header */} + + + Settings + + + + + + + {/* Content */} + + + + + {mode === 'dark' ? ( + + + + + ) : ( + + + + + + )} + Mode + + + + + + + + ); +}; + +export default SettingsPane; diff --git a/Website/components/shared/elements/TabPanel.tsx b/Website/components/shared/elements/TabPanel.tsx new file mode 100644 index 0000000..d9c4db3 --- /dev/null +++ b/Website/components/shared/elements/TabPanel.tsx @@ -0,0 +1,28 @@ +import { Box } from "@mui/material"; + + +interface TabPanelProps { + children?: React.ReactNode; + index: number; + value: number; + className?: string; +} + +const CustomTabPanel = (props: TabPanelProps) => { + const { children, value, index, className, ...other } = props; + + return ( + + ); +} + +export default CustomTabPanel; \ No newline at end of file diff --git a/Website/components/shared/ui/button.tsx b/Website/components/shared/ui/button.tsx deleted file mode 100644 index 65d4fcd..0000000 --- a/Website/components/shared/ui/button.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", - { - variants: { - variant: { - default: - "bg-primary text-primary-foreground shadow hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", - outline: - "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8", - icon: "h-9 w-9", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) - -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean -} - -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" - return ( - - ) - } -) -Button.displayName = "Button" - -export { Button, buttonVariants } diff --git a/Website/components/shared/ui/card.tsx b/Website/components/shared/ui/card.tsx deleted file mode 100644 index e855d73..0000000 --- a/Website/components/shared/ui/card.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)) -Card.displayName = "Card" - -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)) -CardHeader.displayName = "CardHeader" - -const CardTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

    -)) -CardTitle.displayName = "CardTitle" - -const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

    -)) -CardDescription.displayName = "CardDescription" - -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

    -)) -CardContent.displayName = "CardContent" - -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)) -CardFooter.displayName = "CardFooter" - -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } \ No newline at end of file diff --git a/Website/components/shared/ui/checkbox.tsx b/Website/components/shared/ui/checkbox.tsx deleted file mode 100644 index df61a13..0000000 --- a/Website/components/shared/ui/checkbox.tsx +++ /dev/null @@ -1,30 +0,0 @@ -"use client" - -import * as React from "react" -import * as CheckboxPrimitive from "@radix-ui/react-checkbox" -import { Check } from "lucide-react" - -import { cn } from "@/lib/utils" - -const Checkbox = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - - -)) -Checkbox.displayName = CheckboxPrimitive.Root.displayName - -export { Checkbox } diff --git a/Website/components/shared/ui/collapsible.tsx b/Website/components/shared/ui/collapsible.tsx deleted file mode 100644 index 9fa4894..0000000 --- a/Website/components/shared/ui/collapsible.tsx +++ /dev/null @@ -1,11 +0,0 @@ -"use client" - -import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" - -const Collapsible = CollapsiblePrimitive.Root - -const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger - -const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent - -export { Collapsible, CollapsibleTrigger, CollapsibleContent } diff --git a/Website/components/shared/ui/hybridtooltop.tsx b/Website/components/shared/ui/hybridtooltop.tsx deleted file mode 100644 index a50bef8..0000000 --- a/Website/components/shared/ui/hybridtooltop.tsx +++ /dev/null @@ -1,38 +0,0 @@ -'use client'; - -import { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react'; -import { Tooltip, TooltipTrigger, TooltipContent } from './tooltip'; -import { Popover, PopoverTrigger, PopoverContent } from './popover'; -import { TooltipContentProps, TooltipProps, TooltipTriggerProps } from '@radix-ui/react-tooltip'; -import { PopoverContentProps, PopoverProps, PopoverTriggerProps } from '@radix-ui/react-popover'; - -const TouchContext = createContext(undefined); -export const useTouch = () => useContext(TouchContext); - -export const TouchProvider = (props: PropsWithChildren) => { - const [isTouch, setTouch] = useState(); - - useEffect(() => { - setTouch(window.matchMedia('(pointer: coarse)').matches); - }, []); - - return ; -}; - -export const HybridTooltip = (props: TooltipProps & PopoverProps) => { - const isTouch = useTouch(); - - return isTouch ? : ; -}; - -export const HybridTooltipTrigger = (props: TooltipTriggerProps & PopoverTriggerProps) => { - const isTouch = useTouch(); - - return isTouch ? : ; -}; - -export const HybridTooltipContent = (props: TooltipContentProps & PopoverContentProps) => { - const isTouch = useTouch(); - - return isTouch ? : ; -}; \ No newline at end of file diff --git a/Website/components/shared/ui/input.tsx b/Website/components/shared/ui/input.tsx deleted file mode 100644 index aba38dc..0000000 --- a/Website/components/shared/ui/input.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -export type InputProps = React.InputHTMLAttributes; - -const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { - return ( - - ) - } -) -Input.displayName = "Input" - -export { Input } diff --git a/Website/components/shared/ui/label.tsx b/Website/components/shared/ui/label.tsx deleted file mode 100644 index 5341821..0000000 --- a/Website/components/shared/ui/label.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client" - -import * as React from "react" -import * as LabelPrimitive from "@radix-ui/react-label" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const labelVariants = cva( - "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" -) - -const Label = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps ->(({ className, ...props }, ref) => ( - -)) -Label.displayName = LabelPrimitive.Root.displayName - -export { Label } diff --git a/Website/components/shared/ui/loading.tsx b/Website/components/shared/ui/loading.tsx deleted file mode 100644 index b0fa6d1..0000000 --- a/Website/components/shared/ui/loading.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { cn } from "@/lib/utils" - -export function Loading({ className }: { className?: string }) { - return ( -
    -
    -
    - {[...Array(3)].map((_, i) => ( -
    - ))} -
    -

    - Loading your data model... -

    -
    -
    - ) -} \ No newline at end of file diff --git a/Website/components/shared/ui/popover.tsx b/Website/components/shared/ui/popover.tsx deleted file mode 100644 index 29c7bd2..0000000 --- a/Website/components/shared/ui/popover.tsx +++ /dev/null @@ -1,33 +0,0 @@ -"use client" - -import * as React from "react" -import * as PopoverPrimitive from "@radix-ui/react-popover" - -import { cn } from "@/lib/utils" - -const Popover = PopoverPrimitive.Root - -const PopoverTrigger = PopoverPrimitive.Trigger - -const PopoverAnchor = PopoverPrimitive.Anchor - -const PopoverContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( - - - -)) -PopoverContent.displayName = PopoverPrimitive.Content.displayName - -export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } diff --git a/Website/components/shared/ui/select.tsx b/Website/components/shared/ui/select.tsx deleted file mode 100644 index e626e85..0000000 --- a/Website/components/shared/ui/select.tsx +++ /dev/null @@ -1,121 +0,0 @@ -"use client" - -import * as React from "react" -import * as SelectPrimitive from "@radix-ui/react-select" -import { Check, ChevronDown } from "lucide-react" - -import { cn } from "@/lib/utils" - -const Select = SelectPrimitive.Root - -const SelectGroup = SelectPrimitive.Group - -const SelectValue = SelectPrimitive.Value - -const SelectTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - {children} - - - - -)) -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName - -const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, position = "popper", ...props }, ref) => ( - - - - {children} - - - -)) -SelectContent.displayName = SelectPrimitive.Content.displayName - -const SelectLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SelectLabel.displayName = SelectPrimitive.Label.displayName - -const SelectItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - - {children} - -)) -SelectItem.displayName = SelectPrimitive.Item.displayName - -const SelectSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SelectSeparator.displayName = SelectPrimitive.Separator.displayName - -export { - Select, - SelectGroup, - SelectValue, - SelectTrigger, - SelectContent, - SelectLabel, - SelectItem, - SelectSeparator, -} \ No newline at end of file diff --git a/Website/components/shared/ui/separator.tsx b/Website/components/shared/ui/separator.tsx deleted file mode 100644 index 12d81c4..0000000 --- a/Website/components/shared/ui/separator.tsx +++ /dev/null @@ -1,31 +0,0 @@ -"use client" - -import * as React from "react" -import * as SeparatorPrimitive from "@radix-ui/react-separator" - -import { cn } from "@/lib/utils" - -const Separator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->( - ( - { className, orientation = "horizontal", decorative = true, ...props }, - ref - ) => ( - - ) -) -Separator.displayName = SeparatorPrimitive.Root.displayName - -export { Separator } diff --git a/Website/components/shared/ui/sheet.tsx b/Website/components/shared/ui/sheet.tsx deleted file mode 100644 index 272cb72..0000000 --- a/Website/components/shared/ui/sheet.tsx +++ /dev/null @@ -1,140 +0,0 @@ -"use client" - -import * as React from "react" -import * as SheetPrimitive from "@radix-ui/react-dialog" -import { cva, type VariantProps } from "class-variance-authority" -import { X } from "lucide-react" - -import { cn } from "@/lib/utils" - -const Sheet = SheetPrimitive.Root - -const SheetTrigger = SheetPrimitive.Trigger - -const SheetClose = SheetPrimitive.Close - -const SheetPortal = SheetPrimitive.Portal - -const SheetOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SheetOverlay.displayName = SheetPrimitive.Overlay.displayName - -const sheetVariants = cva( - "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out", - { - variants: { - side: { - top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", - bottom: - "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", - left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", - right: - "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", - }, - }, - defaultVariants: { - side: "right", - }, - } -) - -interface SheetContentProps - extends React.ComponentPropsWithoutRef, - VariantProps {} - -const SheetContent = React.forwardRef< - React.ElementRef, - SheetContentProps ->(({ side = "right", className, children, ...props }, ref) => ( - - - - - - Close - - {children} - - -)) -SheetContent.displayName = SheetPrimitive.Content.displayName - -const SheetHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
    -) -SheetHeader.displayName = "SheetHeader" - -const SheetFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
    -) -SheetFooter.displayName = "SheetFooter" - -const SheetTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SheetTitle.displayName = SheetPrimitive.Title.displayName - -const SheetDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SheetDescription.displayName = SheetPrimitive.Description.displayName - -export { - Sheet, - SheetPortal, - SheetOverlay, - SheetTrigger, - SheetClose, - SheetContent, - SheetHeader, - SheetFooter, - SheetTitle, - SheetDescription, -} diff --git a/Website/components/shared/ui/skeleton.tsx b/Website/components/shared/ui/skeleton.tsx deleted file mode 100644 index d7e45f7..0000000 --- a/Website/components/shared/ui/skeleton.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { cn } from "@/lib/utils" - -function Skeleton({ - className, - ...props -}: React.HTMLAttributes) { - return ( -
    - ) -} - -export { Skeleton } diff --git a/Website/components/shared/ui/table.tsx b/Website/components/shared/ui/table.tsx deleted file mode 100644 index c0df655..0000000 --- a/Website/components/shared/ui/table.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Table = React.forwardRef< - HTMLTableElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    - - -)) -Table.displayName = "Table" - -const TableHeader = React.forwardRef< - HTMLTableSectionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)) -TableHeader.displayName = "TableHeader" - -const TableBody = React.forwardRef< - HTMLTableSectionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)) -TableBody.displayName = "TableBody" - -const TableFooter = React.forwardRef< - HTMLTableSectionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - tr]:last:border-b-0", - className - )} - {...props} - /> -)) -TableFooter.displayName = "TableFooter" - -const TableRow = React.forwardRef< - HTMLTableRowElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)) -TableRow.displayName = "TableRow" - -const TableHead = React.forwardRef< - HTMLTableCellElement, - React.ThHTMLAttributes ->(({ className, ...props }, ref) => ( -
    [role=checkbox]]:translate-y-[2px]", - className - )} - {...props} - /> -)) -TableHead.displayName = "TableHead" - -const TableCell = React.forwardRef< - HTMLTableCellElement, - React.TdHTMLAttributes ->(({ className, ...props }, ref) => ( - [role=checkbox]]:translate-y-[2px]", - className - )} - {...props} - /> -)) -TableCell.displayName = "TableCell" - -const TableCaption = React.forwardRef< - HTMLTableCaptionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)) -TableCaption.displayName = "TableCaption" - -export { - Table, - TableHeader, - TableBody, - TableFooter, - TableHead, - TableRow, - TableCell, - TableCaption, -} diff --git a/Website/components/shared/ui/tabs.tsx b/Website/components/shared/ui/tabs.tsx deleted file mode 100644 index f022177..0000000 --- a/Website/components/shared/ui/tabs.tsx +++ /dev/null @@ -1,57 +0,0 @@ -"use client" - -import * as React from "react" -import * as TabsPrimitive from "@radix-ui/react-tabs" -import { cva, type VariantProps } from "class-variance-authority" -import { cn } from "@/lib/utils" - -const tabsListVariants = cva("inline-flex items-center border-b w-full") -const tabsTriggerVariants = cva( - "inline-flex items-center justify-center whitespace-nowrap px-4 py-2 text-sm font-medium transition-all border-b-2 border-transparent", - { - variants: { - variant: { - default: "text-muted-foreground hover:text-foreground hover:border-gray-300", - }, - }, - defaultVariants: { - variant: "default", - } - } -) - -const Tabs = TabsPrimitive.Root - -const TabsList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -TabsList.displayName = TabsPrimitive.List.displayName - -const TabsTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & VariantProps ->(({ className, variant, ...props }, ref) => ( - -)) -TabsTrigger.displayName = TabsPrimitive.Trigger.displayName - -const TabsContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -TabsContent.displayName = TabsPrimitive.Content.displayName - -export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/Website/components/shared/ui/tooltip.tsx b/Website/components/shared/ui/tooltip.tsx deleted file mode 100644 index a66b3f2..0000000 --- a/Website/components/shared/ui/tooltip.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client" - -import * as React from "react" -import * as TooltipPrimitive from "@radix-ui/react-tooltip" - -import { cn } from "@/lib/utils" - -const TooltipProvider = TooltipPrimitive.Provider - -const Tooltip = TooltipPrimitive.Root - -const TooltipTrigger = TooltipPrimitive.Trigger - -const TooltipContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - - - -)) -TooltipContent.displayName = TooltipPrimitive.Content.displayName - -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } diff --git a/Website/contexts/AuthContext.tsx b/Website/contexts/AuthContext.tsx new file mode 100644 index 0000000..681fcd8 --- /dev/null +++ b/Website/contexts/AuthContext.tsx @@ -0,0 +1,87 @@ +"use client" + +import { createContext, ReactNode, useContext, useState, useEffect, useCallback } from "react"; + +export interface AuthState { + isAuthenticated: boolean | null; // null = loading + isLoading: boolean; +} + +const initialState: AuthState = { + isAuthenticated: null, + isLoading: true +} + +interface AuthContextType extends AuthState { + checkAuth: () => Promise; + setAuthenticated: (authenticated: boolean) => void; + logout: () => void; +} + +const AuthContext = createContext(undefined); + +interface AuthProviderProps { + children: ReactNode; +} + +export const AuthProvider = ({ children }: AuthProviderProps) => { + const [state, setState] = useState(initialState); + + const checkAuth = useCallback(async () => { + try { + setState(prev => ({ ...prev, isLoading: true })); + const response = await fetch('/api/auth/session'); + const data = await response.json(); + setState({ + isAuthenticated: data.isAuthenticated, + isLoading: false + }); + } catch (error) { + console.error('Auth check failed:', error); + setState({ + isAuthenticated: false, + isLoading: false + }); + } + }, []); + + const setAuthenticated = useCallback((authenticated: boolean) => { + setState(prev => ({ + ...prev, + isAuthenticated: authenticated, + isLoading: false + })); + }, []); + + const logout = useCallback(() => { + setState({ + isAuthenticated: false, + isLoading: false + }); + }, []); + + useEffect(() => { + checkAuth(); + }, [checkAuth]); + + const value = { + ...state, + checkAuth, + setAuthenticated, + logout + }; + + return ( + + {children} + + ); +}; + +export const useAuth = () => { + const context = useContext(AuthContext); + if (context === undefined) { + throw new Error('useAuth must be used within an AuthProvider'); + } + return context; +}; diff --git a/Website/contexts/DatamodelViewContext.tsx b/Website/contexts/DatamodelViewContext.tsx index 597ed2e..4f7fe30 100644 --- a/Website/contexts/DatamodelViewContext.tsx +++ b/Website/contexts/DatamodelViewContext.tsx @@ -9,6 +9,7 @@ export interface DatamodelViewState { currentSection: string | null; scrollToSection: (sectionId: string) => void; loading: boolean; + loadingSection: string | null; } const initialState: DatamodelViewState = { @@ -16,6 +17,7 @@ const initialState: DatamodelViewState = { currentSection: null, scrollToSection: () => { throw new Error("scrollToSection not initialized yet!"); }, loading: true, + loadingSection: null, } type DatamodelViewAction = @@ -23,6 +25,7 @@ type DatamodelViewAction = | { type: 'SET_CURRENT_SECTION', payload: string | null } | { type: 'SET_SCROLL_TO_SECTION', payload: (sectionId: string) => void } | { type: 'SET_LOADING', payload: boolean } + | { type: 'SET_LOADING_SECTION', payload: string | null } const datamodelViewReducer = (state: DatamodelViewState, action: DatamodelViewAction): DatamodelViewState => { @@ -35,6 +38,8 @@ const datamodelViewReducer = (state: DatamodelViewState, action: DatamodelViewAc return { ...state, scrollToSection: action.payload } case 'SET_LOADING': return { ...state, loading: action.payload } + case 'SET_LOADING_SECTION': + return { ...state, loadingSection: action.payload } default: return state; } diff --git a/Website/contexts/LoadingContext.tsx b/Website/contexts/LoadingContext.tsx new file mode 100644 index 0000000..e1b6abc --- /dev/null +++ b/Website/contexts/LoadingContext.tsx @@ -0,0 +1,56 @@ +import React, { createContext, useContext, useState, ReactNode } from 'react'; + +interface LoadingContextType { + isLoading: boolean; + loadingMessage: string; + setLoading: (loading: boolean, message?: string) => void; + startLoading: (message?: string) => void; + stopLoading: () => void; +} + +const LoadingContext = createContext(undefined); + +export const useLoading = () => { + const context = useContext(LoadingContext); + if (context === undefined) { + throw new Error('useLoading must be used within a LoadingProvider'); + } + return context; +}; + +interface LoadingProviderProps { + children: ReactNode; +} + +export const LoadingProvider: React.FC = ({ children }) => { + const [isLoading, setIsLoading] = useState(false); + const [loadingMessage, setLoadingMessage] = useState('Loading...'); + + const setLoading = (loading: boolean, message: string = 'Loading...') => { + setIsLoading(loading); + setLoadingMessage(message); + }; + + const startLoading = (message: string = 'Loading...') => { + setIsLoading(true); + setLoadingMessage(message); + }; + + const stopLoading = () => { + setIsLoading(false); + }; + + return ( + + {children} + + ); +}; diff --git a/Website/contexts/SettingsContext.tsx b/Website/contexts/SettingsContext.tsx new file mode 100644 index 0000000..507bcdc --- /dev/null +++ b/Website/contexts/SettingsContext.tsx @@ -0,0 +1,77 @@ +'use client'; +import React, { createContext, ReactNode, useContext, useMemo, useState, useEffect } from "react"; +import { ThemeProvider } from "@mui/material/styles"; +import { PaletteMode, CssBaseline } from "@mui/material"; +import { createAppTheme } from "../theme"; + +interface SettingsContextType { + mode: PaletteMode; + toggleColorMode: () => void; + isSettingsOpen: boolean; + setSettingsOpen: (open: boolean) => void; +} + +export const SettingsContext = createContext(undefined); + +// Custom hook to use the settings context +export const useSettings = () => { + const context = useContext(SettingsContext); + if (context === undefined) { + throw new Error('useSettings must be used within a SettingsProvider'); + } + return context; +}; + +interface SettingsProviderProps { + children: ReactNode; +} + +export const SettingsProvider = ({ children }: SettingsProviderProps) => { + const [mode, setMode] = useState('light'); + const [isHydrated, setIsHydrated] = useState(false); + const [isSettingsOpen, setSettingsOpen] = useState(false); + + // Load theme preference from localStorage on mount + useEffect(() => { + const savedMode = localStorage.getItem('themeMode') as PaletteMode; + if (savedMode && (savedMode === 'light' || savedMode === 'dark')) { + setMode(savedMode); + } + setIsHydrated(true); + }, []); + + // Save theme preference to localStorage when it changes + useEffect(() => { + if (isHydrated) { + localStorage.setItem('themeMode', mode); + } + }, [mode, isHydrated]); + + const colorMode = useMemo( + () => ({ + mode, + toggleColorMode: () => { + setMode((prevMode: PaletteMode) => + prevMode === 'light' ? 'dark' : 'light', + ); + }, + isSettingsOpen, + setSettingsOpen, + }), [mode, isSettingsOpen]); + + const theme = useMemo(() => createAppTheme(mode), [mode]); + + // Prevent flash of wrong theme during hydration + if (!isHydrated) { + return null; + } + + return ( + + + + {children} + + + ); +}; \ No newline at end of file diff --git a/Website/contexts/SidebarContext.tsx b/Website/contexts/SidebarContext.tsx index 04d77c5..16599cd 100644 --- a/Website/contexts/SidebarContext.tsx +++ b/Website/contexts/SidebarContext.tsx @@ -1,6 +1,6 @@ "use client" -import { createContext, ReactNode, useContext, useEffect, useReducer } from "react"; +import { createContext, ReactNode, useContext, useReducer, useMemo, useCallback } from "react"; export interface SidebarState { element: React.ReactNode; @@ -18,7 +18,8 @@ type SidebarAction = | { type: 'SET_ELEMENT', payload: React.ReactNode } | { type: 'SET_OPEN', payload: boolean } | { type: 'SET_SHOW_ELEMENT', payload: boolean } - + | { type: 'TOGGLE_OPEN' } + | { type: 'CLEAR_ELEMENT' } const sidebarReducer = (state: SidebarState, action: SidebarAction): SidebarState => { switch (action.type) { @@ -28,26 +29,68 @@ const sidebarReducer = (state: SidebarState, action: SidebarAction): SidebarStat return { ...state, isOpen: action.payload } case 'SET_SHOW_ELEMENT': return { ...state, showElement: action.payload } + case 'TOGGLE_OPEN': + return { ...state, isOpen: !state.isOpen } + case 'CLEAR_ELEMENT': + return { ...state, element: null } default: return state; } } -const SidebarContext = createContext(initialState); -const SidebarDispatcher = createContext>(() => { - throw new Error("SidebarDispatcher must be used within a SidebarProvider"); -}); +// Enhanced interface with convenience methods +export interface SidebarContextValue extends SidebarState { + toggleExpansion: () => void; + expand: () => void; + close: () => void; + setElement: (element: React.ReactNode | null) => void; + clearElement: () => void; + dispatch: React.Dispatch; +} + +const SidebarContext = createContext(null); + export const SidebarProvider = ({ children }: { children: ReactNode }) => { const [sidebarState, dispatch] = useReducer(sidebarReducer, initialState); + // Memoized convenience methods using useCallback + const toggleExpansion = useCallback(() => dispatch({ type: 'TOGGLE_OPEN' }), []); + const expand = useCallback(() => dispatch({ type: 'SET_OPEN', payload: true }), []); + const close = useCallback(() => dispatch({ type: 'SET_OPEN', payload: false }), []); + const setElement = useCallback((element: React.ReactNode | null) => dispatch({ type: 'SET_ELEMENT', payload: element }), []); + const clearElement = useCallback(() => dispatch({ type: 'CLEAR_ELEMENT' }), []); + + const contextValue = useMemo(() => ({ + ...sidebarState, + toggleExpansion, + expand, + close, + setElement, + clearElement, + dispatch + }), [sidebarState, toggleExpansion, expand, close, setElement, clearElement]); + return ( - - - {children} - + + {children} ) } -export const useSidebar = () => useContext(SidebarContext); -export const useSidebarDispatch = () => useContext(SidebarDispatcher); \ No newline at end of file +// Single hook that provides everything +export const useSidebar = () => { + const context = useContext(SidebarContext); + if (!context) { + throw new Error("useSidebar must be used within a SidebarProvider"); + } + return context; +}; + +// Backward compatibility - deprecated, use useSidebar instead +export const useSidebarDispatch = () => { + const context = useContext(SidebarContext); + if (!context) { + throw new Error("useSidebarDispatch must be used within a SidebarProvider"); + } + return context.dispatch; +}; \ No newline at end of file diff --git a/Website/hooks/use-mobile.tsx b/Website/hooks/use-mobile.tsx index 2b0fe1d..7dbc780 100644 --- a/Website/hooks/use-mobile.tsx +++ b/Website/hooks/use-mobile.tsx @@ -1,6 +1,6 @@ import * as React from "react" -const MOBILE_BREAKPOINT = 768 +const MOBILE_BREAKPOINT = 900 export function useIsMobile() { const [isMobile, setIsMobile] = React.useState(undefined) diff --git a/Website/hooks/useDiagram.ts b/Website/hooks/useDiagram.ts index c6cb581..5ec1ca5 100644 --- a/Website/hooks/useDiagram.ts +++ b/Website/hooks/useDiagram.ts @@ -506,7 +506,7 @@ export const useDiagram = (): DiagramState & DiagramActions => { text: 'Sample Text', fill: 'black', fontSize: 14, - fontFamily: 'Inter', + fontFamily: 'Roboto, sans-serif', textAnchor: 'start', textVerticalAnchor: 'top', x: 2, @@ -519,7 +519,7 @@ export const useDiagram = (): DiagramState & DiagramActions => { textElement.set('data', { text: 'Text Element', fontSize: 14, - fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', + fontFamily: 'Roboto, sans-serif', color: 'black', backgroundColor: 'transparent', padding: 8, diff --git a/Website/hooks/useLoading.ts b/Website/hooks/useLoading.ts new file mode 100644 index 0000000..6970574 --- /dev/null +++ b/Website/hooks/useLoading.ts @@ -0,0 +1,47 @@ +import { useState } from 'react'; + +interface UseLoadingReturn { + isAuthenticating: boolean; + isRedirecting: boolean; + startAuthentication: () => void; + startRedirection: () => void; + stopAuthentication: () => void; + stopRedirection: () => void; + resetAuthState: () => void; +} + +export const useLoading = (): UseLoadingReturn => { + const [isAuthenticating, setIsAuthenticating] = useState(false); + const [isRedirecting, setIsRedirecting] = useState(false); + + const startAuthentication = () => { + setIsAuthenticating(true); + }; + + const startRedirection = () => { + setIsRedirecting(true); + }; + + const stopAuthentication = () => { + setIsAuthenticating(false); + }; + + const stopRedirection = () => { + setIsRedirecting(false); + }; + + const resetAuthState = () => { + setIsAuthenticating(false); + setIsRedirecting(false); + }; + + return { + isAuthenticating, + isRedirecting, + startAuthentication, + startRedirection, + stopAuthentication, + stopRedirection, + resetAuthState, + }; +}; diff --git a/Website/hooks/useThemeClasses.ts b/Website/hooks/useThemeClasses.ts new file mode 100644 index 0000000..e69de29 diff --git a/Website/lib/Types.ts b/Website/lib/Types.ts index 2b27869..2eae3e2 100644 --- a/Website/lib/Types.ts +++ b/Website/lib/Types.ts @@ -41,12 +41,37 @@ export const enum CalculationMethods { Rollup = 1, } +export enum ComponentType +{ + PowerAutomateFlow, + Plugin, + WebResource, + WorkflowActivity, + CustomApi +} + +export enum OperationType +{ + Create, + Read, + Update, + Delete, + List, + Other +} + +export type UsageType = { + Name: string, + ComponentType: ComponentType, + Usage: string, + OperationType: OperationType +} + export type BaseAttribute = { + AttributeUsages: UsageType[]; IsPrimaryId: boolean; IsCustomAttribute: boolean; IsStandardFieldModified: boolean; - HasPluginStep: boolean; - PluginTypeNames: string[]; DisplayName: string, SchemaName: string, Description: string | null, diff --git a/Website/lib/session.ts b/Website/lib/session.ts index 8bdb6b5..2be88aa 100644 --- a/Website/lib/session.ts +++ b/Website/lib/session.ts @@ -2,7 +2,6 @@ import 'server-only'; import { SignJWT, jwtVerify } from "jose"; import { cookies } from "next/headers"; -import { redirect } from 'next/navigation' const secretKey = process.env.WebsiteSessionSecret; const encodedKey = new TextEncoder().encode(secretKey); @@ -51,7 +50,6 @@ export async function createSession(password: string) { export async function deleteSession() { const cookieStore = await cookies(); cookieStore.delete("session"); - redirect("/login"); } export async function getSession() { diff --git a/Website/package-lock.json b/Website/package-lock.json index fd2f960..925aeff 100644 --- a/Website/package-lock.json +++ b/Website/package-lock.json @@ -9,41 +9,36 @@ "version": "1.4.1", "dependencies": { "@joint/core": "^4.1.3", - "@radix-ui/react-checkbox": "^1.3.2", - "@radix-ui/react-collapsible": "^1.1.1", - "@radix-ui/react-dialog": "^1.1.2", - "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-popover": "^1.1.6", - "@radix-ui/react-scroll-area": "^1.2.9", - "@radix-ui/react-select": "^2.2.5", - "@radix-ui/react-separator": "^1.1.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-tabs": "^1.1.12", - "@radix-ui/react-tooltip": "^1.1.8", + "@mui/icons-material": "^7.3.2", + "@mui/material": "^7.3.2", + "@mui/material-nextjs": "^7.3.2", + "@nivo/core": "^0.99.0", + "@nivo/pie": "^0.99.0", + "@tailwindcss/postcss": "^4.1.13", "@tanstack/react-virtual": "^3.13.12", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "jose": "^5.9.6", "libavoid-js": "^0.4.5", - "lucide-react": "^0.462.0", "next": "^15.3.4", + "postcss": "^8.5.6", "react": "^19.0.0", "react-dom": "^19.0.0", "react-markdown": "^10.1.0", "react-window": "^1.8.11", "tailwind-merge": "^2.5.5", - "tailwindcss-animate": "^1.0.7" + "tailwindcss": "^4.1.13" }, "devDependencies": { - "@types/lodash": "^4.17.19", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "@types/react-window": "^1.8.8", - "eslint": "^8", + "eslint": "^9.35.0", "eslint-config-next": "15.0.3", - "postcss": "^8", - "tailwindcss": "^3.4.1", "typescript": "^5" } }, @@ -51,6 +46,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -58,11 +54,151 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.28.2" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", + "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, "engines": { "node": ">=6.9.0" } @@ -77,11 +213,187 @@ "tslib": "^2.4.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/server": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/server/-/server-11.11.0.tgz", + "integrity": "sha512-6q89fj2z8VBTx9w93kJ5n51hsmtYuFPtZgnc1L8VzRx9ti4EU6EyvF6Nn1H1x3vcCQCF7u2dB2lY4AYJwUW4PA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emotion/utils": "^1.2.1", + "html-tokenize": "^2.0.0", + "multipipe": "^1.0.2", + "through": "^2.3.8" + }, + "peerDependencies": { + "@emotion/css": "^11.0.0-rc.0" + }, + "peerDependenciesMeta": { + "@emotion/css": { + "optional": true + } + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -104,16 +416,73 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/compat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.3.2.tgz", + "integrity": "sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^8.40 || 9" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -121,72 +490,71 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", + "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", - "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", - "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.2", - "@floating-ui/utils": "^0.2.10" + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.4.tgz", - "integrity": "sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==", - "license": "MIT", + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@floating-ui/dom": "^1.7.2" + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -202,12 +570,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.34.2", @@ -605,45 +980,16 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", "dependencies": { - "ansi-regex": "^6.0.1" + "minipass": "^7.0.4" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=18.0.0" } }, "node_modules/@joint/core": { @@ -653,16 +999,23 @@ "license": "MPL-2.0" }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -673,28 +1026,290 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mui/core-downloads-tracker": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.2.tgz", + "integrity": "sha512-AOyfHjyDKVPGJJFtxOlept3EYEdLoar/RvssBTWVAvDJGIE676dLi2oT/Kx+FoVXFoA/JdV7DEMq/BVWV3KHRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.2.tgz", + "integrity": "sha512-TZWazBjWXBjR6iGcNkbKklnwodcwj0SrChCNHc9BhD9rBgET22J1eFhHsEmvSvru9+opDy3umqAimQjokhfJlQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^7.3.2", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.2.tgz", + "integrity": "sha512-qXvbnawQhqUVfH1LMgMaiytP+ZpGoYhnGl7yYq2x57GYzcFL/iPzSZ3L30tlbwEjSVKNYcbiKO8tANR1tadjUg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@mui/core-downloads-tracker": "^7.3.2", + "@mui/system": "^7.3.2", + "@mui/types": "^7.4.6", + "@mui/utils": "^7.3.2", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.1.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.3.2", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material-nextjs": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/material-nextjs/-/material-nextjs-7.3.2.tgz", + "integrity": "sha512-PYRGXf32vNOdKOrTOkoNmWipFKpMODQzrfSPaQQb0SsuTRWRyPxP1WR9A7JccJvsmvbBhdQ9bcBqrCD8oJub4w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/cache": "^11.11.0", + "@emotion/react": "^11.11.4", + "@emotion/server": "^11.11.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "next": "^13.0.0 || ^14.0.0 || ^15.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/cache": { + "optional": true + }, + "@emotion/server": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.2.tgz", + "integrity": "sha512-ha7mFoOyZGJr75xeiO9lugS3joRROjc8tG1u4P50dH0KR7bwhHznVMcYg7MouochUy0OxooJm/OOSpJ7gKcMvg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@mui/utils": "^7.3.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.2.tgz", + "integrity": "sha512-PkJzW+mTaek4e0nPYZ6qLnW5RGa0KN+eRTf5FA2nc7cFZTeM+qebmGibaTLrgQBy3UpcpemaqfzToBNkzuxqew==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.2.tgz", + "integrity": "sha512-9d8JEvZW+H6cVkaZ+FK56R53vkJe3HsTpcjMUtH8v1xK6Y1TjzHdZ7Jck02mGXJsE6MQGWVs3ogRHTQmS9Q/rA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@mui/private-theming": "^7.3.2", + "@mui/styled-engine": "^7.3.2", + "@mui/types": "^7.4.6", + "@mui/utils": "^7.3.2", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.6.tgz", + "integrity": "sha512-NVBbIw+4CDMMppNamVxyTccNv0WxtDb7motWDlMeSC8Oy95saj1TIZMGynPpFLePt3yOD8TskzumeqORCgRGWw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.2.tgz", + "integrity": "sha512-4DMWQGenOdLnM3y/SdFQFwKsCLM+mqxzvoWp9+x2XdEzXapkznauHLiXtSohHs/mc0+5/9UACt1GdugCX2te5g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@mui/types": "^7.4.6", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@next/env": { "version": "15.3.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.4.tgz", @@ -838,10 +1453,155 @@ "node": ">= 10" } }, + "node_modules/@nivo/arcs": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/arcs/-/arcs-0.99.0.tgz", + "integrity": "sha512-UcvWLQPl+A3APk2Gm74N5xDfT+ATnVs2XkP73WxhYPWJk+dBzF00cndA5g/dptOwdFBvvo62VgcCsNiwUsjKTw==", + "license": "MIT", + "dependencies": { + "@nivo/colors": "0.99.0", + "@nivo/core": "0.99.0", + "@nivo/text": "0.99.0", + "@nivo/theming": "0.99.0", + "@react-spring/core": "9.4.5 || ^9.7.2 || ^10.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", + "@types/d3-shape": "^3.1.6", + "d3-shape": "^3.2.0" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, + "node_modules/@nivo/colors": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.99.0.tgz", + "integrity": "sha512-hyYt4lEFIfXOUmQ6k3HXm3KwhcgoJpocmoGzLUqzk7DzuhQYJo+4d5jIGGU0N/a70+9XbHIdpKNSblHAIASD3w==", + "license": "MIT", + "dependencies": { + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", + "@types/d3-color": "^3.0.0", + "@types/d3-scale": "^4.0.8", + "@types/d3-scale-chromatic": "^3.0.0", + "d3-color": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.0.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, + "node_modules/@nivo/core": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.99.0.tgz", + "integrity": "sha512-olCItqhPG3xHL5ei+vg52aB6o+6S+xR2idpkd9RormTTUniZb8U2rOdcQojOojPY5i9kVeQyLFBpV4YfM7OZ9g==", + "license": "MIT", + "dependencies": { + "@nivo/theming": "0.99.0", + "@nivo/tooltip": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0", + "@types/d3-shape": "^3.1.6", + "d3-color": "^3.1.0", + "d3-format": "^1.4.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.0.0", + "d3-shape": "^3.2.0", + "d3-time-format": "^3.0.0", + "lodash": "^4.17.21", + "react-virtualized-auto-sizer": "^1.0.26", + "use-debounce": "^10.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nivo/donate" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, + "node_modules/@nivo/legends": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.99.0.tgz", + "integrity": "sha512-P16FjFqNceuTTZphINAh5p0RF0opu3cCKoWppe2aRD9IuVkvRm/wS5K1YwMCxDzKyKh5v0AuTlu9K6o3/hk8hA==", + "license": "MIT", + "dependencies": { + "@nivo/colors": "0.99.0", + "@nivo/core": "0.99.0", + "@nivo/text": "0.99.0", + "@nivo/theming": "0.99.0", + "@types/d3-scale": "^4.0.8", + "d3-scale": "^4.0.2" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, + "node_modules/@nivo/pie": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/pie/-/pie-0.99.0.tgz", + "integrity": "sha512-zUbo8UdLndp2RMljrOqitAKKEnl7YypkJrOzjKLk8jQGU7qqUKtgFoJIPhiBsvNPs3xtX2KwgtS1+JKNTNns7A==", + "license": "MIT", + "dependencies": { + "@nivo/arcs": "0.99.0", + "@nivo/colors": "0.99.0", + "@nivo/core": "0.99.0", + "@nivo/legends": "0.99.0", + "@nivo/theming": "0.99.0", + "@nivo/tooltip": "0.99.0", + "@types/d3-shape": "^3.1.6", + "d3-shape": "^3.2.0" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, + "node_modules/@nivo/text": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/text/-/text-0.99.0.tgz", + "integrity": "sha512-ho3oZpAZApsJNjsIL5WJSAdg/wjzTBcwo1KiHBlRGUmD+yUWO8qp7V+mnYRhJchwygtRVALlPgZ/rlcW2Xr/MQ==", + "license": "MIT", + "dependencies": { + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, + "node_modules/@nivo/theming": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/theming/-/theming-0.99.0.tgz", + "integrity": "sha512-KvXlf0nqBzh/g2hAIV9bzscYvpq1uuO3TnFN3RDXGI72CrbbZFTGzprPju3sy/myVsauv+Bb+V4f5TZ0jkYKRg==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, + "node_modules/@nivo/tooltip": { + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.99.0.tgz", + "integrity": "sha512-weoEGR3xAetV4k2P6k96cdamGzKQ5F2Pq+uyDaHr1P3HYArM879Pl+x+TkU0aWjP6wgUZPx/GOBiV1Hb1JxIqg==", + "license": "MIT", + "dependencies": { + "@nivo/core": "0.99.0", + "@nivo/theming": "0.99.0", + "@react-spring/web": "9.4.5 || ^9.7.2 || ^10.0" + }, + "peerDependencies": { + "react": "^16.14 || ^17.0 || ^18.0 || ^19.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -854,6 +1614,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "engines": { "node": ">= 8" } @@ -862,6 +1623,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -879,2369 +1641,88 @@ "node": ">=12.4.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", - "license": "MIT" - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", - "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" - }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz", - "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.0.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", - "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" } }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", - "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", + "node_modules/@react-spring/animated": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-10.0.2.tgz", + "integrity": "sha512-GaVMfinZ6/Aid1v44ESf45H5jOj7cVbDuNVDDkvsVJAPRLgPl8+q8IJsmZGl77+cHpC/nw2X+4B9fOtil+LIOQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.1.2" + "@react-spring/shared": "~10.0.2", + "@react-spring/types": "~10.0.2" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", - "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", + "node_modules/@react-spring/core": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-10.0.2.tgz", + "integrity": "sha512-GTV2I3cHlE1nGqInn2vWHdMD8Wrszlmfq+G5UYrF8TRK/pWu+oMJE+7SI6NbYuCvLPLY9F2cmCiZsKqBSTXXbQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1" + "@react-spring/animated": "~10.0.2", + "@react-spring/shared": "~10.0.2", + "@react-spring/types": "~10.0.2" }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.2.tgz", - "integrity": "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/primitive": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", - "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-presence": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", - "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.1.tgz", - "integrity": "sha512-1///SnrfQHJEofLokyczERxQbWfCGQlQ2XsCZMucVs6it+lq9iw4vXy+uDn1edlb58cOZOWSldnfPAYcT4O/Yg==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", - "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", - "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz", - "integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.1", - "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.2", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.6.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz", - "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==", - "dependencies": { - "react-remove-scroll-bar": "^2.3.6", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll/node_modules/react-remove-scroll-bar": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", - "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", - "dependencies": { - "react-style-singleton": "^2.2.1", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz", - "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", - "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", - "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", - "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", - "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.6.tgz", - "integrity": "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==", - "dependencies": { - "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.5", - "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.2", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.2", - "@radix-ui/react-portal": "1.1.4", - "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-slot": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.1.0", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", - "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==" - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", - "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", - "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz", - "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", - "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", - "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", - "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", - "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz", - "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-use-rect": "1.1.0", - "@radix-ui/react-use-size": "1.1.0", - "@radix-ui/rect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", - "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", - "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", - "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz", - "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", - "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", - "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", - "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/primitive": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", - "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.9.tgz", - "integrity": "sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A==", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/primitive": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", - "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-presence": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", - "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", - "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.10", - "@radix-ui/react-focus-guards": "1.1.2", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.7", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/primitive": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", - "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", - "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", - "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", - "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", - "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", - "license": "MIT", - "dependencies": { - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.0.tgz", - "integrity": "sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz", - "integrity": "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.10", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/primitive": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", - "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", - "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz", - "integrity": "sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==", - "dependencies": { - "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.5", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.2", - "@radix-ui/react-portal": "1.1.4", - "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-slot": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", - "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==" - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", - "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", - "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", - "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.0.2", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", - "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", - "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", - "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz", - "integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.0.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", - "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", - "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", - "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", - "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", - "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", - "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/rect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", - "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@react-spring/rafz": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-10.0.2.tgz", + "integrity": "sha512-UaLbq3sE80YqBx5/g3PKE6zQ4R24/UGg/jjXbxhSyt4w+O52m3sj3xZxSru6dkXyC2QciXO1pg8sGWqpn8foUg==", + "license": "MIT" + }, + "node_modules/@react-spring/shared": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-10.0.2.tgz", + "integrity": "sha512-fG8UTo7iTx8+pbMIp41rrAYtBxJ56qqcNs6Sqy4meogbSfPlk5kJSSeKAvF02regPpgzi9rWZA+dR3HL240ilw==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@react-spring/rafz": "~10.0.2", + "@react-spring/types": "~10.0.2" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@react-spring/types": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-10.0.2.tgz", + "integrity": "sha512-BCJyfNrR0CVsyquRjEXvMFCa+jwFMC+qpdRvT8TNepD+JWB+8lsgbDKrrUbbhexUQhy5pTmk2wHTteYpLPEnig==", + "license": "MIT" + }, + "node_modules/@react-spring/web": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.2.tgz", + "integrity": "sha512-94Gb91dWdua217UskhLYrX61HEn8Tm0xvlIfDiG7HIxXLHcu6sqVfmX2pp2C/n6MxCsWpYcVejVih1PJ2/y4HQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@react-spring/animated": "~10.0.2", + "@react-spring/core": "~10.0.2", + "@react-spring/shared": "~10.0.2", + "@react-spring/types": "~10.0.2" }, "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@radix-ui/rect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", - "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", - "license": "MIT" - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -3268,6 +1749,267 @@ "tslib": "^2.8.0" } }, + "node_modules/@tailwindcss/node": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.13.tgz", + "integrity": "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.5.1", + "lightningcss": "1.30.1", + "magic-string": "^0.30.18", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.13" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz", + "integrity": "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.13", + "@tailwindcss/oxide-darwin-arm64": "4.1.13", + "@tailwindcss/oxide-darwin-x64": "4.1.13", + "@tailwindcss/oxide-freebsd-x64": "4.1.13", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.13", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.13", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.13", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.13", + "@tailwindcss/oxide-linux-x64-musl": "4.1.13", + "@tailwindcss/oxide-wasm32-wasi": "4.1.13", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.13", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.13" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.13.tgz", + "integrity": "sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.13.tgz", + "integrity": "sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.13.tgz", + "integrity": "sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.13.tgz", + "integrity": "sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.13.tgz", + "integrity": "sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.13.tgz", + "integrity": "sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.13.tgz", + "integrity": "sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.13.tgz", + "integrity": "sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.13.tgz", + "integrity": "sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.13.tgz", + "integrity": "sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@emnapi/wasi-threads": "^1.0.4", + "@napi-rs/wasm-runtime": "^0.2.12", + "@tybys/wasm-util": "^0.10.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.13.tgz", + "integrity": "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.13.tgz", + "integrity": "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz", + "integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.13", + "@tailwindcss/oxide": "4.1.13", + "postcss": "^8.4.41", + "tailwindcss": "4.1.13" + } + }, "node_modules/@tanstack/react-virtual": { "version": "3.13.12", "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.12.tgz", @@ -3295,6 +2037,48 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -3328,19 +2112,19 @@ "@types/unist": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-NYqRyg/hIQrYPT9lbOeYc3kIRabJDn/k4qQHIXUpx88CBDww2fD15Sg5kbXlW86zm2XEW4g0QxkTI3/Kfkc7xQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -3365,10 +2149,18 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT", + "peer": true + }, "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.12", @@ -3383,11 +2175,20 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "devOptional": true, + "dev": true, "dependencies": { "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-window": { "version": "1.8.8", "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz", @@ -3664,10 +2465,11 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3680,6 +2482,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3700,18 +2503,11 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3722,45 +2518,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/aria-hidden": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", - "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -3956,7 +2719,23 @@ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, "engines": { - "node": ">= 0.4" + "node": ">= 0.4" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" } }, "node_modules/bail": { @@ -3972,18 +2751,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -3999,6 +2768,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -4006,6 +2776,14 @@ "node": ">=8" } }, + "node_modules/buffer-from": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", + "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -4040,19 +2818,10 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "engines": { - "node": ">= 6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001685", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001685.tgz", @@ -4138,38 +2907,13 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 6" + "node": ">=18" } }, "node_modules/class-variance-authority": { @@ -4214,6 +2958,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -4224,7 +2969,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true }, "node_modules/color-string": { "version": "1.9.1", @@ -4247,24 +2993,59 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT", + "peer": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4274,22 +3055,145 @@ "node": ">= 8" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-time": "1 - 2" + } + }, + "node_modules/d3-time-format/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-time-format/node_modules/d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "2" + } + }, + "node_modules/d3-time-format/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -4430,16 +3334,10 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" - }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -4453,43 +3351,74 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", + "optional": true, + "peer": true, + "dependencies": { + "readable-stream": "^2.0.2" + } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dev": true, + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4498,6 +3427,23 @@ "node": ">=10.13.0" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT", + "peer": true + }, "node_modules/es-abstract": { "version": "1.23.5", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", @@ -4661,7 +3607,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -4670,59 +3615,64 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", + "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.35.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-next": { @@ -5036,16 +3986,17 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5063,18 +4014,45 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5097,6 +4075,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -5188,26 +4167,29 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5215,6 +4197,13 @@ "node": ">=8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT", + "peer": true + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -5232,66 +4221,33 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" + "keyv": "^4.5.4" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" } }, "node_modules/function-bind": { @@ -5348,14 +4304,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", @@ -5385,31 +4333,11 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -5418,15 +4346,13 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5466,8 +4392,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/graphemer": { "version": "1.4.0", @@ -5598,6 +4523,41 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT", + "peer": true + }, + "node_modules/html-tokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz", + "integrity": "sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "buffer-from": "~0.1.1", + "inherits": "~2.0.1", + "minimist": "~1.2.5", + "readable-stream": "~1.0.27-1", + "through2": "~0.4.1" + }, + "bin": { + "html-tokenize": "bin/cmd.js" + } + }, "node_modules/html-url-attributes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", @@ -5621,7 +4581,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5642,22 +4601,12 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "optional": true, + "peer": true }, "node_modules/inline-style-parser": { "version": "0.2.4", @@ -5679,6 +4628,15 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -5753,17 +4711,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.0.tgz", @@ -5859,6 +4806,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -5878,14 +4826,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -5905,6 +4845,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -5950,6 +4891,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } @@ -5970,15 +4912,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -6131,7 +5064,8 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/iterator.prototype": { "version": "1.1.3", @@ -6149,26 +5083,13 @@ "node": ">= 0.4" } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "license": "MIT", "bin": { - "jiti": "bin/jiti.js" + "jiti": "lib/jiti-cli.mjs" } }, "node_modules/jose": { @@ -6182,8 +5103,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -6197,11 +5117,32 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT", + "peer": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -6247,6 +5188,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -6282,24 +5224,245 @@ "node": ">= 0.8.0" } }, - "node_modules/libavoid-js": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/libavoid-js/-/libavoid-js-0.4.5.tgz", - "integrity": "sha512-9BrYRXAQ+nmLuHZSqf4z52YN8TroBPxyqo6A6h6Pj03j5UYNx/Hhnd/rg+kiLVrE76wzBeBVO3OW7kaEpzYC9Q==", - "license": "LGPL-2.1-or-later" - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "node_modules/libavoid-js": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/libavoid-js/-/libavoid-js-0.4.5.tgz", + "integrity": "sha512-9BrYRXAQ+nmLuHZSqf4z52YN8TroBPxyqo6A6h6Pj03j5UYNx/Hhnd/rg+kiLVrE76wzBeBVO3OW7kaEpzYC9Q==", + "license": "LGPL-2.1-or-later" + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "peer": true }, "node_modules/locate-path": { "version": "6.0.0", @@ -6316,6 +5479,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -6336,7 +5505,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -6344,17 +5512,13 @@ "loose-envify": "cli.js" } }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, - "node_modules/lucide-react": { - "version": "0.462.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.462.0.tgz", - "integrity": "sha512-NTL7EbAao9IFtuSivSZgrAh4fZd09Lr+6MTkqIxuHaH2nnYiYIzXPo06cOxHg9wKLdj6LL8TByG4qpePqwgx/g==", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/mdast-util-from-markdown": { @@ -6520,6 +5684,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "engines": { "node": ">= 8" } @@ -6970,6 +6135,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -6994,7 +6160,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, + "devOptional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7003,35 +6169,66 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "node_modules/multipipe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-1.0.2.tgz", + "integrity": "sha512-6uiC9OvY71vzSGX8lZvSqscE7ft9nPupJ8fMjrCNRAUy2LREUW42UL+V/NTrogr6rFgRydUrCX4ZitfpSNkSCQ==", + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" + "duplexer2": "^0.1.2", + "object-assign": "^4.1.0" } }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -7126,14 +6323,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7142,14 +6331,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", @@ -7252,15 +6433,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -7308,16 +6480,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -7350,6 +6516,25 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7359,19 +6544,11 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -7381,19 +6558,14 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "peer": true, "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, "node_modules/picocolors": { @@ -7405,6 +6577,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -7412,22 +6585,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "engines": { - "node": ">= 6" - } - }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -7438,9 +6595,9 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -7455,8 +6612,9 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7464,126 +6622,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -7593,17 +6631,30 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -7627,6 +6678,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -7664,10 +6716,10 @@ } }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", + "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", + "license": "MIT" }, "node_modules/react-markdown": { "version": "10.1.0", @@ -7696,70 +6748,30 @@ "react": ">=18" } }, - "node_modules/react-remove-scroll": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", - "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", - "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll/node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" }, "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "react": ">=16.6.0", + "react-dom": ">=16.6.0" } }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", - "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, + "node_modules/react-virtualized-auto-sizer": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz", + "integrity": "sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A==", + "license": "MIT", "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-window": { @@ -7779,24 +6791,27 @@ "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "pify": "^2.3.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } + "node_modules/readable-stream/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/reflect.getprototypeof": { "version": "1.0.7", @@ -7890,7 +6905,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -7908,31 +6922,17 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -7969,6 +6969,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -8083,6 +7091,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -8094,6 +7103,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -8116,17 +7126,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -8137,6 +7136,16 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -8163,65 +7172,13 @@ "node": ">=10.0.0" } }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/string.prototype.includes": { "version": "2.0.1", @@ -8336,29 +7293,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -8420,67 +7354,11 @@ } } }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" }, "node_modules/supports-color": { "version": "7.2.0", @@ -8515,113 +7393,61 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", - "integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.6", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss-animate": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", - "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/tailwindcss/node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/tailwindcss/node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz", + "integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==", + "license": "MIT" }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "engines": { "node": ">=6" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "license": "ISC", "dependencies": { - "any-promise": "^1.0.0" + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/through2": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" + "readable-stream": "~1.0.17", + "xtend": "~2.1.1" } }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -8661,11 +7487,6 @@ "typescript": ">=4.2.0" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -8695,18 +7516,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", @@ -8911,51 +7720,25 @@ "punycode": "^2.1.0" } }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sidecar": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" - }, + "node_modules/use-debounce": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.6.tgz", + "integrity": "sha512-C5OtPyhAZgVoteO9heXMTdW7v/IbFI+8bSVKYCJrSmiWWCLsbUxiBSp4t9v0hNBTGY97bT72ydDIDyGSFWfwXg==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 16.0.0" }, "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "react": "*" } }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/vfile": { "version": "6.0.3", @@ -8989,6 +7772,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -9088,108 +7872,34 @@ "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", + "optional": true, + "peer": true, "dependencies": { - "ansi-regex": "^6.0.1" + "object-keys": "~0.4.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=0.4" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "node_modules/xtend/node_modules/object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==", + "license": "MIT", + "optional": true, + "peer": true }, - "node_modules/yaml": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", - "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", - "bin": { - "yaml": "bin.mjs" - }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 14" + "node": ">=18" } }, "node_modules/yocto-queue": { diff --git a/Website/package.json b/Website/package.json index 2a11a3c..cd1476b 100644 --- a/Website/package.json +++ b/Website/package.json @@ -11,41 +11,36 @@ }, "dependencies": { "@joint/core": "^4.1.3", - "@radix-ui/react-checkbox": "^1.3.2", - "@radix-ui/react-collapsible": "^1.1.1", - "@radix-ui/react-dialog": "^1.1.2", - "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-popover": "^1.1.6", - "@radix-ui/react-scroll-area": "^1.2.9", - "@radix-ui/react-select": "^2.2.5", - "@radix-ui/react-separator": "^1.1.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-tabs": "^1.1.12", - "@radix-ui/react-tooltip": "^1.1.8", + "@mui/icons-material": "^7.3.2", + "@mui/material": "^7.3.2", + "@mui/material-nextjs": "^7.3.2", + "@nivo/core": "^0.99.0", + "@nivo/pie": "^0.99.0", + "@tailwindcss/postcss": "^4.1.13", "@tanstack/react-virtual": "^3.13.12", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "jose": "^5.9.6", "libavoid-js": "^0.4.5", - "lucide-react": "^0.462.0", "next": "^15.3.4", + "postcss": "^8.5.6", "react": "^19.0.0", "react-dom": "^19.0.0", "react-markdown": "^10.1.0", "react-window": "^1.8.11", "tailwind-merge": "^2.5.5", - "tailwindcss-animate": "^1.0.7" + "tailwindcss": "^4.1.13" }, "devDependencies": { - "@types/lodash": "^4.17.19", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "@types/react-window": "^1.8.8", - "eslint": "^8", + "eslint": "^9.35.0", "eslint-config-next": "15.0.3", - "postcss": "^8", - "tailwindcss": "^3.4.1", "typescript": "^5" } } diff --git a/Website/postcss.config.mjs b/Website/postcss.config.mjs index 1a69fd2..5f04293 100644 --- a/Website/postcss.config.mjs +++ b/Website/postcss.config.mjs @@ -1,8 +1,7 @@ -/** @type {import('postcss-load-config').Config} */ const config = { plugins: { - tailwindcss: {}, + "@tailwindcss/postcss": {}, }, }; -export default config; +export default config; \ No newline at end of file diff --git a/Website/public/4716572.svg b/Website/public/4716572.svg new file mode 100644 index 0000000..feac5c4 --- /dev/null +++ b/Website/public/4716572.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Website/public/documentation.jpg b/Website/public/documentation.jpg new file mode 100644 index 0000000..f9954a8 Binary files /dev/null and b/Website/public/documentation.jpg differ diff --git a/Website/public/processes.jpg b/Website/public/processes.jpg new file mode 100644 index 0000000..8601b52 Binary files /dev/null and b/Website/public/processes.jpg differ diff --git a/Website/public/upgrade.jpg b/Website/public/upgrade.jpg new file mode 100644 index 0000000..9933791 Binary files /dev/null and b/Website/public/upgrade.jpg differ diff --git a/Website/public/welcomeback-data-stockimage.webp b/Website/public/welcomeback-data-stockimage.webp new file mode 100644 index 0000000..323e9d2 Binary files /dev/null and b/Website/public/welcomeback-data-stockimage.webp differ diff --git a/Website/stubs/Data.ts b/Website/stubs/Data.ts index 23226f5..0f94ff1 100644 --- a/Website/stubs/Data.ts +++ b/Website/stubs/Data.ts @@ -25,8 +25,6 @@ export let Groups: GroupType[] = [ "IsPrimaryId": false, "IsCustomAttribute": true, "IsStandardFieldModified": false, - "HasPluginStep": true, - "PluginTypeNames": ["Sample Plugin Type"], "DisplayName": "Account Name", "SchemaName": "name", "Description": "The name of the account", @@ -35,15 +33,14 @@ export let Groups: GroupType[] = [ "IsColumnSecured": false, "CalculationMethod": null, "Format": "Text", - "MaxLength": 160 + "MaxLength": 160, + "AttributeUsages": [] }, { "AttributeType": "StringAttribute", "IsPrimaryId": false, "IsCustomAttribute": true, "IsStandardFieldModified": false, - "HasPluginStep": false, - "PluginTypeNames": [], "DisplayName": "Phone", "SchemaName": "telephone1", "Description": "The main phone number for the account", @@ -52,15 +49,14 @@ export let Groups: GroupType[] = [ "IsColumnSecured": false, "CalculationMethod": null, "Format": "Phone", - "MaxLength": 50 + "MaxLength": 50, + "AttributeUsages": [] }, { "AttributeType": "LookupAttribute", "IsPrimaryId": false, "IsCustomAttribute": true, "IsStandardFieldModified": false, - "HasPluginStep": true, - "PluginTypeNames": ["Another Plugin Type"], "DisplayName": "Primary Contact", "SchemaName": "primarycontactid", "Description": "The primary contact for the account", @@ -68,6 +64,7 @@ export let Groups: GroupType[] = [ "IsAuditEnabled": true, "IsColumnSecured": false, "CalculationMethod": null, + "AttributeUsages": [], "Targets": [ { "Name": "Contact", diff --git a/Website/tailwind.config.ts b/Website/tailwind.config.ts deleted file mode 100644 index 030dfb9..0000000 --- a/Website/tailwind.config.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { Config } from "tailwindcss"; - -export default { - darkMode: ["class"], - content: [ - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./app/**/*.{js,ts,jsx,tsx,mdx}", - ], - theme: { - extend: { - colors: { - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))' - }, - popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))' - }, - primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))' - }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))' - }, - muted: { - DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))' - }, - accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))' - }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))' - }, - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - chart: { - '1': 'hsl(var(--chart-1))', - '2': 'hsl(var(--chart-2))', - '3': 'hsl(var(--chart-3))', - '4': 'hsl(var(--chart-4))', - '5': 'hsl(var(--chart-5))' - }, - sidebar: { - DEFAULT: 'hsl(var(--sidebar-background))', - foreground: 'hsl(var(--sidebar-foreground))', - primary: 'hsl(var(--sidebar-primary))', - 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))', - accent: 'hsl(var(--sidebar-accent))', - 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))', - border: 'hsl(var(--sidebar-border))', - ring: 'hsl(var(--sidebar-ring))' - } - }, - borderRadius: { - lg: 'var(--radius)', - md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)' - } - } - }, - plugins: [require("tailwindcss-animate")], -} satisfies Config; diff --git a/Website/theme.ts b/Website/theme.ts new file mode 100644 index 0000000..005684b --- /dev/null +++ b/Website/theme.ts @@ -0,0 +1,106 @@ +'use client'; +import { createTheme, PaletteMode } from '@mui/material/styles'; + +// Augment the theme to add custom IconButton sizes +declare module '@mui/material/IconButton' { + interface IconButtonPropsSizeOverrides { + xsmall: true; + } +} + +// Augment the palette to add custom colors +declare module '@mui/material/styles' { + interface Palette { + accent: Palette['primary']; + border: Palette['primary']; + } + + interface PaletteOptions { + accent?: PaletteOptions['primary']; + border?: PaletteOptions['primary']; + } +} + +export const createAppTheme = (mode: PaletteMode) => createTheme({ + components: { + MuiIconButton: { + styleOverrides: { + root: { + // Base styles for all IconButton variants + }, + }, + variants: [ + { + props: { size: 'xsmall' }, + style: { + padding: '2px', + fontSize: '0.75rem', + '& svg': { + width: '16px', + height: '16px', + }, + }, + }, + ], + }, + }, + palette: { + mode, + primary: { + main: mode === 'dark' ? '#9fa8da' : '#3949ab', // Automatically adapts based on mode + contrastText: '#ffffff', + }, + secondary: { + main: mode === 'dark' ? '#8b5cf6' : '#7c3aed', // Violet-500 in dark, Violet-600 in light + contrastText: '#ffffff', + }, + accent: { + main: mode === 'dark' ? '#c4b5fd' : '#a78bfa', // Purple-300 in dark, Purple-400 in light + contrastText: '#ffffff', + }, + error: { + main: mode === 'dark' ? '#ef4444' : '#dc2626', // Red-500 in dark, Red-600 in light + }, + warning: { + main: mode === 'dark' ? '#f59e0b' : '#d97706', // Amber-500 in dark, Amber-600 in light + }, + info: { + main: mode === 'dark' ? '#38bdf8' : '#0ea5e9', // Sky-400 in dark, Sky-500 in light + }, + success: { + main: mode === 'dark' ? '#22c55e' : '#16a34a', // Green-500 in dark, Green-600 in light + }, + text: { + primary: mode === 'dark' ? '#f9fafb' : '#111827', // Light text in dark mode, dark text in light mode + secondary: mode === 'dark' ? '#d1d5db' : '#6b7280', // Secondary text colors + disabled: mode === 'dark' ? '#6b7280' : '#9ca3af', // Disabled text colors + }, + background: { + default: mode === 'dark' ? '#111827' : '#fafafa', + paper: mode === 'dark' ? '#1f2937' : '#ffffff', + }, + divider: mode === 'dark' ? '#374151' : '#e5e7eb', // Same as border.main for consistency + grey: { + 100: mode === 'dark' ? '#374151' : '#f3f4f6', + 200: mode === 'dark' ? '#4b5563' : '#e5e7eb', + 600: mode === 'dark' ? '#9ca3af' : '#4b5563', + 700: mode === 'dark' ? '#d1d5db' : '#374151', + }, + border: { + main: mode === 'dark' ? '#374151' : '#e5e7eb', // Gray-700 in dark mode, Gray-200 in light mode + dark: mode === 'dark' ? '#4b5563' : '#d1d5db', // Gray-600 in dark mode, Gray-300 in light mode + } + }, + typography: { + fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif', + allVariants: { + fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif', + }, + }, + cssVariables: true, +}); + +// Default theme for backwards compatibility +const theme = createAppTheme('light'); + +export default theme; \ No newline at end of file