diff --git a/README.md b/README.md index 05db2b3..26befac 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,24 @@ > > - [How to create a First Release Environment](#create-a-first-release-power-platform-environment) - Get an environment ready to run Code Apps! > - [Start in minutes with a Hello World sample code](samples/HelloWorld/README.md) - A ready to run React sample, with minimum setps to run on Power Apps. +> - ✨ [Static Sample / Template](samples/FluentSample/README.md) - The most complete sample. A static App with navigation, build with GitHub Copilot using Fluent UI. Samples includes prompt samples and guide to connect with real data. Includes: +> - Office 365 +> - SQL using data pagination +> - Custom Connector +> +> πŸ“‚ **Samples** +> +> - [Hello World](samples/HelloWorld/) - Basic React sample to get started quickly +> - [Static Asset Tracker](samples/StaticAssetTracker/) - Asset management with static data. +> - [Fluent Sample](samples/FluentSample/) - A static App with navigation, build with GitHub Copilot using Fluent UI. +> +> πŸ“š **How to** +> > - [How to create an app from Scratch](docs/how-to-create-from-scratch.md) - A detailed walkthrough to turn a blank app created with vite into Power Apps code app. > - [How to connect to data](docs/how-to-connect-to-data.md) - Code apps enable connecting to Power Platform connectors. To do this, you will create connections, add them to the app, and update the app to call them. -> - [How to connect to Azure SQL](docs/how-to-connect-to-azure-sql.md) β€” Find a detailed walkthrough for connecting your code app to Azure SQL. -> - [How to analyze data requests/response](docs/how-to-analyze-data-request-response.md) - Guide to troubleshoot and debug. +> - [How to connect to Azure SQL](docs/how-to-connect-to-azure-sql.md) - Find a detailed walkthrough for connecting your code app to Azure SQL. +> - [How to analyze data requests/response](docs/how-to-analyze-data-request-response.md) - Troubleshoot API calls > - [How to create sample api and a custom connector](docs/how-to-create-api-and-custom-connector.md) - Quickly create a mock api and a custom connector to test Code Apps with Custom Connectors. -> - ✨ [Sample - Static Asset Tracker](samples/StaticAssetTracker/) - A sample app with static data, ideal for learning how to add data sources and integrate with Power Platform connectors. -> Power Apps empowers developers of all skillsetsβ€”including those building web apps in IDEs like Visual Studio Codeβ€”to efficiently build and run business apps on a managed platform. diff --git a/samples/FluentSample/.cursor/rules/powersdkcli.mdc b/samples/FluentSample/.cursor/rules/powersdkcli.mdc new file mode 100644 index 0000000..4dfffe5 --- /dev/null +++ b/samples/FluentSample/.cursor/rules/powersdkcli.mdc @@ -0,0 +1,6 @@ +--- +description: +globs: +alwaysApply: true +--- +Always read the .github/copilot-instructions.md for the context. \ No newline at end of file diff --git a/samples/FluentSample/.cursor/rules/powersdkcli_backup.mdc b/samples/FluentSample/.cursor/rules/powersdkcli_backup.mdc new file mode 100644 index 0000000..4dfffe5 --- /dev/null +++ b/samples/FluentSample/.cursor/rules/powersdkcli_backup.mdc @@ -0,0 +1,6 @@ +--- +description: +globs: +alwaysApply: true +--- +Always read the .github/copilot-instructions.md for the context. \ No newline at end of file diff --git a/samples/FluentSample/.github/copilot-instructions.md b/samples/FluentSample/.github/copilot-instructions.md new file mode 100644 index 0000000..7aead03 --- /dev/null +++ b/samples/FluentSample/.github/copilot-instructions.md @@ -0,0 +1,725 @@ + +# Power Apps Code Apps Development Guide + +# General Coding Guidance + +## General Behavior + +- You are an agent: continue working until the user's request is fully resolved. + Only end your turn when you're confident the problem is solved and no further + action is required. + +- Your thinking should be thoroughβ€”it's absolutely fine (and encouraged) if your + reasoning is long. Think step by step before and after each action you take. + +- Plan extensively before making any function calls. Reflect critically after + each one. Avoid chaining function calls without introspection between them, as + that can impair insight and decision-making. + +- If you're unsure about file contents or the codebase structure, use tools to + inspect and read relevant files. Never guess or make assumptions. + +- Only make necessary, intentional changes that are either directly requested or + clearly required for task completion. Avoid editing unrelated or unclear areas. + +## Code Quality and Style + +- Prefer simple solutions that are easy to understand and maintain. + +- Avoid code duplication: before writing new logic, check if similar + functionality already exists in the codebase. + +- Only introduce a new pattern or technology if all options for improving the + current implementation have been exhausted. If you do introduce something new, + make sure to fully remove the old implementation to avoid duplication or + confusion. + +- Keep the codebase clean and organized. Use consistent patterns and naming + conventions where applicable. + +- Avoid writing one-off scripts in the main codebaseβ€”especially if they are + only intended to run once. + +- Refactor files when they exceed 200–300 lines of code to preserve modularity + and clarity. + +- Never overwrite the .env file without asking for and receiving explicit + confirmation. + +- Follow best practices around formatting and consistency. Use linters, + formatters, and style guides where appropriate. + +## Coding Workflow + +- Stay focused on the parts of the code directly relevant to the current task. + +- Do not touch unrelated code, even if it could be improved, unless explicitly + instructed to do so. + +- Avoid major architectural changes or large refactors unless they are + structured, justified, and approved. + +- Before making a change, always consider its impact on other parts of the + systemβ€”downstream dependencies, shared services, and global logic should be + reviewed. + +- Document or summarize your reasoning and decision-making if a change affects + multiple components. + +--- + +# Using this template repository to build Power Apps Code App. + +Follow these steps in order to create a complete Power Apps Code App: + +1. **Install dependencies and build the app** - Set up the foundation +2. **Configure for Power Apps Code App** - Add Power Platform SDK integration +3. **Build app to work locally with mocked data** - Develop and test locally +4. **Check requirements for connecting with live data** - Ensure you have connectors setup to connect. +5. **Connect to Office 365** - Connect to live data sources +6. **Connect to SQL** - Connect to live data sources +7. **Connect to custom API** - Connect to custom connector +7. **Test and deploy** - Final testing and deployment + +--- + +## Step 1: Install depedencies + +Use only the files within FluentSample folder. + +Open the VS Code terminal (Terminal β†’ New Terminal) and navigate to the FluentSample folder: + +```bash +cd samples/FluentSample +npm install +npm run build +``` + +This ensures the project compiles successfully before running. + +--- + +## Step 2: Configure for Power Apps Code App + +Be sure the user has PAC CLI installed and it is connected to the right environment. To know what is your user - 'pac auth who'. To know what is current environment 'pac org who'. + +Initialize the app + +```bash +pac code init +``` + +If any error occurs, it is likely due to the wrong environment. Inform the user and don't proceed. + +--- + +## Step 3: Build app to work locally with mocked data + +```bash +npm run dev +``` + +This will start both Vite dev server and PAC Code Run automatically for local development and testing. +The server will start in a new terminal window, don't look for terminal output. You can assume the app is running in the port 3000. The file power.config.json has the necessary configuration for the Power Apps environment. + +--- +## Step 4: Check requirements for connecting with live data + +Check if the user has the needed connections. Use: + +```bash +pac connection list +``` + +This will show all available connections with their IDs and names. It is important to have the Office 365 Users, SQL and Custom Connector connections available. + +--- + +## Step 5: Connect to Office 365 + +For Office 365 Users: + +```bash +pac code add-data-source -a "shared_office365users" -c +``` + +Replace static data with real data. + +The Office365Page.tsx file is specifically designed for easy conversion from mock to live data: + +#### Step 1: Update Imports +**Current (Mock Data):** +```typescript +// TODO: Replace with live Office365UsersService when connecting to real data +// import { Office365UsersService } from '../Services/Office365UsersService'; +import * as mockData from '../mockData/office365Data'; +``` + +**Replace with (Live Data):** +```typescript +import { Office365UsersService } from '../Services/Office365UsersService'; +// import * as mockData from '../mockData/office365Data'; +``` + +#### Step 2: Update Current User Loading +**Current (Mock Data):** +```typescript +// Using mock data for demonstration +setCurrentUser(mockData.mockCurrentUser); +``` + +**Replace with (Live Data):** +```typescript +const result = await Office365UsersService.MyProfile(); +if (result.data) { + setCurrentUser(result.data); + // Load the current user's photo + const photo = await loadUserPhoto(result.data.Id); + if (photo) { + setUserPhotos(prev => ({ ...prev, [result.data.Id]: photo })); + } +} +``` + +#### Step 3: Update Photo Loading +**Current (Mock Data):** +```typescript +// For mock data, we don't have real photos +console.log(`Mock: Would load photo for user ${userId}`); +``` + +**Replace with (Live Data):** +```typescript +const result = await Office365UsersService.UserPhoto(userId); +if (result.data) { + // The photo comes as base64 data, create a data URL + return `data:image/jpeg;base64,${result.data}`; +} +``` + +#### Step 4: Update Search Function +**Current (Mock Data):** +```typescript +// Using mock data for demonstration +const pageSize = 50; +const mockResults = mockData.searchUsers(searchTerm.trim(), pageSize); +setUsers(mockResults); +``` + +**Replace with (Live Data):** +```typescript +const pageSize = 50; +const result = await Office365UsersService.SearchUser( + searchTerm.trim(), + pageSize +); + +if (result.success && result.data) { + setUsers(result.data); + console.log('Users loaded:', result.data.length); + + // Load photos for the users + await loadPhotosForUsers(result.data); +} else { + console.error('Search failed:', result.errorMessage); + setUsers([]); +} +``` + +#### Step 5: Update UI Status Indicators +**Current (Mock Data):** +```typescript + + πŸ“‹ Demo Mode - Using Mock Data (Welcome, {currentUser.DisplayName}!) + +``` + +**Replace with (Live Data):** +```typescript + + βœ… Connected to Office 365 - Welcome, {currentUser.DisplayName}! + +``` + +--- + +## step 6: Connect to SQL + +Discover the tables available in your database using the MSSQL tool +or ask the user to provide them. + +Always ask the user to confirm the server name and the database name. Prefer to use tables, as they have pagination support. + +Example stored procedures for a typical CRUD application: + +```bash +pac code add-data-source -a "shared_sql" -c \ + -t "dbo.Projects" -d "server.database.windows.net,database" +``` + +**Note:** Replace the table name, server and database name with the actual +values available in your database. Ask the user to provide their specific +values or use the MSSQL tool to discover them. Ask the user to confirm the values. + +replace static data from SQL sample with real data. User server side pagination. + +--- + +# Step 7: Connect to custom API + +Custom connector api id is usualy a long string. Use: +```bash +pac code add-data-source -a "shared_customapi" -c +``` + +--- + +## Step 8: Test and Deploy + +--- + + +### Original configuration + +To run code app, the following settings are needed. Use this in case changes cause the app to do not build or run. + +`vite.config.ts` proper configuration: + +```typescript +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import * as path from 'path' + +// https://vite.dev/config/ +export default defineConfig({ + base: "./", + server: { + host: "::", + port: 3000, // Important: Power Apps Code Apps require port 3000 + }, + plugins: [react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +}); +``` + +### Package.json Scripts + +The dev script in `package.json`: + +```json +{ + "scripts": { + "dev": "start pac code run && vite", + "build": "tsc -b && vite build" + } +} +``` + +**Note for macOS users**: Remove `start` from the dev script: +```json +{ + "scripts": { + "dev": "vite && pac code run" + } +} +``` + +### PowerProvider Component + +Need a `src/PowerProvider.tsx` with the following content: + +```typescript +import React from 'react'; +import { PowerProvider as Provider } from '@pa-client/power-code-sdk'; + +interface PowerProviderProps { + children: React.ReactNode; +} + +const PowerProvider: React.FC = ({ children }) => { + return ( + + {children} + + ); +}; + +export default PowerProvider; +``` + +### Update main.tsx + +Update `src/main.tsx` to include the PowerProvider: + +```typescript + + + + + , +``` + +--- + +## Fluent UI v9 + +### To Install Fluent UI Packages + +```bash +npm install @fluentui/react-components @fluentui/react-icons +``` + +### FluentProvider Setup + +Wrap your app with FluentProvider for consistent theming: + +```typescript +import { + FluentProvider, + webLightTheme, + webDarkTheme +} from '@fluentui/react-components'; + +function App() { + return ( + + {/* Your app content */} + + ); +} +``` +--- +The user might want to create more examples. Guidance: + +### Critical Implementation Rules for DataGrids + +1. **Server-Side Only**: Never implement client-side sorting with compare functions +2. **Responsive Design**: Always provide both desktop table and mobile card views +3. **Loading States**: Include skeleton components for all data loading states +4. **Column Resizing**: Use columnSizingOptions with proper width constraints +5. **Pagination**: Reset to page 1 when changing sort or filter parameters +6. **Accessibility**: Implement proper ARIA labels and keyboard navigation + +### Reference Documentation +- [Fluent UI DataGrid Documentation](https://fluentuipr.z22.web.core.windows.net/heads/master/public-docsite-v9/storybook/?path=/docs/components-datagrid--default) +- [Resizable Columns Example](https://github.com/microsoft/fluentui/blob/938a069ea4e0c460050e0dc147b9786e144cb6d3/packages/react-components/react-table/stories/src/DataGrid/ResizableColumns.stories.tsx) + +### Common Implementation Patterns +- Use `makeStyles` for consistent styling with design tokens +- Implement `useEffect` hooks for data loading on parameter changes +- Use `useMemo` for column definitions to prevent unnecessary re-renders +- Handle loading, error, and empty states appropriately +- Implement proper accessibility with ARIA labels and keyboard navigation +- Use proper TypeScript interfaces for type safety + +--- + +### Data Access Service Interface Pattern + +- Define TypeScript interfaces for all data operations (CRUD, search, pagination) +- Create contracts that both mock and real services will implement +- Ensure strongly-typed parameters and return types for all operations + +- Implement singleton factory to manage service instances +- Allow runtime switching between mock and real services +- Provide single point of configuration for the entire application + +#### Mock Services (Initial Implementation) + +- Create mock implementations that simulate real data operations +- Include realistic test data and proper pagination/filtering simulation +- Provide comprehensive logging for development debugging +- **Start here - implement mock services first** + +#### Real Services (Future Implementation) + +- **Do not implement initially - focus on mock services** +- **Stored procedure names will be determined later** +- Will integrate with Power Apps generated service classes +- Must maintain same interface as mock services + +### Accessibility Guidelines + +#### ARIA Best Practices +- Always include `aria-label` or `aria-labelledby` for interactive elements +- Use `aria-describedby` for additional context +- Implement proper focus management with `tabIndex` +- Use semantic HTML elements when possible + +#### Keyboard Navigation +- Ensure all interactive elements are keyboard accessible +- Implement proper tab order with `tabIndex` +- Use arrow keys for grid navigation +- Provide skip links for long content + +#### Color and Contrast +- Use Fluent UI design tokens for consistent colors +- Ensure minimum contrast ratios (4.5:1 for normal text, 3:1 for large text) +- Don't rely solely on color to convey information + +### Performance Optimization + +#### React Best Practices +- Use `useMemo` and `useCallback` for expensive computations +- Implement proper dependency arrays in `useEffect` +- Use `React.memo` for components that don't need frequent re-renders +- Implement proper key props for lists + +#### Data Loading Patterns +- Implement server-side pagination for large datasets +- Use loading skeletons instead of spinners +- Implement proper error boundaries +- Cache API responses where appropriate + +#### Bundle Optimization +- Use dynamic imports for code splitting +- Implement proper tree shaking +- Optimize images and assets +- Use Vite's built-in optimization features + +### Responsive Design Guidelines + +#### Mobile-First Approach +- Design for mobile screens first, then enhance for larger screens +- Use Fluent UI's responsive breakpoints +- Implement touch-friendly interactions (minimum 44px tap targets) + +#### Layout Patterns +- Use CSS Grid and Flexbox for responsive layouts +- Implement proper viewport meta tags +- Use relative units (rem, em, %) instead of fixed pixels +- Test on various screen sizes and orientations + +#### Component Responsiveness +- Provide alternative layouts for different screen sizes +- Use compound components for complex responsive patterns +- Implement proper overflow handling +- Consider content hierarchy on smaller screens + +### Local Development Testing + +```bash +npm run dev +``` + +This starts both the Vite development server and Power SDK server. + +--- + +### Power Platform Setup + +First release environment is required. Confirm with the user: + +```bash +pac admin create --name 'Code Apps' --region 'unitedstatesfirstrelease' --type 'Developer' +``` + +Authenticate and select environment: + +```bash +pac auth create --environment {environment id} +pac auth who # Verify correct environment is selected +``` + +### Initialize Power Apps Code App + +Configure the Power Apps Code App: + +```bash +pac code init --displayName "My App" -l "[location of the vite.svg]" +``` + +**Note:** Replace "My App" with the actual app name provided by the user. +Replace [location of the vite.svg] with the real location + +--- + +## Step 6: Wire Up to Real Connectors + +Initially use mocked data for development. Once the app is ready, replace with +actual data sources. + +Confirm everything is working with mocked data before integrating with real +data sources. + +### Get Connection IDs + +List available connections to find the connection ID: + +```bash +pac connection list +``` + +This will show all available connections with their IDs and names. + +--- + +## Step 7: Test and Deploy + +### Build and Deploy + +```bash +npm run build +pac code push +``` + +### Common Issues and Troubleshooting + +- **Port 3000 Required**: Power Apps Code Apps require port 3000 +- **PowerProvider Issues**: Ensure PowerProvider.tsx is properly configured +- **Build Errors**: Run `npm run build` before deploying +- **Authentication**: Use same browser profile as Power Platform tenant + +--- + +# FluentSample Template Guide + +## 🎯 Template Overview + +The FluentSample template is a comprehensive Power Apps Code Apps example demonstrating: +- Fluent UI v9 integration patterns in Power Platform context +- Navigation and data management with realistic mock data +- Clear transition path from mock data to live Power Platform connectors +- GitHub Copilot-optimized code patterns for AI-assisted development + +## πŸ“ FluentSample Project Structure + +``` +src/ +β”œβ”€β”€ components/ # Reusable UI components +β”‚ └── Layout.tsx # Main app layout with navigation +β”œβ”€β”€ pages/ # Route components +β”‚ β”œβ”€β”€ HomePage.tsx # Landing page with overview +β”‚ β”œβ”€β”€ Office365Page.tsx # Office 365 connector example (READY FOR LIVE DATA) +β”‚ β”œβ”€β”€ SqlPage.tsx # SQL database connector example +β”‚ └── CustomApiPage.tsx # Custom API connector example +β”œβ”€β”€ mockData/ # Mock data matching live API structures +β”‚ β”œβ”€β”€ office365Data.ts # Office 365 Users mock data +β”‚ β”œβ”€β”€ sqlData.ts # SQL mock data +β”‚ └── customApiData.ts # Custom API mock data +β”œβ”€β”€ Services/ # Auto-generated service files +β”‚ └── Office365UsersService.ts # Live Office 365 connector (commented out) +└── Models/ # TypeScript interfaces matching Power Platform + └── Office365UsersModel.ts # Office 365 data models +``` + +## πŸ”„ Converting Mock Data to Live Data in FluentSample + +### Office 365 Connector Integration + + + +## πŸ€– GitHub Copilot Integration for FluentSample + +### Optimized Copilot Prompts for FluentSample + +**For Office 365 Integration:** +``` +@workspace Convert the Office 365 mock data to live Office365UsersService calls. Replace the mock searchUsers, mockCurrentUser, and photo loading with actual API calls while maintaining the same UI patterns and error handling. +``` + +**For Complete Mock-to-Live Conversion:** +``` +@workspace I need to replace all mock data in Office365Page.tsx with live Office365UsersService calls. Update the imports, replace mockData.searchUsers with Office365UsersService.SearchUser, replace mockCurrentUser with MyProfile API call, and update photo loading to use UserPhoto API. +``` + +**For Error Handling Updates:** +``` +@workspace Update the error handling in Office365Page.tsx to handle live API failures, network errors, and authentication issues when using Office365UsersService instead of mock data. +``` + +**For UI Status Updates:** +``` +@workspace Update the connection status badge and integration note to reflect live Office 365 connection instead of mock data. +``` + +### Copilot-Friendly Code Patterns in FluentSample + +The FluentSample code uses specific patterns that Copilot can easily recognize: + +1. **Side-by-side mock/live code examples** with clear TODO comments +2. **Consistent function signatures** between mock and live services +3. **TypeScript interfaces** that match both mock and live data structures +4. **Clear separation** between UI logic and data access patterns + +Example pattern: +```typescript +// TODO: Replace with live Office365UsersService when connecting to real data +// const result = await Office365UsersService.SearchUser(searchTerm, pageSize); +// if (result.success && result.data) { ... } + +// Using mock data for demonstration +const mockResults = mockData.searchUsers(searchTerm.trim(), pageSize); +``` + +## 🎨 FluentSample Features Demonstrated + +### Office 365 Integration (Ready for Live Data) +- **User Directory Search**: Comprehensive search functionality with realistic Office 365 user data +- **User Profile Display**: Rich user cards showing DisplayName, JobTitle, BusinessPhones, OfficeLocation +- **Profile Photos**: User photo loading and display with fallback avatars +- **Current User Context**: Display of authenticated user profile and photo +- **Department Grouping**: Users organized by department for realistic organizational view +- **Responsive Design**: Cards adapt to different screen sizes using Fluent UI responsive patterns + +### UI Patterns & Components +- **Fluent UI v9 Integration**: Modern, accessible components following Microsoft design system +- **Navigation System**: Sidebar navigation with route management +- **Search Interface**: Real-time search with loading states and empty state handling +- **Card Layouts**: Responsive grid layouts for displaying user information +- **Status Indicators**: Connection badges showing current data source (mock vs live) +- **Loading States**: Proper loading indicators for async operations + +### Developer Experience Features +- **Clear Transition Path**: Well-documented mock-to-live data conversion +- **Copilot-Friendly Code**: Structured comments and patterns optimized for AI assistance +- **TypeScript Integration**: Full type safety with Power Platform data models +- **Error Handling**: Comprehensive error handling patterns for API integrations +- **Realistic Mock Data**: Mock data that exactly matches live API structures + +## πŸ”§ Troubleshooting FluentSample Live Data Integration + +### Common Issues and Solutions + +**Authentication Errors:** +- Ensure your Office 365 connection is properly configured +- Check that you have the necessary permissions +- Verify your Power Platform environment is active + +**No Users Returned:** +- Check your search terms are valid +- Verify the connector has access to your organization's directory +- Ensure the Office 365 Users connector is properly connected + +**Photos Not Loading:** +- User photos may not exist for all users +- Check network permissions and policies +- Verify the UserPhoto API has proper permissions + +**API Rate Limiting:** +- Implement proper error handling for rate limits +- Consider caching strategies for frequently accessed data +- Add loading states for better user experience + +## πŸ”„ Advanced Customization for FluentSample + +### Adding New Connector Examples + +1. **Create new service file** (auto-generated by Power Platform CLI) +2. **Create corresponding mock data file** with matching interfaces +3. **Create new page component** following the Office365Page.tsx pattern +4. **Add navigation route** in Layout.tsx +5. **Document conversion steps** in this guide + +### Extending the Office 365 Example + +The Office 365 integration can be extended with additional features: +- **Group Management**: Add groups search and member listing +- **Calendar Integration**: Show user availability and calendar events +- **Contact Details**: Extended contact information and organizational hierarchy +- **Manager/Direct Reports**: Organizational chart functionality + diff --git a/samples/FluentSample/.github/requirements.md b/samples/FluentSample/.github/requirements.md new file mode 100644 index 0000000..10818ec --- /dev/null +++ b/samples/FluentSample/.github/requirements.md @@ -0,0 +1,220 @@ +# FluentSample Requirements + +## Project Overview +This is a **ready-to-use static template** demonstrating Power Apps Code App integration patterns. The template provides a fully functional application with realistic mock data that users can **directly connect to their real Power Platform data sources**. + +**Primary Purpose**: +- **Provide Working Foundation**: Complete static app with mock data that users can immediately run and explore +- **Enable Easy Migration**: Use GitHub Copilot to help users replace mock data with their actual Power Platform connectors +- **Demonstrate Integration Patterns**: Show practical examples of Office 365, SQL, and Custom API connector usage +- **Accelerate Development**: Give developers a production-ready starting point for their own Power Apps Code Apps + +**User Journey**: Clone β†’ Run locally β†’ Use Copilot to connect to real data β†’ Deploy to Power Platform + +## Core Features + +### 1. Navigation System +- **Main Navigation Menu** with clear section descriptions +- **Responsive design** that works on desktop and mobile +- **Visual indicators** for active/current section +- **Sample descriptions** directly in the navigation to explain what each example demonstrates + +### 2. Office 365 Connector Example +**Current Implementation**: User directory search and profile display with static mock data +- **Features**: + - Search functionality across 50+ realistic user profiles with departments, roles, and contact info + - User profile cards showing DisplayName, JobTitle, Email, Department, BusinessPhones, OfficeLocation + - Profile photo placeholders with fallback avatars + - Current user context display + - Responsive grid layout adapting to screen sizes +- **Mock Data Structure**: Matches Office 365 Users connector API response format +- **Migration Path**: Clear TODO comments and side-by-side code examples for Copilot-assisted conversion +- **Target Connector**: Office 365 Users connector (`shared_office365users`) +- **Reference Documentation**: [How to Connect to Data](https://github.com/microsoft/PowerAppsCodeApps/blob/FluentSample/docs/how-to-connect-to-data.md) + +### 3. SQL Connector Example +**Purpose**: Demonstrate transitioning from mock database operations to live Azure SQL integration +- **Features**: + - Static implementation with realistic SQL mock data (Projects, Tasks, Employees) + - Comprehensive CRUD operations with mock data foundation + - Data pagination patterns ready for live data + - GitHub Copilot-friendly code structure for easy connector migration + - Search and filtering capabilities with realistic data scenarios +- **Copilot Integration Goal**: Guide users through replacing mock database calls with Power Apps SDK SQL connector +- **Reference Documentation**: [How to Connect to Azure SQL](https://github.com/microsoft/PowerAppsCodeApps/blob/FluentSample/docs/how-to-connect-to-azure-sql.md) +- **Navigation Description**: "SQL Database - CRUD operations, search, and data management" + +### 4. Custom Connector Example +**Current Implementation**: Basic asset management interface with realistic mock data +- **Features**: + - Asset listing with 30+ realistic business assets (equipment, software, facilities) + - Asset cards showing Name, Type, Category, Status, Location, Purchase Date, and Cost + - Search functionality to filter assets by name + - Status indicators (Available, In Use, Maintenance, Retired) + - Category-based organization (IT Equipment, Software, Office Supplies, etc.) + - Responsive card layout with detailed asset information +- **Mock Data Structure**: Designed to match common asset management API response formats +- **Migration Path**: Structured for easy Copilot-assisted conversion to custom connector calls +- **Target Integration**: Power Platform custom connectors for asset management APIs +- **Reference Documentation**: [How to Create API and Custom Connector](https://github.com/microsoft/PowerAppsCodeApps/blob/FluentSample/docs/how-to-create-api-and-custom-connector.md) +- **Navigation Description**: "Custom API - External service integration and custom connectors" + +### 5. Data Pagination Support +**Purpose**: Efficiently handle large datasets across all examples +- **Implementation**: Follow patterns from [PowerAppsCodeApps Discussion #49](https://github.com/microsoft/PowerAppsCodeApps/discussions/49) +- **Features**: + - **Page-based navigation** (Previous/Next buttons) + - **Page size selection** (10, 25, 50, 100 items per page) + - **Total record count** display + - **Jump to page** functionality + - **Loading states** during page transitions + - **URL parameter support** for shareable paginated views +- **Apply to**: SQL connector example primarily, adaptable to other connectors as needed + +## Technical Requirements + +### UI Framework +- **Fluent UI React v9** for all components +- **Consistent design language** following Microsoft design principles +- **Responsive layout** using Fluent UI's responsive utilities +- **Accessibility compliance** (WCAG 2.1 AA) + +### Navigation Implementation +- **React Router** for client-side routing +- **Breadcrumb navigation** for deep pages +- **Side navigation panel** with collapsible sections +- **Mobile-friendly** hamburger menu for smaller screens + +### State Management +- **React Context** for global app state +- **React Query/TanStack Query** for server state and caching +- **Local state** using React hooks for component-specific data + +### Error Handling +- **Global error boundary** for unhandled errors +- **Toast notifications** for user feedback +- **Retry mechanisms** for failed API calls +- **Graceful degradation** when connectors are unavailable + +### Performance +- **Code splitting** by route/feature +- **Lazy loading** for heavy components +- **Memoization** for expensive computations +- **Virtualization** for large data lists + +## Project Structure +``` +FluentSample/ +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ components/ +β”‚ β”‚ β”œβ”€β”€ Layout.tsx # Main layout with navigation +β”‚ β”‚ β”œβ”€β”€ PageHeader.tsx # Page header component +β”‚ β”‚ β”œβ”€β”€ PaginationComponent.tsx # Data pagination +β”‚ β”‚ └── ThemedApp.tsx # Theme wrapper component +β”‚ β”œβ”€β”€ pages/ +β”‚ β”‚ β”œβ”€β”€ HomePage.tsx # Landing page with app overview +β”‚ β”‚ β”œβ”€β”€ Office365Page.tsx # Office 365 connector demo +β”‚ β”‚ β”œβ”€β”€ SqlPage.tsx # SQL database demo +β”‚ β”‚ └── CustomApiPage.tsx # Custom API connector demo +β”‚ β”œβ”€β”€ hooks/ +β”‚ β”‚ β”œβ”€β”€ usePagination.ts # Reusable pagination logic +β”‚ β”‚ └── useTheme.ts # Theme management hooks +β”‚ β”œβ”€β”€ contexts/ +β”‚ β”‚ β”œβ”€β”€ ThemeContext.ts # Theme context definition +β”‚ β”‚ └── ThemeContext.tsx # Theme provider implementation +β”‚ β”œβ”€β”€ mockData/ # Mock data for development +β”‚ β”‚ β”œβ”€β”€ office365Data.ts # Office 365 mock data +β”‚ β”‚ β”œβ”€β”€ sqlData.ts # SQL mock data +β”‚ β”‚ └── customApiData.ts # Custom API mock data +β”‚ β”œβ”€β”€ assets/ # Static assets and images +β”‚ β”œβ”€β”€ App.tsx # Main app with routing +β”‚ β”œβ”€β”€ main.tsx # Entry point with providers +β”‚ β”œβ”€β”€ PowerProvider.tsx # Power Apps SDK setup +β”‚ β”œβ”€β”€ App.css # Global styles +β”‚ └── index.css # Base styles +β”œβ”€β”€ public/ # Public assets +β”œβ”€β”€ contentMedia/ # Documentation media files +β”‚ └── 1-clone_repo.gif # Setup demonstration GIF +β”œβ”€β”€ .github/ # GitHub metadata +β”‚ β”œβ”€β”€ copilot-instructions.md # Copilot development guidance +β”‚ └── requirements.md # This requirements document +β”œβ”€β”€ README.md # Setup and usage guide +β”œβ”€β”€ package.json # Dependencies and scripts +└── power.config.json # Power Apps configuration +``` + +## User Experience Requirements + +### Landing Page +- **Welcome message** explaining the app's purpose +- **Quick navigation cards** to each example +- **Getting started guide** for developers +- **Links to documentation** and resources + +### Example Pages +- **Clear headings** describing the connector and its capabilities +- **Step-by-step demonstrations** of key features +- **Code snippets** showing implementation details +- **Live data interactions** where possible +- **Error simulation** buttons for testing error handling + +### Documentation Integration +- **Inline help text** referencing the provided documentation links +- **"Learn More" buttons** linking to detailed guides +- **Tooltips** explaining Power Platform concepts +- **Code examples** with copy-to-clipboard functionality + +## Data Requirements + +### Sample Data +- **Mock data** for development when connectors aren't available +- **Test records** for SQL database examples +- **Realistic user scenarios** demonstrating practical use cases + +### Security Considerations +- **No sensitive data** in sample implementations +- **Environment variable** usage for connection strings +- **Error messages** that don't expose internal details +- **Proper authentication** handling for all connectors + +## Success Criteria +1. **Effective Copilot Integration**: GitHub Copilot can successfully guide users from mock data to live connectors +2. **Clear Transition Paths**: Well-documented and AI-friendly code patterns for connector migration +3. **Functional Static Foundation**: Fully working app with realistic mock data as starting point +4. **Power Apps SDK Demonstration**: Clear examples of connector usage patterns +5. **Smooth navigation** between sections and connector examples +6. **Responsive design** that works across all device sizes +7. **Comprehensive documentation** supporting both human and AI-assisted development + +## Implementation Status + +### βœ… Completed +- **Project Structure**: React + TypeScript + Vite foundation ready for connector integration +- **Static App Foundation**: Fully functional app with realistic mock data across all connector types +- **Navigation System**: Complete layout with routing between connector examples +- **Theme System**: Dark/light theme support with context management +- **Copilot-Optimized Code**: GitHub Copilot-friendly patterns with clear TODO markers for migration +- **Mock Data Foundation**: Comprehensive mock data matching real Power Platform API structures +- **Documentation**: Detailed setup guides and connector migration instructions +- **Development Workflow**: Build system, linting, and development environment ready + +### πŸ”„ In Progress / Needs Update +- **Copilot Migration Guidance**: Refining prompts and patterns for optimal AI assistance +- **Power Platform Integration**: Adding more detailed connector integration examples +- **Error Handling**: Expanding error scenarios for live connector integration +- **Performance Optimization**: Enhancing patterns for production-ready connector usage + +### πŸ“‹ Next Steps for Users (with Copilot Assistance) +- **Connect to Office 365**: Use Copilot to replace mock user data with live Office 365 Users connector +- **Integrate SQL Database**: Leverage AI assistance to connect mock CRUD operations to real Azure SQL +- **Setup Custom Connectors**: Use Copilot guidance to replace mock API calls with custom connector integration +- **Environment Configuration**: AI-assisted setup of Power Platform connections and authentication + +## Future Enhancements +- **SharePoint connector** example +- **Dataverse integration** (when supported) +- **Multi-language support** +- **Theme customization** options +- **Advanced filtering** and search capabilities +- **Export functionality** for data views +- **Real-time updates** using SignalR or similar diff --git a/samples/FluentSample/.gitignore b/samples/FluentSample/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/samples/FluentSample/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/samples/FluentSample/README.md b/samples/FluentSample/README.md new file mode 100644 index 0000000..35d51ab --- /dev/null +++ b/samples/FluentSample/README.md @@ -0,0 +1,306 @@ +# 🌟 FluentSample - Power Apps Code Apps Template + +A comprehensive Power Apps Code Apps template showcasing Fluent UI components, navigation patterns, and connector integrations. Built with GitHub Copilot and designed as a learning resource for developers. + +> [!IMPORTANT] +> **πŸ€– AI-Generated Code Notice** +> +> This template was entirely generated using GitHub Copilot to demonstrate AI-assisted development workflows with Power Apps Code Apps. The code has been created for **educational and demonstration purposes only** and has not undergone detailed manual code review or security auditing. +> +> **Please use this sample at your own risk** and ensure proper code review, testing, and security validation before using any patterns or code in production environments. + +## 🎯 What's Included + +This template demonstrates: +- **Office 365 Integration** - User profiles, calendar events, and email management +- **SQL Database Connectivity** - Projects, tasks, and employee data with pagination +- **Custom API Connectors** - Asset management with REST API patterns +- **Modern UI Components** - Fluent UI v9 with responsive design +- **Navigation & Routing** - Multi-page app with sidebar navigation + +## πŸ“‹ Prerequisites + +- **Visual Studio Code** with [Power Platform Tools extension](https://marketplace.visualstudio.com/items?itemName=microsoft-IsvExpTools.powerplatform-vscode) +- **Power Apps environment** with Code Apps enabled - [Create a first release environment](../../README.md#create-a-first-release-power-platform-environment) +- **Node.js** (LTS version) and **npm** +- **Git** for version control +- **Power Apps CLI** (`pac` command available) + +> [!IMPORTANT] +> **Before connecting to real data, be sure to:** +> +> - **Create a connection for your Office 365 account** - [How to connect to data](../../docs/how-to-connect-to-data.md) +> - **Create a connection for your SQL Database** - [How to connect to Azure SQL](../../docs/how-to-connect-to-azure-sql.md) +> - **Create a custom connector and connection** - [How to create sample API and custom connector](../../docs/how-to-create-api-and-custom-connector.md) + +--- + +# Getting Started πŸš€ + +## 1. Clone this repository and open in VS Code + +```bash +git clone https://github.com/microsoft/PowerAppsCodeApps.git +cd PowerAppsCodeApps +code . +``` + +**Important**: Make sure you have the Power Platform Tools extension installed and configured in VS Code: +- Open the Power Platform panel in VS Code (View β†’ Command Palette β†’ "Power Platform") +- Ensure you're **logged in** to your Power Platform account +- Verify the **correct environment** is selected (the one with Code Apps enabled) + +![Git Clone Demo](contentMedia/1-clone_repo.gif) + +## 2. Install dependencies and build + +Open the VS Code terminal (Terminal β†’ New Terminal) and navigate to the FluentSample folder: + +```bash +cd samples/FluentSample +npm install +npm run build +``` + +This ensures the project compiles successfully before running. + +## 3. Initialize Power Apps Code integration + +```bash +pac code init +``` + +This sets up the Power Apps Code integration for local development. + +## 4. Run locally + +```bash +npm run dev +``` + +This will start both Vite dev server and PAC Code Run automatically for local development and testing. + +![Init and run the app locally](contentMedia/2-install_init_run.gif) + +## 5. Deploy to Power Apps (Optional) + +```bash +pac code push +``` + +This deploys your app to the Power Apps environment. If successful, this command will return a Power Apps URL where others can access your app. + +Optionally, you can navigate to https://make.powerapps.com to see the app in the Maker Portal. + +--- + +# πŸ“Š Connecting to Real Data + +This template uses mock data by default. Follow these guides to connect to real data sources: + +## 🏒 How to Connect to Office 365 + +### Prerequisites +- Office 365 business account +- Power Apps environment with Office 365 connectors enabled + +![Prerequisites](contentMedia/copilot_office_prereq.gif) + +### Use GitHub Copilot to connect with Office 365: + +![copilot adding Office 365](contentMedia/copilot_office365.gif) + +#### Manual Steps + +1. **Create Office 365 Connection** + ```bash + # Navigate to Power Apps Maker Portal + # Go to Data > Connections > New Connection + # Select "Office 365 Users", "Office 365 Outlook", etc. + ``` + +2. **Update the Office 365 Page** + + Replace mock data in `src/pages/Office365Page.tsx`: + + ```typescript + // Before (mock data) + import { mockUsers, mockCalendarEvents, mockEmails } from '../mockData/office365Data'; + + // After (real connector) + import { useConnector } from '@pa-client/power-code-sdk'; + + // Use Office 365 connector + const office365 = useConnector('office365users'); + const outlook = useConnector('office365outlook'); + ``` + +3. **Replace Service Calls** + ```typescript + // Example: Get real users + const loadUsers = async () => { + try { + const response = await office365.getUserProfiles(); + setUsers(response.data); + } catch (error) { + console.error('Failed to load users:', error); + } + }; + ``` + +4. **Update Mock Data Structure** + - Review `src/mockData/office365Data.ts` for data structure + - Ensure real API responses match the interface definitions + - Update TypeScript interfaces if needed + +--- + +## πŸ›’οΈ How to Connect to SQL Database + +### Prerequisites +- Azure SQL Database or SQL Server +- SQL connector enabled in your Power Apps environment +- Database connection string and credentials + +### Steps + +1. **Create SQL Connection** + ```bash + # In Power Apps Maker Portal: + # Data > Connections > New Connection > SQL Server + # Enter server details and authentication + ``` + +2. **Update SQL Page** + + Replace mock data in `src/pages/SqlPage.tsx`: + + ```typescript + // Before (mock data) + import { mockProjects, mockTasks, mockEmployees } from '../mockData/sqlData'; + + // After (real connector) + import { useConnector } from '@pa-client/power-code-sdk'; + + const sqlConnector = useConnector('sql'); + ``` + +3. **Replace Database Queries** + ```typescript + // Example: Get real projects with pagination + const loadProjects = async (skip: number = 0, take: number = 10) => { + try { + const response = await sqlConnector.getTable('Projects', { + skip, + take, + orderBy: 'CreatedDate desc' + }); + setProjects(response.data); + setTotalCount(response.totalCount); + } catch (error) { + console.error('Failed to load projects:', error); + } + }; + ``` + +4. **Database Schema Example** + ```sql + -- Projects table + CREATE TABLE Projects ( + Id INT PRIMARY KEY IDENTITY, + Name NVARCHAR(255) NOT NULL, + Description NVARCHAR(MAX), + Status NVARCHAR(50), + CreatedDate DATETIME2 DEFAULT GETDATE(), + DueDate DATETIME2, + AssignedTo INT FOREIGN KEY REFERENCES Employees(Id) + ); + + -- Tasks table + CREATE TABLE Tasks ( + Id INT PRIMARY KEY IDENTITY, + ProjectId INT FOREIGN KEY REFERENCES Projects(Id), + Title NVARCHAR(255) NOT NULL, + Description NVARCHAR(MAX), + Priority NVARCHAR(20), + Status NVARCHAR(50), + AssignedTo INT FOREIGN KEY REFERENCES Employees(Id), + CreatedDate DATETIME2 DEFAULT GETDATE() + ); + ``` + +### πŸ” SQL Operations Available +- **Select**: Query tables with filtering and pagination +- **Insert**: Create new records +- **Update**: Modify existing records +- **Delete**: Remove records +- **Stored Procedures**: Execute custom database logic + +--- + +# πŸ“ Project Structure + +``` +src/ +β”œβ”€β”€ components/ # Reusable UI components +β”‚ β”œβ”€β”€ Layout.tsx # Main layout with navigation +β”‚ β”œβ”€β”€ PageHeader.tsx # Page header component +β”‚ └── PaginationComponent.tsx # Data pagination +β”œβ”€β”€ pages/ # Route components +β”‚ β”œβ”€β”€ HomePage.tsx # Landing page overview +β”‚ β”œβ”€β”€ Office365Page.tsx # Office 365 connector demo +β”‚ β”œβ”€β”€ SqlPage.tsx # SQL database demo +β”‚ └── CustomApiPage.tsx # Custom API connector demo +β”œβ”€β”€ mockData/ # Mock data for development +β”‚ β”œβ”€β”€ office365Data.ts # Office 365 mock data +β”‚ β”œβ”€β”€ sqlData.ts # SQL mock data +β”‚ └── customApiData.ts # Custom API mock data +β”œβ”€β”€ App.tsx # Main app with routing +β”œβ”€β”€ main.tsx # Entry point with providers +└── PowerProvider.tsx # Power Apps SDK setup +``` + +# πŸ›  Technology Stack + +- **React 18** + **TypeScript** - Modern React development +- **Vite** - Fast build tool and dev server +- **Fluent UI v9** - Microsoft design system +- **React Router v6** - Client-side routing +- **TanStack Query v5** - Server state management +- **Power Apps Code SDK** - Power Platform integration + +# πŸ“š Learning Resources + +- [Power Apps Code Apps Docs](https://docs.microsoft.com/power-apps/code-apps) +- [Fluent UI React v9](https://react.fluentui.dev/) +- [Office 365 Connectors](https://docs.microsoft.com/connectors/office365/) +- [SQL Server Connector](https://docs.microsoft.com/connectors/sql/) + +# πŸ’‘ Tips for Development + +## GitHub Copilot Integration +This template was built with GitHub Copilot assistance. For best results: +- Use descriptive comments to guide Copilot +- Leverage Copilot for boilerplate code generation +- Ask Copilot to explain Power Apps patterns + +## Mock Data to Real Data Migration +- Start with mock data to understand patterns +- Replace one connector at a time +- Test thoroughly with real data volumes +- Handle errors and edge cases + +## Performance Optimization +- Use React.memo for expensive components +- Implement proper loading states +- Add error boundaries for robustness +- Consider data caching strategies + +--- + +> [!NOTE] If you get stuck on the "fetching your app" loading screen or see an "App timed out" error screen, double check: +> 1. that you ran `npm run build` +> 2. there are no issues in PowerProvider.tsx +> 3. your environment has the required connectors enabled + +**Congratulations!** You have successfully set up the FluentSample template! πŸŽ‰ diff --git a/samples/FluentSample/SAMPLE-DATA-GENERATOR.md b/samples/FluentSample/SAMPLE-DATA-GENERATOR.md new file mode 100644 index 0000000..6937e6b --- /dev/null +++ b/samples/FluentSample/SAMPLE-DATA-GENERATOR.md @@ -0,0 +1,106 @@ +# Sample Data Generator for Projects Table + +This document provides a script to generate 5,000 sample project records for testing and development purposes. + +## Prerequisites + +Before running this script, you need to have the Projects table created. Follow the setup instructions in the [Azure SQL Connection Guide](https://github.com/microsoft/PowerAppsCodeApps/blob/FluentSample/docs/how-to-connect-to-azure-sql.md) to create the required database schema. + +## Overview + +The sample data generator creates realistic project data with: +- βœ… **5,000 unique project records** +- βœ… **Randomized project names** with sequential numbering +- βœ… **Realistic date ranges** (past and future dates) +- βœ… **Varied statuses** (Planning, Active, On Hold, Completed, Cancelled) +- βœ… **Different priorities** (Low, Medium, High, Critical) +- βœ… **Random budgets** between $10,000 and $500,000 +- βœ… **Rotating project managers** from a pool of sample emails + +## Usage + +### Step 1: Execute the Script + +1. Open your SQL Server Management Studio or Azure Data Studio +2. Connect to your Azure SQL Database +3. Copy and execute the contents of [`generate-sample-data.sql`](./generate-sample-data.sql) + +### Step 2: Monitor Progress + +The script provides progress indicators every 1,000 records: +``` +Generated 1000 records... +Generated 2000 records... +Generated 3000 records... +Generated 4000 records... +Generated 5000 records... +Successfully generated 5000 sample project records! +``` + +### Step 3: Verify Results + +The script automatically verifies the data generation: +```sql +-- Results will show: +TotalRecords: 5003 (3 original + 5000 new) +SampleRecords: 5000 +``` + +## Sample Data Characteristics + +### Project Names +- Base names from a realistic pool (Website Redesign, Mobile App Development, etc.) +- Sequential numbering for uniqueness (e.g., "Website Redesign 1", "API Integration 2500") + +### Date Ranges +- **Start dates**: Random dates within the last year +- **End dates**: Random dates within the next year +- Ensures realistic project timelines + +### Budget Distribution +- **Range**: $10,000 to $500,000 +- **Increment**: Rounded to nearest $100 +- **Distribution**: Evenly distributed across the range + +### Project Managers +- Pool of 10 sample email addresses +- Randomly assigned to ensure variety +- Format: `firstname.lastname@company.com` + +## Cleanup (Optional) + +To remove only the generated sample data while keeping original records: + +```sql +DELETE FROM [dbo].[Projects] +WHERE [CreatedBy] = 'sample-data-generator'; +``` + +## Performance Notes + +- ⚑ **Execution time**: Approximately 30-60 seconds for 5,000 records +- πŸ’Ύ **Memory usage**: Minimal - uses efficient batch processing +- πŸ“Š **Database size**: ~2-3 MB additional storage + +## Troubleshooting + +### Common Issues + +1. **Table doesn't exist** + - Ensure you've run the schema creation script from the [Azure SQL guide](https://github.com/microsoft/PowerAppsCodeApps/blob/FluentSample/docs/how-to-connect-to-azure-sql.md) + +2. **Permission errors** + - Verify your user has INSERT permissions on the Projects table + +3. **Constraint violations** + - The script uses only valid Status and Priority values as defined in the table constraints + +## Integration with FluentSample + +This sample data works perfectly with the FluentSample Power Apps Code App: +- βœ… **SQL Database page** will display all 5,000+ records +- βœ… **Search and filtering** functionality will be more realistic +- βœ… **Performance testing** with substantial data +- βœ… **Pagination** behavior can be properly evaluated + +Ready to test your app with realistic data volume! πŸš€ diff --git a/samples/FluentSample/asset-management-api.json b/samples/FluentSample/asset-management-api.json new file mode 100644 index 0000000..8525064 --- /dev/null +++ b/samples/FluentSample/asset-management-api.json @@ -0,0 +1,107 @@ +{ + "swagger": "2.0", + "info": { + "title": "Asset Management API", + "description": "Simple API for managing assets - tutorial example for Power Platform custom connector", + "version": "1.0.0", + "contact": { + "name": "Asset Management Tutorial", + "url": "https://github.com/microsoft/PowerAppsCodeApps" + } + }, + "host": "[add your api url here]", + "basePath": "/api", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/GetAssets": { + "get": { + "summary": "Get all assets", + "description": "Retrieves a list of all assets in the system", + "operationId": "GetAssets", + "parameters": [], + "responses": { + "200": { + "description": "Successfully retrieved assets", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Asset" + } + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + } + }, + "definitions": { + "Asset": { + "type": "object", + "required": [ + "id", + "name", + "type", + "status" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32", + "description": "Unique identifier for the asset", + "example": 1 + }, + "name": { + "type": "string", + "description": "Name of the asset", + "example": "Laptop" + }, + "type": { + "type": "string", + "description": "Category/type of the asset", + "example": "Electronics", + "enum": [ + "Electronics", + "Furniture", + "Office Supply" + ] + }, + "status": { + "type": "string", + "description": "Current status of the asset", + "example": "Available", + "enum": [ + "Available", + "In Use", + "Maintenance" + ] + } + } + }, + "Error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Error message" + }, + "code": { + "type": "string", + "description": "Error code" + } + } + } + } +} diff --git a/samples/FluentSample/contentMedia/1-clone_repo.gif b/samples/FluentSample/contentMedia/1-clone_repo.gif new file mode 100644 index 0000000..966fc3f Binary files /dev/null and b/samples/FluentSample/contentMedia/1-clone_repo.gif differ diff --git a/samples/FluentSample/contentMedia/2-install_init_run.gif b/samples/FluentSample/contentMedia/2-install_init_run.gif new file mode 100644 index 0000000..b97c5f1 Binary files /dev/null and b/samples/FluentSample/contentMedia/2-install_init_run.gif differ diff --git a/samples/FluentSample/contentMedia/copilot_office365.gif b/samples/FluentSample/contentMedia/copilot_office365.gif new file mode 100644 index 0000000..e6588ee Binary files /dev/null and b/samples/FluentSample/contentMedia/copilot_office365.gif differ diff --git a/samples/FluentSample/contentMedia/copilot_office_prereq.gif b/samples/FluentSample/contentMedia/copilot_office_prereq.gif new file mode 100644 index 0000000..69af592 Binary files /dev/null and b/samples/FluentSample/contentMedia/copilot_office_prereq.gif differ diff --git a/samples/FluentSample/create-projects-table.sql b/samples/FluentSample/create-projects-table.sql new file mode 100644 index 0000000..b148bea --- /dev/null +++ b/samples/FluentSample/create-projects-table.sql @@ -0,0 +1,34 @@ +-- Create the Projects table for the FluentSample demo +-- Execute this script in your Azure SQL Database to create the table and sample data + +-- Create the dbo.Projects table +CREATE TABLE dbo.Projects ( + ProjectId INT IDENTITY(1,1) PRIMARY KEY, + Name NVARCHAR(255) NOT NULL, + Description NVARCHAR(MAX) NULL, + StartDate DATETIME2 NULL, + EndDate DATETIME2 NULL, + Status NVARCHAR(50) NOT NULL, + Priority NVARCHAR(50) NOT NULL, + Budget DECIMAL(18,2) NULL, + ProjectManagerEmail NVARCHAR(255) NOT NULL, + CreatedBy NVARCHAR(255) NOT NULL, + CreatedDate DATETIME2 NOT NULL DEFAULT GETUTCDATE(), + IsActive BIT NOT NULL DEFAULT 1 +); + +-- Insert sample data +INSERT INTO dbo.Projects (Name, Description, StartDate, EndDate, Status, Priority, Budget, ProjectManagerEmail, CreatedBy, IsActive) +VALUES +('Website Redesign', 'Complete overhaul of company website with modern design and improved user experience', '2024-01-15', '2024-06-30', 'Active', 'High', 75000.00, 'alice.johnson@contoso.com', 'system', 1), +('Mobile App Development', 'Native mobile application for iOS and Android platforms', '2024-03-01', '2024-09-15', 'Planning', 'Critical', 120000.00, 'bob.smith@contoso.com', 'system', 1), +('Database Migration', 'Migrate legacy database to cloud infrastructure', '2024-02-01', '2024-05-30', 'Completed', 'Medium', 45000.00, 'carol.davis@contoso.com', 'system', 1), +('Security Audit', 'Comprehensive security assessment and vulnerability testing', '2024-04-01', '2024-07-15', 'On Hold', 'High', 30000.00, 'david.wilson@contoso.com', 'system', 1), +('AI Integration', 'Integrate machine learning capabilities into existing systems', '2024-05-01', '2024-12-31', 'Planning', 'Low', 95000.00, 'eve.brown@contoso.com', 'system', 1), +('Cloud Migration', 'Move on-premises infrastructure to Azure cloud', '2024-06-01', '2024-11-30', 'Active', 'Medium', 150000.00, 'frank.miller@contoso.com', 'system', 1), +('Customer Portal', 'Self-service portal for customers to manage their accounts', '2024-07-01', '2024-10-15', 'Planning', 'High', 80000.00, 'grace.taylor@contoso.com', 'system', 1), +('API Modernization', 'Update legacy APIs to REST and GraphQL standards', '2024-03-15', '2024-08-30', 'Active', 'Medium', 60000.00, 'henry.anderson@contoso.com', 'system', 1); + +-- Verify the data was inserted +SELECT COUNT(*) as TotalProjects FROM dbo.Projects; +SELECT * FROM dbo.Projects ORDER BY ProjectId; diff --git a/samples/FluentSample/eslint.config.js b/samples/FluentSample/eslint.config.js new file mode 100644 index 0000000..d94e7de --- /dev/null +++ b/samples/FluentSample/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { globalIgnores } from 'eslint/config' + +export default tseslint.config([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/samples/FluentSample/generate-sample-data.sql b/samples/FluentSample/generate-sample-data.sql new file mode 100644 index 0000000..344d525 --- /dev/null +++ b/samples/FluentSample/generate-sample-data.sql @@ -0,0 +1,79 @@ +-- ============================================= +-- SAMPLE DATA GENERATOR FOR PROJECTS TABLE +-- ============================================= +-- This script generates 5,000 sample project records +-- for the Projects table created in the Azure SQL setup guide + +SET NOCOUNT ON; + +-- Clear existing sample data (optional) +-- DELETE FROM [dbo].[Projects] WHERE [CreatedBy] LIKE '%sample%'; + +-- Generate 5,000 sample projects +DECLARE @Counter INT = 1; +DECLARE @ProjectNames TABLE (Name NVARCHAR(255)); +DECLARE @Statuses TABLE (Status NVARCHAR(50)); +DECLARE @Priorities TABLE (Priority NVARCHAR(20)); +DECLARE @Managers TABLE (Email NVARCHAR(255)); + +-- Insert sample project names +INSERT INTO @ProjectNames VALUES +('Website Redesign'), ('Mobile App Development'), ('Database Migration'), ('Cloud Infrastructure'), +('API Integration'), ('Security Audit'), ('Performance Optimization'), ('User Experience Update'), +('Data Analytics Platform'), ('E-commerce Enhancement'), ('Customer Portal'), ('Inventory System'), +('HR Management System'), ('Financial Dashboard'), ('Marketing Automation'), ('Quality Assurance'), +('DevOps Pipeline'), ('Machine Learning Model'), ('Blockchain Integration'), ('IoT Implementation'); + +-- Insert statuses +INSERT INTO @Statuses VALUES ('Planning'), ('Active'), ('On Hold'), ('Completed'), ('Cancelled'); + +-- Insert priorities +INSERT INTO @Priorities VALUES ('Low'), ('Medium'), ('High'), ('Critical'); + +-- Insert sample managers +INSERT INTO @Managers VALUES +('sarah.johnson@company.com'), ('mike.chen@company.com'), ('lisa.williams@company.com'), +('david.brown@company.com'), ('emma.davis@company.com'), ('james.wilson@company.com'), +('sophia.miller@company.com'), ('robert.taylor@company.com'), ('olivia.garcia@company.com'), +('william.martinez@company.com'); + +-- Generate records +WHILE @Counter <= 5000 +BEGIN + INSERT INTO [dbo].[Projects] ( + [Name], + [Description], + [StartDate], + [EndDate], + [Status], + [Priority], + [Budget], + [ProjectManagerEmail], + [CreatedBy] + ) + SELECT + CONCAT((SELECT TOP 1 Name FROM @ProjectNames ORDER BY NEWID()), ' ', @Counter), + CONCAT('Sample project description for project ', @Counter, ' with automated data generation'), + DATEADD(day, ABS(CHECKSUM(NEWID())) % 365 * -1, GETDATE()), -- Random date in last year + DATEADD(day, ABS(CHECKSUM(NEWID())) % 365, GETDATE()), -- Random date in next year + (SELECT TOP 1 Status FROM @Statuses ORDER BY NEWID()), + (SELECT TOP 1 Priority FROM @Priorities ORDER BY NEWID()), + ROUND((ABS(CHECKSUM(NEWID())) % 500000 + 10000), -2), -- Random budget 10k-500k + (SELECT TOP 1 Email FROM @Managers ORDER BY NEWID()), + 'sample-data-generator' + ; + + SET @Counter = @Counter + 1; + + -- Progress indicator every 1000 records + IF @Counter % 1000 = 0 + PRINT CONCAT('Generated ', @Counter, ' records...'); +END + +PRINT CONCAT('Successfully generated ', @Counter - 1, ' sample project records!'); + +-- Verify the data +SELECT + COUNT(*) as TotalRecords, + COUNT(CASE WHEN CreatedBy = 'sample-data-generator' THEN 1 END) as SampleRecords +FROM [dbo].[Projects]; diff --git a/samples/FluentSample/implementation-plan.md b/samples/FluentSample/implementation-plan.md new file mode 100644 index 0000000..1b964d6 --- /dev/null +++ b/samples/FluentSample/implementation-plan.md @@ -0,0 +1,317 @@ +# FluentSample Implementation Plan + +## Overview +This plan outlines the implementation of the FluentSample Power Apps Code App - a **static template project** with navigation and connector UI examples using mock data. The goal is to create a complete, functional app that others can clone and extend with their own data connectors for learning purposes. + +**Key Goal**: Create a committable template that demonstrates Power Apps Code Apps best practices, which developers can use as a starting point to add their own live connectors. + +## Phase 1: Project Foundation (Setup & Architecture) + +### 1.1 Project Initialization & Vite Setup (Following copilot-instructions.md) +- [x] **Create Vite Project** + - Run `npm create vite@latest FluentSample -- --template react-ts` + - Navigate to project: `cd FluentSample` + - Install base dependencies: `npm install` + +- [x] **CRITICAL React Version Downgrade** + - **MUST downgrade to React 18.2.0**: `npm install react@^18.2.0 react-dom@^18.2.0` + - This ensures Power Apps Code SDK compatibility + +- [x] **Install Power Apps SDK (Local Version)** + ```bash + # Use your local Power Apps SDK file (new version) + npm install ./PowerAppsSDK/7-16-pa-client-power-code-sdk-0.0.1\ 1.tgz + ``` + +- [x] **Configure Vite for Power Apps** + Update `vite.config.ts`: + ```typescript + import { defineConfig } from 'vite' + import react from '@vitejs/plugin-react' + import path from "path"; + + export default defineConfig({ + base: "./", + server: { + host: "::", + port: 3000, + }, + plugins: [react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + }); + ``` + +- [x] **Update Package.json Scripts** + ```json + { + "scripts": { + "dev": "start vite && start pac code run", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + } + } + ``` + +- [x] **Install Core Dependencies (Static Development First)** + ```json + { + "@fluentui/react-components": "^9.54.0", + "@fluentui/react-icons": "^2.0.0", + "react-router-dom": "^6.26.0", + "@tanstack/react-query": "^5.56.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "typescript": "^5.8.3" + } + ``` + +### 1.2 Static App Development with Mock Data +- [x] **PowerProvider Setup in main.tsx** + - Wrap App with PowerProvider + - Configure FluentProvider with webLightTheme + - Set up QueryClient for TanStack Query + +- [x] **Create Mock Data Files** + - `src/mockData/office365Data.ts` - User profiles, calendar, emails + - `src/mockData/sqlData.ts` - Projects, tasks, relationships + - `src/mockData/customApiData.ts` - Asset management data + - `src/mockData/paginationData.ts` - Large datasets (100+ items) + +- [x] **Build Static UI Components** + - Navigation system with static routes + - Connector example pages using mock data + - Pagination components with mock datasets + - Responsive layout and components + +- [x] **Project Structure Setup** + - Create folder structure as defined in requirements + - Set up ESLint and Prettier configurations + - Configure path aliases for imports + +### 1.3 Core Architecture Components (Static Phase) +- [x] **Theme and Design System** + - Configure Fluent UI theme + - Set up responsive breakpoints + - Create design tokens for consistency + +- [x] **Static Navigation System** + - Set up React Router with static routes + - Create navigation components + - Implement responsive mobile navigation + +- [x] **Mock Data Integration** + - Connect components to mock data sources + - Implement pagination with static datasets + - Create realistic data relationships + +### 1.4 Static Template Success Criteria +- [x] Project builds and runs with `npm run dev` +- [x] React 18.2.0 compatibility confirmed +- [x] PowerProvider and FluentProvider properly configured +- [x] Complete navigation between all pages works with mock data +- [x] All Fluent UI components render correctly +- [x] Pagination works with static datasets +- [x] TypeScript compilation is error-free +- [x] App is fully functional as a learning template +- [x] Clear code structure for others to extend with real connectors +- [x] Comprehensive mock data that demonstrates realistic scenarios + +**Template Goal**: Provide a complete, working app that developers can use to learn Power Apps Code Apps patterns and replace mock data with real connectors. + +## Phase 2: Navigation & Layout System + +### 2.1 Complete Navigation Infrastructure +- [x] **React Router Setup** + - Configure all route definitions for connector examples + - Implement 404 handling with helpful messages + - Add route descriptions for learning purposes + +- [x] **Navigation Components** + - `NavigationMenu` - Main navigation with clear descriptions + - `SideNavigation` - Collapsible side panel with icons + - `Breadcrumbs` - Page hierarchy for easy navigation + - `MobileMenu` - Responsive hamburger menu + +### 2.2 App Layout & Theme +- [x] **Complete App Layout** + - Header with app title and navigation + - Side navigation panel with connector examples + - Main content area with consistent spacing + - Footer with learning resources + +- [x] **Responsive Design** + - Mobile-first approach for all screen sizes + - Tablet and desktop breakpoints + - Touch-friendly interactions throughout + +## Phase 3: Static Connector Example Pages + +### 3.1 Home & Welcome Page +- [x] **Landing Experience** + - Welcome section explaining the template purpose + - Overview of available connector examples + - Getting started guide for developers + - Link to documentation and setup instructions + +### 3.2 Office 365 Example Page (Static) +- [x] **Office 365 Mock UI** + - User profile display with mock data + - Calendar events list with sample entries + - Email messages preview + - Contact directory with search + - **Clear indicators** that data is mocked + - **Code comments** showing where to add real connectors + +### 3.3 SQL Database Example Page (Static) +- [x] **SQL Mock UI** + - Data grid with sortable columns + - CRUD operation forms (mock actions) + - Search and filter functionality + - Pagination with large mock datasets + - **Placeholder areas** for real database connections + - **Code structure** ready for SQL connector integration + +### 3.4 Custom API Example Page (Static) +- [x] **Custom API Mock UI** + - API response display with formatted JSON + - Different HTTP method examples (GET, POST, PUT, DELETE) + - Request/response visualization + - Error handling scenarios with mock errors + - **Template structure** for custom connector integration + +## Phase 4: Shared Components & Documentation + +### 4.1 Reusable Components for Learning +- [x] **Essential Components** + - `LoadingSpinner` - Consistent loading states + - `ErrorBoundary` - Error handling wrapper + - `ToastNotification` - User feedback system + - `ConfirmDialog` - Deletion confirmations + - `CodeSnippet` - Copy-to-clipboard code examples + +### 4.2 Pagination System (Template) +- [x] **Pagination Components** + - `PaginationControls` - Navigation buttons + - `PageSizeSelector` - Items per page + - `PageInfo` - Current page display + - `usePagination` hook - Reusable pagination logic + - **Mock data integration** showing how to implement with real data + +### 4.3 Developer Learning Resources +- [x] **Inline Documentation** + - Code comments explaining Power Apps patterns + - TypeScript interfaces showing data structures + - Examples of how to replace mock data with real connectors + - Best practices documentation in README + +## Phase 5: Mock Data & Template Structure + +### 5.1 Comprehensive Mock Data +- [x] **Realistic Mock Datasets** + - `office365Data.ts` - Users, calendar, emails (50+ entries) + - `sqlData.ts` - Projects, tasks, relationships (100+ entries) + - `customApiData.ts` - Asset management data (varied responses) + - `paginationData.ts` - Large datasets for pagination testing + +### 5.2 Template Code Structure +- [x] **Connector Integration Points** + - Clear separation between UI and data layers + - Hooks ready for real connector implementation + - Service layer architecture for easy data source swapping + - Error handling patterns for connector failures + +## Phase 6: Final Polish & Documentation + +### 6.1 Template Finalization +- [x] **Code Quality & Consistency** + - ESLint/Prettier configuration + - TypeScript strict mode compliance + - Consistent naming conventions + - Clean, readable code structure + +### 6.2 Learning Documentation +- [x] **Comprehensive README** + - Quick start guide + - How to replace mock data with real connectors + - Power Apps Code Apps best practices + - Common patterns and examples + - Troubleshooting guide + +### 6.3 Accessibility & Polish +- [x] **Production Ready Template** + - Accessibility compliance (WCAG 2.1 AA) + - Responsive design on all devices + - Performance optimization + - Error handling throughout + +## Implementation Timeline + +### Week 1: Static Foundation & Navigation (Phases 1-2) βœ… COMPLETED +- **Phase 1**: Vite setup with Power Apps SDK and complete project structure +- **Phase 2**: Full navigation system and responsive layout + +### Week 2: Connector Example Pages (Phase 3) βœ… COMPLETED +- **Phase 3**: All connector example pages with comprehensive mock data and UI + +### Week 3: Components & Polish (Phases 4-6) βœ… COMPLETED +- **Phase 4**: Shared components and pagination system +- **Phase 5**: Comprehensive mock data and template structure +- **Phase 6**: Final polish, documentation, and accessibility + +**Final Goal**: A complete, production-ready template that developers can clone, run immediately, and use as a learning foundation to add their own Power Apps connectors. + +## Template Success Metrics + +### Learning Template Metrics +- [x] **Immediate usability**: `npm install && npm run dev` works out of the box +- [x] **Complete functionality**: All features work with mock data +- [x] **Clear code structure**: Easy to understand and extend +- [x] **Comprehensive examples**: Covers all major connector patterns +- [x] **Good documentation**: README explains how to add real connectors +- [x] **Accessibility compliant**: WCAG 2.1 AA standards +- [x] **Mobile responsive**: Works on all device sizes +- [x] **Zero errors**: Clean TypeScript compilation +- [x] **Performance optimized**: Fast loading and smooth interactions + +### Educational Value +- [x] Demonstrates Power Apps Code Apps best practices +- [x] Shows proper Fluent UI implementation +- [x] Illustrates pagination and data management patterns +- [x] Provides clear separation between UI and data layers +- [x] Includes comprehensive inline documentation + +## Template Benefits + +### For Developers +- **Quick Start**: Complete working app to learn from +- **Best Practices**: Follows Microsoft recommended patterns +- **Extensible**: Easy to replace mock data with real connectors +- **Modern Stack**: Uses latest Fluent UI v9, React Router, TypeScript + +### For Learning +- **Comprehensive Examples**: Office 365, SQL, and Custom API patterns +- **Realistic Scenarios**: Mock data that represents real-world use cases +- **Code Documentation**: Inline comments explaining Power Apps concepts +- **Progressive Enhancement**: Shows how to build static-first, then add connectors + +## Next Steps to Complete Template +1. βœ… **Phase 1**: Set up Vite project with Power Apps SDK +2. βœ… **Phase 2**: Build navigation and layout system +3. βœ… **Phase 3**: Create all connector example pages with mock data +4. βœ… **Phase 4**: Implement shared components and pagination +5. βœ… **Phase 5**: Create comprehensive mock datasets +6. βœ… **Phase 6**: Final polish and documentation +7. βœ… **Commit**: Push complete template to repository for others to use + +## πŸŽ‰ IMPLEMENTATION COMPLETE! + +**Status**: The FluentSample template is now fully implemented and ready for use as a learning resource. + +--- + +*This template provides developers with a complete, functional Power Apps Code App that demonstrates best practices and serves as a foundation for building their own connector integrations.* diff --git a/samples/FluentSample/index.html b/samples/FluentSample/index.html new file mode 100644 index 0000000..c174f5f --- /dev/null +++ b/samples/FluentSample/index.html @@ -0,0 +1,13 @@ + + + + + + + Power Apps Code Sample + + +
+ + + diff --git a/samples/FluentSample/package-lock.json b/samples/FluentSample/package-lock.json new file mode 100644 index 0000000..fe0b6ea --- /dev/null +++ b/samples/FluentSample/package-lock.json @@ -0,0 +1,5282 @@ +{ + "name": "fluentsample", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fluentsample", + "version": "0.0.0", + "dependencies": { + "@fluentui/react-components": "^9.67.0", + "@fluentui/react-icons": "^2.0.306", + "@pa-client/power-code-sdk": "https://github.com/microsoft/PowerAppsCodeApps/releases/download/v0.0.3/7-16-pa-client-power-code-sdk-0.0.1.1.tgz", + "@tanstack/react-query": "^5.83.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.30.1" + }, + "devDependencies": { + "@eslint/js": "^9.30.1", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.6.0", + "eslint": "^9.30.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.35.1", + "vite": "^7.0.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "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/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@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-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "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==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.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==", + "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==", + "dev": true, + "license": "MIT", + "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.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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/@esbuild/aix-ppc64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", + "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", + "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", + "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", + "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", + "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", + "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", + "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", + "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", + "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", + "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", + "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", + "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", + "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", + "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", + "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", + "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", + "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", + "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", + "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", + "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", + "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", + "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", + "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", + "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", + "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", + "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "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": "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": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", + "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "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/@eslint/plugin-kit": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.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" + } + }, + "node_modules/@floating-ui/devtools": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.1.tgz", + "integrity": "sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==", + "peerDependencies": { + "@floating-ui/dom": ">=1.5.4" + } + }, + "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/@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/@fluentui/keyboard-keys": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.8.tgz", + "integrity": "sha512-iUSJUUHAyTosnXK8O2Ilbfxma+ZyZPMua5vB028Ys96z80v+LFwntoehlFsdH3rMuPsA8GaC1RE7LMezwPBPdw==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/priority-overflow": { + "version": "9.1.15", + "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.1.15.tgz", + "integrity": "sha512-/3jPBBq64hRdA416grVj+ZeMBUIaKZk2S5HiRg7CKCAV1JuyF84Do0rQI6ns8Vb9XOGuc4kurMcL/UEftoEVrg==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-accordion": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.8.0.tgz", + "integrity": "sha512-YHvTZCdARlDKF69qt3nQc+Q4N3uFTUDmZGg97/H+HZAbpTlwnQVsw//y860M828d5SMyvutNm6BGqpsb+XBudw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-motion": "^9.9.0", + "@fluentui/react-motion-components-preview": "^0.7.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-alert": { + "version": "9.0.0-beta.124", + "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.124.tgz", + "integrity": "sha512-yFBo3B5H9hnoaXxlkuz8wRz04DEyQ+ElYA/p5p+Vojf19Zuta8DmFZZ6JtWdtxcdnnQ4LvAfC5OYYlzdReozPA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-avatar": "^9.6.29", + "@fluentui/react-button": "^9.3.83", + "@fluentui/react-icons": "^2.0.239", + "@fluentui/react-jsx-runtime": "^9.0.39", + "@fluentui/react-tabster": "^9.21.5", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.10", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-aria": { + "version": "9.15.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.15.4.tgz", + "integrity": "sha512-5t/BrCQOWz3ZAbCy6RHN3iT3+MiwbHe3ESZXoxSquxVJzBjDixuvzhnls83cqC86OaWi2fp2kI8e3/BvLA54+Q==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-utilities": "^9.22.0", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-avatar": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.9.0.tgz", + "integrity": "sha512-2KWRkz7khP42ROD/thdID+dHhyCz8irQp37pD3pyLRAZe7Su1ckkjbaSB3aBl3ee0rmVq8vQmyulshsGZkyFJg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-badge": "^9.4.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-popover": "^9.12.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-tooltip": "^9.8.0", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-badge": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.4.0.tgz", + "integrity": "sha512-FS12bACA0i5YFwTjYT1aF0NBSoNgPdZTNXM/MqJpqOq6UyCylRf75ro06a0LduU671gB578Ap+yzk8E3+Ia9NQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-breadcrumb": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.3.0.tgz", + "integrity": "sha512-t8EAbhyO/wFJAzEr921Oag0yrkKcX6zprqzJ1dybWv8ndyjbJdQcut0fkOeMwmXCgu3MoBirW27s+4gHODwidw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-link": "^9.6.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-button": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.6.0.tgz", + "integrity": "sha512-rsSGqJrXs4NL8Lo/2BCDEGYZrGj3Kkg2crVYnG3xBC2GMFGmlww+ovsIUcWhMo6KRY87F8dyqUcqX1g+HJNv/A==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-card": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.4.0.tgz", + "integrity": "sha512-hH862zMzVVS1BRE2UGH8ZrLT0z1yLg4LRn4L8onEfCAKj5E65o+trGH4T6c0TOLexNyJKeF6bqrQDUtbT35pIA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-text": "^9.6.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-carousel": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-carousel/-/react-carousel-9.8.0.tgz", + "integrity": "sha512-6BRHOSzaY7gkSvktaHBfa3FE/Tdmjel0o1lrR0Zl1D0kdbUDtY8ICb0FtROJ4YLSE2YyLWmAMlR3MbxKWPmCcw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-tooltip": "^9.8.0", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "embla-carousel": "^8.5.1", + "embla-carousel-autoplay": "^8.5.1", + "embla-carousel-fade": "^8.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-checkbox": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.5.0.tgz", + "integrity": "sha512-HB4zac4C0Msqbrjl7AOTuEMnmpEyKeNTaKc8eb9MDU8xJVWzWS5Q91TWpmXOXgneaG3/pu5ops749zBmlCU1Pg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-label": "^9.3.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-color-picker": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-color-picker/-/react-color-picker-9.2.0.tgz", + "integrity": "sha512-4E6woOMxj4Tyy0sHAORR8pGUlZbtoGgQ6UsdQ38SWEU+f/zo/2SsyJOqtuMur67+ThAoJR5bq+W3mLGi8WhAPA==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.3.4", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-combobox": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.16.0.tgz", + "integrity": "sha512-w84o5ubLL4MCfbzb/xCRoWjc1S2ZGk0Ci8PEXkP+CFAl3SxAORJISAiMCbfk+ZoWAwNLFcHNO6UFj2XH+fWkbA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-positioning": "^9.20.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-components": { + "version": "9.67.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.67.0.tgz", + "integrity": "sha512-692/t+6te3HO0/tA5585CrA9FA6AIR7a6UVJ/p6Cah0cwRfi/ffeNYZ5fhZHX/46DU0SRfAXemcsoFE1cgKpYA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-accordion": "^9.8.0", + "@fluentui/react-alert": "9.0.0-beta.124", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-avatar": "^9.9.0", + "@fluentui/react-badge": "^9.4.0", + "@fluentui/react-breadcrumb": "^9.3.0", + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-card": "^9.4.0", + "@fluentui/react-carousel": "^9.8.0", + "@fluentui/react-checkbox": "^9.5.0", + "@fluentui/react-color-picker": "^9.2.0", + "@fluentui/react-combobox": "^9.16.0", + "@fluentui/react-dialog": "^9.14.0", + "@fluentui/react-divider": "^9.4.0", + "@fluentui/react-drawer": "^9.9.0", + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-image": "^9.3.0", + "@fluentui/react-infobutton": "9.0.0-beta.102", + "@fluentui/react-infolabel": "^9.4.0", + "@fluentui/react-input": "^9.7.0", + "@fluentui/react-label": "^9.3.0", + "@fluentui/react-link": "^9.6.0", + "@fluentui/react-list": "^9.3.0", + "@fluentui/react-menu": "^9.19.0", + "@fluentui/react-message-bar": "^9.6.0", + "@fluentui/react-motion": "^9.9.0", + "@fluentui/react-nav": "^9.3.0", + "@fluentui/react-overflow": "^9.5.0", + "@fluentui/react-persona": "^9.5.0", + "@fluentui/react-popover": "^9.12.0", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-positioning": "^9.20.0", + "@fluentui/react-progress": "^9.4.0", + "@fluentui/react-provider": "^9.22.0", + "@fluentui/react-radio": "^9.5.0", + "@fluentui/react-rating": "^9.3.0", + "@fluentui/react-search": "^9.3.0", + "@fluentui/react-select": "^9.4.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-skeleton": "^9.4.0", + "@fluentui/react-slider": "^9.5.0", + "@fluentui/react-spinbutton": "^9.5.0", + "@fluentui/react-spinner": "^9.7.0", + "@fluentui/react-swatch-picker": "^9.4.0", + "@fluentui/react-switch": "^9.4.0", + "@fluentui/react-table": "^9.18.0", + "@fluentui/react-tabs": "^9.9.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-tag-picker": "^9.7.0", + "@fluentui/react-tags": "^9.7.0", + "@fluentui/react-teaching-popover": "^9.6.0", + "@fluentui/react-text": "^9.6.0", + "@fluentui/react-textarea": "^9.6.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-toast": "^9.6.0", + "@fluentui/react-toolbar": "^9.6.0", + "@fluentui/react-tooltip": "^9.8.0", + "@fluentui/react-tree": "^9.12.0", + "@fluentui/react-utilities": "^9.22.0", + "@fluentui/react-virtualizer": "9.0.0-alpha.100", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-context-selector": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.2.2.tgz", + "integrity": "sha512-R9710dBH2AYNbdQz0UpvSqoA8YZ8vVicyqGvWPKvDGCNbZB6GY1Cu5LbODpeAthylLXhgXxIlGEcoOpjBBpRbA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.22.0", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-dialog": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.14.0.tgz", + "integrity": "sha512-FgvxWVwET9niVhWoD1gpEx7MICOCDncTyreJV12KmCVC0eYxvun0uQmA6FXVnh+3yh/9AhIH0KfiKa0C8qsP7g==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-motion": "^9.9.0", + "@fluentui/react-motion-components-preview": "^0.7.0", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-divider": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.4.0.tgz", + "integrity": "sha512-WLs/12FP7Yf+SYCISzxGaNbLvJjZyBcUFbG9KhhRmt5CcwIklTinEJWW3qXcAmS+nHuGdkwpgC/avgEjzpYMcg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-drawer": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.9.0.tgz", + "integrity": "sha512-HjW13Tikmk7s/XUKGoYn6MKsvm9gmO6Og8h3PtcWIccsXBUesQtWAgNJpgvprEDKHFwLF5aB1fHqYDsStbrLCw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-dialog": "^9.14.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-motion": "^9.9.0", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-field": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.4.0.tgz", + "integrity": "sha512-X4XWe1gWVxUP6Oa395Ekpdtj9FX2WAWPj5+DGW8OGB7SNJA67cEP/E8FCEA/tflm0eZXaHVFThh0yElf1KX7nw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-label": "^9.3.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-icons": { + "version": "2.0.306", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.306.tgz", + "integrity": "sha512-zS66O59F8gvwjaaIchguMVTwmI3qplwJrm5F8c17rfdrqtFhJKMM2Udef6DWHA7XtnQA8OfvYz2GGrE+GBy/KA==", + "license": "MIT", + "dependencies": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-image": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.3.0.tgz", + "integrity": "sha512-qhKZ6Dj267UPvnAwzmvLD3JDb8zSCEtkL2c9CLyUAcuuvT4KubhNsLudY//1EMiC5a+Du0gC2lcxRT84PQ2NZg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infobutton": { + "version": "9.0.0-beta.102", + "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.102.tgz", + "integrity": "sha512-3kA4F0Vga8Ds6JGlBajLCCDOo/LmPuS786Wg7ui4ZTDYVIMzy1yp2XuVcZniifBFvEp0HQCUoDPWUV0VI3FfzQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.237", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-popover": "^9.9.6", + "@fluentui/react-tabster": "^9.21.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infolabel": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.4.0.tgz", + "integrity": "sha512-ABSzkV/FN0TfKRXbarb+/dWihgKpqDeS5YWf69pCeXg7s+Ls3UQn/7+mgBjHcMOoRpbqW45bOzCoC+6Iqb2ggg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-label": "^9.3.0", + "@fluentui/react-popover": "^9.12.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-input": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.7.0.tgz", + "integrity": "sha512-rJCVaVnAidVtp//DQFaz1vHMbiNVcxZPjvZ9xfIpdRjFk+kSEkcRj1AT/iCMqwTXhJb9hYIMJRE+gPQoTiQYdQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.1.2.tgz", + "integrity": "sha512-igGuh0P7Gd09Kk3g6JwjnaRIRk+mluCbpf+KcAUde6bxZ/5qB50HGX+DOGWa3+RPd5240+HLBxpT3Y985INgqw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.22.0", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-label": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.3.0.tgz", + "integrity": "sha512-HRSi4TBEjkJoeNZ9FOL8VPnOwrKrJp5drd1f00cICwRz7cimSZt56C97BwM9IB41nEdF3Yk3MLd4Hea1PO+Msg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-link": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.6.0.tgz", + "integrity": "sha512-2G+IWuT98pt1HwJWuL9VuTQesUdYjDooK/LPUOsXaVwwGP71lKBXQ6B7ZBw5bqDt3dwborTugyG6RlD7aDpPbw==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-list": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-list/-/react-list-9.3.0.tgz", + "integrity": "sha512-OsYz2ULKXnFEExZW8FaUk1+cjPcFIrtRlwytKDAnRvwyBLIhhQezRWWTEVpc2M75NmZbkZtqyDujdB/ZdSlOmA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-checkbox": "^9.5.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-menu": { + "version": "9.19.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.19.0.tgz", + "integrity": "sha512-Wy/8DaHXEtntJk2onVWZI19AHIJkAJB9gXjXrKFk4DbSX0n9Brj06dBu9lZzl5q4i7cUQhg9sMayle3ovspX6w==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-positioning": "^9.20.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-message-bar": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.6.0.tgz", + "integrity": "sha512-sGVd+wK2NsiHBcGl1Pw3P4LJW50hbaN4+4NA5udCwbtIW97lO2zMFJtROU+oBYkmV0HbJ9jSxOYyeMmndjKjAQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-link": "^9.6.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion/-/react-motion-9.9.0.tgz", + "integrity": "sha512-xgm/CkU1UvemooplEFKJL9mfGJFvzId2DJ1WYTFAa5TSZMtzOAZuPuwS/PrPNFuwjnhvCMShDj8zazgvR5i37A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-utilities": "^9.22.0", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion-components-preview": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.7.0.tgz", + "integrity": "sha512-vGxi2KLqwCzfV2WSZBYGKSzKnfsnGKjkQpE5qYfwk0aPp3iDXtyiLCANgNiPKIBJ4R+/48SAbIDKaiXBtd7GRw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-motion": "*", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-nav": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-nav/-/react-nav-9.3.0.tgz", + "integrity": "sha512-IodGcAPlH45pNskmPmFsXF8IGGrRAEcd4PrytdAPFhBx0Ov69uvoI1B7mCTDGYYb0g8KRW751rGJtU4QMgUAUw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-divider": "^9.4.0", + "@fluentui/react-drawer": "^9.9.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-motion": "^9.9.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-tooltip": "^9.8.0", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-overflow": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.5.0.tgz", + "integrity": "sha512-XIJ2WGNiSs4KER5GIV9iMQA/lGVSR2eE+Aeht+hGiwlmn/YvTvS5SM/LSw2CKyi1LkVRzNB3Kj1wiIzD/he5+Q==", + "license": "MIT", + "dependencies": { + "@fluentui/priority-overflow": "^9.1.15", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-persona": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.5.0.tgz", + "integrity": "sha512-0MnNTqrJ3BxTXvg+NdLE9mabSmLFVKiuqdIAtK/gYFiEk43wGskMUx9Kw1Dfq6xRYQImaFnoLhd+47YsLyn9jg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-avatar": "^9.9.0", + "@fluentui/react-badge": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-popover": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.12.0.tgz", + "integrity": "sha512-qnPwYW3E63jLTaVB7ssbTVE9ez04eNmky7SjdD2MlU6F2506nuV5V7wPp3Z5LZpD6SQqgMjtPiTlcFgWHAjAvw==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-positioning": "^9.20.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-portal": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.7.0.tgz", + "integrity": "sha512-g9Q9wsw4OH4UFYyjb5BfbL7GwaloIiFMVZXie9q0lLeo9JUFhNHh/2X7UUGesagCO86WMGN1haQUA7uaN6gIXA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-disposable": "^1.0.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-positioning": { + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.20.0.tgz", + "integrity": "sha512-qbxIYG8N+zBVXsgyiqd8kQzDiEn+eabnDBn3hqhaolVqn3QVWfgjoARJXYuKbUY0GDMPMukW1PH2NbEl5BvQXQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/devtools": "0.2.1", + "@floating-ui/dom": "^1.6.12", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-progress": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.4.0.tgz", + "integrity": "sha512-EplT3K95DPob22MV0mIzLmbzsdS2bhMPEiRjUAsRpUPnw5gRJi4OKneS5y3mRCBUiFjlkzEDwTTbEa+NkZEXlg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-provider": { + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.22.0.tgz", + "integrity": "sha512-dyrux/z+OXTM9U0uaq/AHtSI/5jZsehw3LND79StMP11ebi9lGjyRthZ3M8E6Pq7LlSgQ0yVnMFYZc9WoijVHg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/core": "^1.16.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-radio": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.5.0.tgz", + "integrity": "sha512-9j4t85KdIYu5TN3tN1S2KlIfzL4FNYRuFBsQ8WxB0F8vmGlyIxUt9S2dRG3+MScqOwIS2Q0HAmZhu0hrTJVWRg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-label": "^9.3.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-rating": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-rating/-/react-rating-9.3.0.tgz", + "integrity": "sha512-FP19VCBG3aQm7uP/pORfDBKHU/f5YinvETe39y4+9VPiXlgbF+sqjwXGB6N7kvu9ZdTD4ZFrMW4FaSLYrpJEtA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-search": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-search/-/react-search-9.3.0.tgz", + "integrity": "sha512-RMzYhNdrLpz5/e6Z3NlDmX7KP+AXz0N0e4SBoKjHauoDfEPD9+oHbSbah/JQWmw290h1jUUrElRwPYoIQ8eSgg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-input": "^9.7.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-select": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.4.0.tgz", + "integrity": "sha512-6DoC6Xc6hkHKCzRFjB2UYbJAa3v+KZ/OUML18OvYvdGkEtv+n2x3sc+mUDgFuXHqB/4OIhUDXq4S/Mriwd8KUg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-shared-contexts": { + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.24.0.tgz", + "integrity": "sha512-GA+uLv711E+YGrAP/aVB15ozvNCiuB2ZrPDC9aYF+A6sRDxoZZG8VgHjhQ/YWJfVjDXLky4ihirknzsW1sjGtg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-theme": "^9.1.24", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-skeleton": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.4.0.tgz", + "integrity": "sha512-n6viQkyI+g7ljf33x/6FVwNfyfJq6Qosug5OlxsSTrneyn+kSb6lw8K4z3AUIEBOR65XEonYWegXOm4ldcJYOw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-slider": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.5.0.tgz", + "integrity": "sha512-qxLRYBKKEbRuKdHzE0iSpETvjYKGjIK4Rm18swFd5Jl4SfXUxaq6EuHRE1sfiOhraH2nDSKHVT+iXZxYi/g+Tg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinbutton": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.5.0.tgz", + "integrity": "sha512-rRdgwNb0yNJOeCwbr6Kn1VX+ys+4PEfl6bwHphXy/6iwbF7BETtZjmGGbfXhuu+WsLxQxHnyeo5uC21E/mbWqg==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinner": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.7.0.tgz", + "integrity": "sha512-B9KQ6Muy2KZIBpmzkdZ0ONu4Ao/3iMhBous1Emq7wfiYEhoz1pOLKvVgh+IgXz5SX28x8cZiDt9/Hu7Quf6zJg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-label": "^9.3.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-swatch-picker": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-swatch-picker/-/react-swatch-picker-9.4.0.tgz", + "integrity": "sha512-KSeIvU/fwBeXP5irqQxSvs34LNu03a3NYF48GOJrDODUwv/tjYn+/IgsPRMjA2pZ502AMWFa5OSKpeUJ9mbi1g==", + "license": "MIT", + "dependencies": { + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-switch": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.4.0.tgz", + "integrity": "sha512-8uKP2aM/doLGprYuljbJAbAapeVWbgMW1FLQH53+RHURZNy1Gvt8AiisllJwtmQC8esgK4xlbaSzn/b1/S8B8A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-label": "^9.3.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-table": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.18.0.tgz", + "integrity": "sha512-yBdBvY5X/XnX5WYoFseKlqc0pYomBZ+3jFaMEeWMYxOAIuHWif3IUq4kTxBoweKcFMmclMNMpY22j/6YcFwHXA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-avatar": "^9.9.0", + "@fluentui/react-checkbox": "^9.5.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-radio": "^9.5.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tabs": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.9.0.tgz", + "integrity": "sha512-V06heimvtH5LcjjePkl8ETWrX4YN1V2STQhFr6lXn6FjS8nsNGhWemHduCi2qY3DLyZgYLBGrOR5AgSbbv5jcA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tabster": { + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.26.0.tgz", + "integrity": "sha512-ENaISUye53JLvAN3VqiKzTdDSubnMucG/mcGuB+QbnzTLGIHxvEYq/GV4WHwWbQwjZPXAG9Hr0F0l0AFzrkeFA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "keyborg": "^2.6.0", + "tabster": "^8.5.5" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tag-picker": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tag-picker/-/react-tag-picker-9.7.0.tgz", + "integrity": "sha512-p0xAxemN/fYlDG6dVbkcGybjMCiNravyzTsnpE2OwEoh3eDfsL5oXipPkcJACzv5ZhmavVyAHs4txenEcW24gw==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-combobox": "^9.16.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-positioning": "^9.20.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-tags": "^9.7.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tags": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.7.0.tgz", + "integrity": "sha512-TU7CPouGFuOXxGVjrbWbLgyTNrVoyxOS3xvwdZGJuGlaU9FbFuzKNUeV/CL0o6SiA/0O1wGa4/VV6XRuUGQX3Q==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-avatar": "^9.9.0", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-teaching-popover/-/react-teaching-popover-9.6.0.tgz", + "integrity": "sha512-/JX1+W/ff8bkO1nCSExL9ASP1zfysUInc83V/6XzRgwhyNMkUoNgGRw32EDpxz6Ympe8mZnQKWNUmvTsxr28aQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-popover": "^9.12.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-text": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.6.0.tgz", + "integrity": "sha512-/ZAMjgAn5sgbAjYnwmM5k0kxgNehpccxXI6f5uJ72IfAmj85dMH4TDNsN6xOCIMhj+xDxuBIT4axEYt+wAoF1Q==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-textarea": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.6.0.tgz", + "integrity": "sha512-o6jAAB4cIzzPLBj8/RDo+my7yXSQtFCC+O2p4mD2X+hUvBCydoQI+45RbEeJXXwEsWjUp7XfbLUyt3mB8dH0xQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-theme": { + "version": "9.1.24", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.24.tgz", + "integrity": "sha512-OhVKYD7CMYHxzJEn4PtIszledj8hbQJNWBMfIZsp4Sytdp9vCi0txIQUx4BhS1WqtQPhNGCF16eW9Q3NRrnIrQ==", + "license": "MIT", + "dependencies": { + "@fluentui/tokens": "1.0.0-alpha.21", + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-toast": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.6.0.tgz", + "integrity": "sha512-t/eUl3w8RdLFMLHcvWHXCH9jec29MV7K7pqmyXsW2g7edaChTyCbkxlII861IvY+XqwIvNlpczzh4cgkyzAj/w==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-motion": "^9.9.0", + "@fluentui/react-motion-components-preview": "^0.7.0", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-toolbar": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.6.0.tgz", + "integrity": "sha512-tbpM8prz8cDTzeF7PudjTA3UQruVrjGNSsTwR+vmIGVo0E986Zz+VSJaLICeC2ttiHOirhqm6goswP+bGG5Evw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-divider": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-radio": "^9.5.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tooltip": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.8.0.tgz", + "integrity": "sha512-LW0ouXkPXxx+XPScLB9tWlqn11cVHxmDJ3weZXuWrl5jjx4agjqKHGC8MOdr4Un+2hoO0g2BcrlDaQNhsMPgYA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-portal": "^9.7.0", + "@fluentui/react-positioning": "^9.20.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tree": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.12.0.tgz", + "integrity": "sha512-vehLCk918YN53h8sGs4jx5oEF2twdVRdoIQ+csuLUkxRhl7f6eWyQWRk/R2lZlJgsz0vgk07RB/Yfx8/BFEUiA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.15.4", + "@fluentui/react-avatar": "^9.9.0", + "@fluentui/react-button": "^9.6.0", + "@fluentui/react-checkbox": "^9.5.0", + "@fluentui/react-context-selector": "^9.2.2", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-motion": "^9.9.0", + "@fluentui/react-motion-components-preview": "^0.7.0", + "@fluentui/react-radio": "^9.5.0", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-tabster": "^9.26.0", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-utilities": { + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.22.0.tgz", + "integrity": "sha512-O4D51FUyn5670SjduzzN1usmwWAmFPQA00Gu6jJrbDXvOXTpOAO/ApkLpSW87HChKGrj8Y0gjFHtK8xpC3qOCg==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-shared-contexts": "^9.24.0", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.100", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.100.tgz", + "integrity": "sha512-e7u3SP2Smv5+9Adey+pOerGmHq2D6Nd0ek/iWbc/o0CKX5QMeHwbUlZAbVVsrX/vwIeeZ3+qJMt+UH3hHI+wdw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.1.2", + "@fluentui/react-shared-contexts": "^9.24.0", + "@fluentui/react-utilities": "^9.22.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/tokens": { + "version": "1.0.0-alpha.21", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.21.tgz", + "integrity": "sha512-xQ1T56sNgDFGl+kJdIwhz67mHng8vcwO7Dvx5Uja4t+NRULQBgMcJ4reUo4FGF3TjufHj08pP0/OnKQgnOaSVg==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@griffel/core": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.19.2.tgz", + "integrity": "sha512-WkB/QQkjy9dE4vrNYGhQvRRUHFkYVOuaznVOMNTDT4pS9aTJ9XPrMTXXlkpcwaf0D3vNKoerj4zAwnU2lBzbOg==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@griffel/style-types": "^1.3.0", + "csstype": "^3.1.3", + "rtl-css-js": "^1.16.1", + "stylis": "^4.2.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@griffel/react": { + "version": "1.5.30", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.30.tgz", + "integrity": "sha512-1q4ojbEVFY5YA0j1NamP0WWF4BKh+GHsVugltDYeEgEaVbH3odJ7tJabuhQgY+7Nhka0pyEFWSiHJev0K3FSew==", + "license": "MIT", + "dependencies": { + "@griffel/core": "^1.19.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@griffel/style-types": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.3.0.tgz", + "integrity": "sha512-bHwD3sUE84Xwv4dH011gOKe1jul77M1S6ZFN9Tnq8pvZ48UMdY//vtES6fv7GRS5wXYT4iqxQPBluAiYAfkpmw==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3" + } + }, + "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/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "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, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pa-client/power-code-sdk": { + "version": "0.0.1", + "resolved": "https://github.com/microsoft/PowerAppsCodeApps/releases/download/v0.0.3/7-16-pa-client-power-code-sdk-0.0.1.1.tgz", + "integrity": "sha512-3EiJ78KOo+csby7Q05mkPtqGmZmzbXkWx2lXl/ymP4zfFeuSR2pvoIoqSqUlhwMmw2opNXZliatxRSvu74G8Vg==", + "license": "UNLICENSED" + }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", + "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz", + "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz", + "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", + "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz", + "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz", + "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz", + "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz", + "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz", + "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz", + "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz", + "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz", + "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz", + "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz", + "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz", + "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz", + "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz", + "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz", + "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz", + "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz", + "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", + "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.83.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.83.0.tgz", + "integrity": "sha512-0M8dA+amXUkyz5cVUm/B+zSk3xkQAcuXuz5/Q/LveT4ots2rBpPTZOzd7yJa2Utsf8D2Upl5KyjhHRY+9lB/XA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.83.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.83.0.tgz", + "integrity": "sha512-/XGYhZ3foc5H0VM2jLSD/NyBRIOK4q9kfeml4+0x2DlL6xVuAcVEW+hTlTapAmejObg0i3eNqhkr2dT+eciwoQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.83.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "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/prop-types": { + "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.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", + "integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.37.0", + "@typescript-eslint/type-utils": "8.37.0", + "@typescript-eslint/utils": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.37.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", + "integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.37.0", + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", + "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.37.0", + "@typescript-eslint/types": "^8.37.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", + "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", + "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", + "integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0", + "@typescript-eslint/utils": "8.37.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", + "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", + "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.37.0", + "@typescript-eslint/tsconfig-utils": "8.37.0", + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", + "integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.37.0", + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", + "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.37.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.6.0.tgz", + "integrity": "sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.19", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + } + }, + "node_modules/acorn": { + "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" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "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" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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, + "license": "Python-2.0" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "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/electron-to-chromium": { + "version": "1.5.187", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.187.tgz", + "integrity": "sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA==", + "dev": true, + "license": "ISC" + }, + "node_modules/embla-carousel": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", + "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", + "license": "MIT" + }, + "node_modules/embla-carousel-autoplay": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-autoplay/-/embla-carousel-autoplay-8.6.0.tgz", + "integrity": "sha512-OBu5G3nwaSXkZCo1A6LTaFMZ8EpkYbwIaH+bPqdBnDGQ2fh4+NbzjXjs2SktoPNKCtflfVMc75njaDHOYXcrsA==", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, + "node_modules/embla-carousel-fade": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-fade/-/embla-carousel-fade-8.6.0.tgz", + "integrity": "sha512-qaYsx5mwCz72ZrjlsXgs1nKejSrW+UhkbOMwLgfRT7w2LtdEB03nPRI06GHuHv5ac2USvbEiX2/nAHctcDwvpg==", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", + "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.6", + "@esbuild/android-arm": "0.25.6", + "@esbuild/android-arm64": "0.25.6", + "@esbuild/android-x64": "0.25.6", + "@esbuild/darwin-arm64": "0.25.6", + "@esbuild/darwin-x64": "0.25.6", + "@esbuild/freebsd-arm64": "0.25.6", + "@esbuild/freebsd-x64": "0.25.6", + "@esbuild/linux-arm": "0.25.6", + "@esbuild/linux-arm64": "0.25.6", + "@esbuild/linux-ia32": "0.25.6", + "@esbuild/linux-loong64": "0.25.6", + "@esbuild/linux-mips64el": "0.25.6", + "@esbuild/linux-ppc64": "0.25.6", + "@esbuild/linux-riscv64": "0.25.6", + "@esbuild/linux-s390x": "0.25.6", + "@esbuild/linux-x64": "0.25.6", + "@esbuild/netbsd-arm64": "0.25.6", + "@esbuild/netbsd-x64": "0.25.6", + "@esbuild/openbsd-arm64": "0.25.6", + "@esbuild/openbsd-x64": "0.25.6", + "@esbuild/openharmony-arm64": "0.25.6", + "@esbuild/sunos-x64": "0.25.6", + "@esbuild/win32-arm64": "0.25.6", + "@esbuild/win32-ia32": "0.25.6", + "@esbuild/win32-x64": "0.25.6" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", + "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.31.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@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.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "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": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "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": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/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": "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.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "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" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "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.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "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": "^4.0.0" + }, + "engines": { + "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, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "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.4" + }, + "engines": { + "node": ">=16" + } + }, + "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==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "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==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "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==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyborg": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.6.0.tgz", + "integrity": "sha512-o5kvLbuTF+o326CMVYpjlaykxqYP9DphFQZ2ZpgrvBouyvOxyEB7oqe8nOLFpiV5VCtz0D3pt8gXQYWpLpBnmA==", + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "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" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "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==", + "license": "MIT", + "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/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "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", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz", + "integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz", + "integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0", + "react-router": "6.30.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "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": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/resolve-from": { + "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, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", + "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.45.1", + "@rollup/rollup-android-arm64": "4.45.1", + "@rollup/rollup-darwin-arm64": "4.45.1", + "@rollup/rollup-darwin-x64": "4.45.1", + "@rollup/rollup-freebsd-arm64": "4.45.1", + "@rollup/rollup-freebsd-x64": "4.45.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", + "@rollup/rollup-linux-arm-musleabihf": "4.45.1", + "@rollup/rollup-linux-arm64-gnu": "4.45.1", + "@rollup/rollup-linux-arm64-musl": "4.45.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-musl": "4.45.1", + "@rollup/rollup-linux-s390x-gnu": "4.45.1", + "@rollup/rollup-linux-x64-gnu": "4.45.1", + "@rollup/rollup-linux-x64-musl": "4.45.1", + "@rollup/rollup-win32-arm64-msvc": "4.45.1", + "@rollup/rollup-win32-ia32-msvc": "4.45.1", + "@rollup/rollup-win32-x64-msvc": "4.45.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "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", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "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, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tabster": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/tabster/-/tabster-8.5.6.tgz", + "integrity": "sha512-2vfrRGrx8O9BjdrtSlVA5fvpmbq5HQBRN13XFRg6LAvZ1Fr3QdBnswgT4YgFS5Bhoo5nxwgjRaRueI2Us/dv7g==", + "license": "MIT", + "dependencies": { + "keyborg": "2.6.0", + "tslib": "^2.8.1" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "4.40.0" + } + }, + "node_modules/tabster/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", + "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", + "integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.37.0", + "@typescript-eslint/parser": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0", + "@typescript-eslint/utils": "8.37.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-disposable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/use-disposable/-/use-disposable-1.0.4.tgz", + "integrity": "sha512-j83t6AMLWUyb5zwlTDqf6dP9LezM9R0yTbI/b6olmdaGtCKQUe9pgJWV6dRaaQLcozypjIEp4EmZr2DkZGKLSg==", + "license": "MIT", + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vite": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz", + "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.2", + "postcss": "^8.5.6", + "rollup": "^4.40.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/samples/FluentSample/package.json b/samples/FluentSample/package.json new file mode 100644 index 0000000..371942b --- /dev/null +++ b/samples/FluentSample/package.json @@ -0,0 +1,34 @@ +{ + "name": "fluentsample", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "start vite && start pac code run", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@fluentui/react-components": "^9.67.0", + "@fluentui/react-icons": "^2.0.306", + "@pa-client/power-code-sdk": "https://github.com/microsoft/PowerAppsCodeApps/releases/download/v0.0.3/7-16-pa-client-power-code-sdk-0.0.1.1.tgz", + "@tanstack/react-query": "^5.83.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.30.1" + }, + "devDependencies": { + "@eslint/js": "^9.30.1", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.6.0", + "eslint": "^9.30.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.35.1", + "vite": "^7.0.4" + } +} diff --git a/samples/FluentSample/public/PowerApps_scalable.svg b/samples/FluentSample/public/PowerApps_scalable.svg new file mode 100644 index 0000000..4568592 --- /dev/null +++ b/samples/FluentSample/public/PowerApps_scalable.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/FluentSample/src/App.css b/samples/FluentSample/src/App.css new file mode 100644 index 0000000..375dfeb --- /dev/null +++ b/samples/FluentSample/src/App.css @@ -0,0 +1 @@ +/* Fluent UI App Styles - Let components handle their own styling */ diff --git a/samples/FluentSample/src/App.tsx b/samples/FluentSample/src/App.tsx new file mode 100644 index 0000000..da218b4 --- /dev/null +++ b/samples/FluentSample/src/App.tsx @@ -0,0 +1,52 @@ +import { Routes, Route } from 'react-router-dom' +import { makeStyles, shorthands, tokens, Spinner } from '@fluentui/react-components' +import { lazy, Suspense } from 'react' +import Layout from './components/Layout' +import HomePage from './pages/HomePage' + +// Lazy load pages for code splitting +const Office365Page = lazy(() => import('./pages/Office365Page')) +const SqlPage = lazy(() => import('./pages/SqlPage')) +const CustomApiPage = lazy(() => import('./pages/CustomApiPage')) + +const useStyles = makeStyles({ + root: { + ...shorthands.margin(0), + ...shorthands.padding(0), + minHeight: '100vh', + backgroundColor: tokens.colorNeutralBackground1, + }, + loadingContainer: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + height: '200px', + }, +}); + +function App() { + const styles = useStyles(); + + const LoadingFallback = () => ( +
+ +
+ ); + + return ( +
+ + }> + + } /> + } /> + } /> + } /> + + + +
+ ) +} + +export default App diff --git a/samples/FluentSample/src/PowerProvider.tsx b/samples/FluentSample/src/PowerProvider.tsx new file mode 100644 index 0000000..a3c2dde --- /dev/null +++ b/samples/FluentSample/src/PowerProvider.tsx @@ -0,0 +1,24 @@ +import { initialize } from "@pa-client/power-code-sdk/lib/Lifecycle"; +import { useEffect } from "react"; +import type { ReactNode } from "react"; + +interface PowerProviderProps { + children: ReactNode; +} + +export default function PowerProvider({ children }: PowerProviderProps) { + useEffect(() => { + const initApp = async () => { + try { + await initialize(); + console.log('Power Platform SDK initialized successfully'); + } catch (error) { + console.error('Failed to initialize Power Platform SDK:', error); + } + }; + + initApp(); + }, []); + + return <>{children}; +} diff --git a/samples/FluentSample/src/assets/react.svg b/samples/FluentSample/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/samples/FluentSample/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/samples/FluentSample/src/components/Layout.tsx b/samples/FluentSample/src/components/Layout.tsx new file mode 100644 index 0000000..2c1ed97 --- /dev/null +++ b/samples/FluentSample/src/components/Layout.tsx @@ -0,0 +1,536 @@ +import type { ReactNode } from 'react'; +import { + makeStyles, + shorthands, + Text, + Button, + tokens, + Breadcrumb, + BreadcrumbItem, + BreadcrumbDivider +} from '@fluentui/react-components'; +import { + HomeRegular, + HomeFilled, + PeopleRegular, + PeopleFilled, + DatabaseRegular, + DatabaseFilled, + CloudRegular, + CloudFilled, + NavigationRegular, + WeatherMoonRegular, + WeatherSunnyRegular +} from '@fluentui/react-icons'; +import { Link, useLocation } from 'react-router-dom'; +import { useState } from 'react'; +import { useTheme } from '../hooks/useTheme'; + +const useStyles = makeStyles({ + root: { + display: 'flex', + minHeight: '100vh', + width: '100vw', + overflow: 'hidden', + }, + sidebar: { + width: '280px', + backgroundColor: tokens.colorNeutralBackground2, + ...shorthands.borderRight('1px', 'solid', tokens.colorNeutralStroke2), + display: 'flex', + flexDirection: 'column', + ...shorthands.padding('16px'), + position: 'fixed', + top: 0, + left: 0, + height: '100vh', + zIndex: 1000, + paddingTop: '76px', + transition: 'transform 0.3s ease-in-out', + '@media (max-width: 768px)': { + width: '100vw', + transform: 'translateX(-100%)', + paddingTop: '60px', + }, + }, + sidebarVisible: { + '@media (max-width: 768px)': { + transform: 'translateX(0) !important', + }, + }, + sidebarCollapsed: { + width: '60px', + '@media (max-width: 768px)': { + transform: 'translateX(-100%)', + }, + }, + mobileOverlay: { + position: 'fixed', + top: 0, + left: 0, + width: '100vw', + height: '100vh', + backgroundColor: 'rgba(0, 0, 0, 0.5)', + zIndex: 999, + display: 'none', + '@media (max-width: 768px)': { + display: 'block', + }, + }, + mobileHeader: { + display: 'none', + '@media (max-width: 768px)': { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + ...shorthands.padding('16px'), + backgroundColor: tokens.colorNeutralBackground2, + ...shorthands.borderBottom('1px', 'solid', tokens.colorNeutralStroke2), + position: 'fixed', + top: 0, + left: 0, + right: 0, + zIndex: 1001, + }, + }, + content: { + flex: 1, + display: 'flex', + flexDirection: 'column', + marginLeft: '280px', + marginTop: '76px', + width: 'calc(100vw - 280px)', + '@media (max-width: 768px)': { + marginLeft: 0, + marginTop: '60px', + width: '100vw', + paddingTop: '60px', // Account for mobile header + }, + }, + contentCollapsed: { + marginLeft: '60px', + marginTop: '76px', + width: 'calc(100vw - 60px)', + '@media (max-width: 768px)': { + marginLeft: 0, + marginTop: '60px', + width: '100vw', + paddingTop: '60px', + }, + }, + appHeader: { + backgroundColor: tokens.colorNeutralBackground1, + ...shorthands.borderBottom('1px', 'solid', tokens.colorNeutralStroke2), + ...shorthands.padding('16px', '24px'), + position: 'fixed', + top: 0, + left: 0, + right: 0, + zIndex: 1100, + display: 'grid', + gridTemplateColumns: 'auto 1fr auto', + alignItems: 'center', + minHeight: '60px', + boxShadow: tokens.shadow4, + }, + headerLeft: { + display: 'flex', + alignItems: 'center', + gap: '16px', + }, + headerCenter: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, + headerRight: { + // Reserved for future actions like user menu, etc. + }, + pageTitle: { + fontSize: tokens.fontSizeBase500, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + marginLeft: '16px', + }, + header: { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + marginBottom: '24px', + }, + logo: { + fontSize: tokens.fontSizeBase500, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + }, + navList: { + listStyle: 'none', + ...shorthands.margin(0), + ...shorthands.padding(0), + display: 'flex', + flexDirection: 'column', + ...shorthands.gap('8px'), + }, + navItem: { + display: 'flex', + }, + navLink: { + display: 'flex', + alignItems: 'center', + ...shorthands.gap('12px'), + ...shorthands.padding('12px', '16px'), + textDecoration: 'none', + color: tokens.colorNeutralForeground2, + backgroundColor: 'transparent', + ...shorthands.borderRadius(tokens.borderRadiusMedium), + ...shorthands.border('2px', 'solid', 'transparent'), + width: '100%', + transition: 'all 0.2s ease-in-out', + position: 'relative', + '&:hover': { + backgroundColor: tokens.colorNeutralBackground1Hover, + color: tokens.colorNeutralForeground1, + transform: 'translateY(-1px)', + }, + '&:focus': { + outline: `2px solid ${tokens.colorBrandBackground}`, + outlineOffset: '2px', + }, + }, + navLinkActive: { + backgroundColor: `${tokens.colorBrandBackground} !important`, + color: `${tokens.colorNeutralForegroundOnBrand} !important`, + fontWeight: '600', + ...shorthands.border('2px', 'solid', tokens.colorBrandBackgroundSelected), + boxShadow: `0 4px 8px ${tokens.colorNeutralShadowAmbient}, 0 2px 4px ${tokens.colorNeutralShadowKey}`, + transform: 'translateY(-2px)', + '&:hover': { + backgroundColor: `${tokens.colorBrandBackgroundHover} !important`, + color: `${tokens.colorNeutralForegroundOnBrand} !important`, + transform: 'translateY(-2px)', + }, + '&::before': { + content: '""', + position: 'absolute', + left: '-16px', + top: '50%', + transform: 'translateY(-50%)', + width: '4px', + height: '24px', + backgroundColor: tokens.colorBrandForeground1, + ...shorthands.borderRadius('2px'), + }, + }, + navLinkCollapsed: { + justifyContent: 'center', + ...shorthands.padding('12px'), + }, + navText: { + fontSize: tokens.fontSizeBase300, + fontWeight: tokens.fontWeightMedium, + lineHeight: tokens.lineHeightBase300, + color: 'inherit', + }, + navTextActive: { + fontSize: tokens.fontSizeBase300, + fontWeight: tokens.fontWeightSemibold, + lineHeight: tokens.lineHeightBase300, + color: 'inherit', + }, + navDescription: { + fontSize: tokens.fontSizeBase200, + marginTop: '2px', + lineHeight: tokens.lineHeightBase200, + opacity: 0.9, + color: 'inherit', + }, + navIcon: { + fontSize: '20px', + transition: 'transform 0.2s ease-in-out', + }, + navIconActive: { + fontSize: '20px', + transform: 'scale(1.1)', + }, + main: { + flex: 1, + ...shorthands.padding('24px'), + backgroundColor: tokens.colorNeutralBackground1, + color: tokens.colorNeutralForeground1, + overflow: 'auto', + minHeight: 'calc(100vh - 120px)', + '@media (max-width: 768px)': { + ...shorthands.padding('16px'), + minHeight: 'calc(100vh - 180px)', + }, + }, + themeToggle: { + marginTop: 'auto', + ...shorthands.padding('12px'), + borderTop: `1px solid ${tokens.colorNeutralStroke2}`, + display: 'flex', + justifyContent: 'center', + }, + footer: { + ...shorthands.padding('16px', '24px'), + backgroundColor: tokens.colorNeutralBackground2, + ...shorthands.borderTop('1px', 'solid', tokens.colorNeutralStroke2), + fontSize: tokens.fontSizeBase200, + color: tokens.colorNeutralForeground2, + textAlign: 'center', + '@media (max-width: 768px)': { + ...shorthands.padding('12px', '16px'), + fontSize: tokens.fontSizeBase100, + }, + }, + toggleButton: { + minWidth: 'auto', + width: '32px', + height: '32px', + }, +}); + +interface NavItem { + path: string; + label: string; + description: string; + icon: React.ReactElement; + iconFilled: React.ReactElement; +} + +const navItems: NavItem[] = [ + { + path: '/', + label: 'Home', + description: 'Welcome and overview', + icon: , + iconFilled: , + }, + { + path: '/office365', + label: 'Office 365', + description: 'User profiles and directory', + icon: , + iconFilled: , + }, + { + path: '/sql', + label: 'SQL Database', + description: 'Project management with DataGrid and pagination', + icon: , + iconFilled: , + }, + { + path: '/custom-api', + label: 'Custom API', + description: 'Custom connector template', + icon: , + iconFilled: , + }, +]; + +const routeNames: Record = { + '/': 'Home', + '/office365': 'Office 365 Connector', + '/sql': 'SQL Database Connector', + '/custom-api': 'Custom API Connector' +}; + +interface LayoutProps { + children: ReactNode; +} + +export default function Layout({ children }: LayoutProps) { + const styles = useStyles(); + const location = useLocation(); + const [collapsed, setCollapsed] = useState(false); + const [mobileMenuOpen, setMobileMenuOpen] = useState(false); + const { isDarkMode, toggleTheme } = useTheme(); + + const getBreadcrumbs = () => { + const pathSegments = location.pathname.split('/').filter(Boolean); + const breadcrumbs = [{ path: '/', name: 'Home' }]; + + let currentPath = ''; + pathSegments.forEach(segment => { + currentPath += `/${segment}`; + const routeName = routeNames[currentPath]; + if (routeName) { + breadcrumbs.push({ path: currentPath, name: routeName }); + } + }); + + return breadcrumbs; + }; + + const breadcrumbs = getBreadcrumbs(); + + const handleMobileToggle = () => { + setMobileMenuOpen(!mobileMenuOpen); + }; + + const handleMobileClose = () => { + setMobileMenuOpen(false); + }; + + const sidebarClassName = `${styles.sidebar} ${ + collapsed ? styles.sidebarCollapsed : '' + } ${mobileMenuOpen ? styles.sidebarVisible : ''}`; + + const contentClassName = `${styles.content} ${ + collapsed ? styles.contentCollapsed : '' + }`; + + return ( +
+ {/* Fixed App Header with Hamburger, Breadcrumbs, and Centered Title */} +
+ {/* Left Section: Hamburger + Breadcrumbs */} +
+
+ + {/* Center Section: App Title with Logo */} +
+ Power Apps + + Sample Code App + +
+ + {/* Right Section: Reserved for future actions */} +
+ {/* Space for user menu, notifications, etc. */} +
+
+ {/* Mobile Header */} +
+
+ + {/* Mobile Overlay */} + {mobileMenuOpen && ( +
+ )} + + {/* Sidebar */} + + + {/* Main Content */} +
+
+ {children} +
+ +
+ + Power Apps Code App sample crafted with Copilot Chat πŸ€– + +
+
+
+ ); +} diff --git a/samples/FluentSample/src/components/PageHeader.tsx b/samples/FluentSample/src/components/PageHeader.tsx new file mode 100644 index 0000000..e5fed6f --- /dev/null +++ b/samples/FluentSample/src/components/PageHeader.tsx @@ -0,0 +1,53 @@ +import { Text, makeStyles, shorthands, tokens } from '@fluentui/react-components'; +import type { ReactNode } from 'react'; + +const useStyles = makeStyles({ + container: { + marginBottom: '32px', + backgroundColor: tokens.colorNeutralBackground1, + }, + header: { + display: 'flex', + alignItems: 'center', + ...shorthands.gap('16px'), + marginBottom: '16px', + }, + icon: { + fontSize: '32px', + color: tokens.colorBrandForeground1, + }, + title: { + fontSize: tokens.fontSizeHero700, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + margin: 0, + }, + subtitle: { + fontSize: tokens.fontSizeBase300, + color: tokens.colorNeutralForeground2, + lineHeight: tokens.lineHeightBase300, + maxWidth: '800px', + }, +}); + +interface PageHeaderProps { + title: string; + subtitle: string; + icon: ReactNode; +} + +export default function PageHeader({ title, subtitle, icon }: PageHeaderProps) { + const styles = useStyles(); + + return ( +
+
+ {icon} +

{title}

+
+ + {subtitle} + +
+ ); +} diff --git a/samples/FluentSample/src/components/PaginationComponent.tsx b/samples/FluentSample/src/components/PaginationComponent.tsx new file mode 100644 index 0000000..df059e1 --- /dev/null +++ b/samples/FluentSample/src/components/PaginationComponent.tsx @@ -0,0 +1,130 @@ +import { + Button, + Text, + makeStyles, + shorthands, + Dropdown, + Option +} from '@fluentui/react-components'; +import { + ChevronLeftRegular, + ChevronRightRegular, + ChevronDoubleLeftRegular, + ChevronDoubleRightRegular +} from '@fluentui/react-icons'; +import type { PaginationState, PaginationControls } from '../hooks/usePagination'; + +const useStyles = makeStyles({ + container: { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + ...shorthands.gap('16px'), + ...shorthands.padding('16px', '0'), + }, + controls: { + display: 'flex', + alignItems: 'center', + ...shorthands.gap('8px'), + }, + pageInfo: { + fontSize: '14px', + color: '#605e5c', + }, + pageSizeContainer: { + display: 'flex', + alignItems: 'center', + ...shorthands.gap('8px'), + }, + dropdown: { + minWidth: '80px', + }, +}); + +interface PaginationComponentProps { + paginationState: PaginationState; + paginationControls: PaginationControls; + showPageSizeSelector?: boolean; + pageSizeOptions?: number[]; +} + +export default function PaginationComponent({ + paginationState, + paginationControls, + showPageSizeSelector = true, + pageSizeOptions = [5, 10, 20, 50], +}: PaginationComponentProps) { + const styles = useStyles(); + const { currentPage, pageSize, totalItems, totalPages } = paginationState; + const { goToPage, nextPage, previousPage, setPageSize, canGoNext, canGoPrevious } = paginationControls; + + const startItem = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1; + const endItem = Math.min(currentPage * pageSize, totalItems); + + return ( +
+
+
+ +
+ + Showing {startItem}-{endItem} of {totalItems} items + + + {showPageSizeSelector && ( +
+ Items per page: + { + if (data.optionValue) { + setPageSize(parseInt(data.optionValue)); + } + }} + > + {pageSizeOptions.map(size => ( + + ))} + +
+ )} +
+
+ ); +} diff --git a/samples/FluentSample/src/components/ThemedApp.tsx b/samples/FluentSample/src/components/ThemedApp.tsx new file mode 100644 index 0000000..220cd78 --- /dev/null +++ b/samples/FluentSample/src/components/ThemedApp.tsx @@ -0,0 +1,20 @@ +import { FluentProvider } from '@fluentui/react-components'; +import { QueryClientProvider } from '@tanstack/react-query'; +import { BrowserRouter } from 'react-router-dom'; +import { useTheme } from '../hooks/useTheme'; +import { queryClient } from '../main'; +import App from '../App'; + +export const ThemedApp = () => { + const { theme } = useTheme(); + + return ( + + + + + + + + ); +}; diff --git a/samples/FluentSample/src/contexts/ThemeContext.ts b/samples/FluentSample/src/contexts/ThemeContext.ts new file mode 100644 index 0000000..7cace04 --- /dev/null +++ b/samples/FluentSample/src/contexts/ThemeContext.ts @@ -0,0 +1,10 @@ +import { createContext } from 'react'; +import type { Theme } from '@fluentui/react-components'; + +export interface ThemeContextType { + isDarkMode: boolean; + toggleTheme: () => void; + theme: Theme; +} + +export const ThemeContext = createContext(undefined); diff --git a/samples/FluentSample/src/contexts/ThemeContext.tsx b/samples/FluentSample/src/contexts/ThemeContext.tsx new file mode 100644 index 0000000..d7b1ae7 --- /dev/null +++ b/samples/FluentSample/src/contexts/ThemeContext.tsx @@ -0,0 +1,39 @@ +import { useState, useEffect } from 'react'; +import type { ReactNode } from 'react'; +import { webLightTheme, webDarkTheme } from '@fluentui/react-components'; +import { ThemeContext } from './ThemeContext'; + +interface ThemeProviderProps { + children: ReactNode; +} + +export const ThemeProvider = ({ children }: ThemeProviderProps) => { + // Get initial theme from localStorage or default to light mode + const [isDarkMode, setIsDarkMode] = useState(() => { + const saved = localStorage.getItem('fluentSample-darkMode'); + return saved ? JSON.parse(saved) : false; + }); + + // Update localStorage when theme changes + useEffect(() => { + localStorage.setItem('fluentSample-darkMode', JSON.stringify(isDarkMode)); + }, [isDarkMode]); + + const toggleTheme = () => { + setIsDarkMode((prev: boolean) => !prev); + }; + + const theme = isDarkMode ? webDarkTheme : webLightTheme; + + const value = { + isDarkMode, + toggleTheme, + theme, + }; + + return ( + + {children} + + ); +}; diff --git a/samples/FluentSample/src/hooks/usePagination.ts b/samples/FluentSample/src/hooks/usePagination.ts new file mode 100644 index 0000000..e41d448 --- /dev/null +++ b/samples/FluentSample/src/hooks/usePagination.ts @@ -0,0 +1,88 @@ +import { useState, useMemo } from 'react'; + +export interface PaginationState { + currentPage: number; + pageSize: number; + totalItems: number; + totalPages: number; +} + +export interface PaginationControls { + goToPage: (page: number) => void; + nextPage: () => void; + previousPage: () => void; + setPageSize: (size: number) => void; + canGoNext: boolean; + canGoPrevious: boolean; +} + +export interface UsePaginationProps { + totalItems: number; + initialPageSize?: number; + initialPage?: number; +} + +export interface UsePaginationReturn { + paginationState: PaginationState; + paginationControls: PaginationControls; + getPagedItems: (items: T[]) => T[]; +} + +export function usePagination({ + totalItems, + initialPageSize = 10, + initialPage = 1, +}: UsePaginationProps): UsePaginationReturn { + const [currentPage, setCurrentPage] = useState(initialPage); + const [pageSize, setPageSize] = useState(initialPageSize); + + const paginationState: PaginationState = useMemo(() => { + const totalPages = Math.ceil(totalItems / pageSize); + return { + currentPage, + pageSize, + totalItems, + totalPages, + }; + }, [currentPage, pageSize, totalItems]); + + const paginationControls: PaginationControls = useMemo(() => { + const canGoNext = currentPage < paginationState.totalPages; + const canGoPrevious = currentPage > 1; + + return { + goToPage: (page: number) => { + const clampedPage = Math.max(1, Math.min(page, paginationState.totalPages)); + setCurrentPage(clampedPage); + }, + nextPage: () => { + if (canGoNext) { + setCurrentPage(prev => prev + 1); + } + }, + previousPage: () => { + if (canGoPrevious) { + setCurrentPage(prev => prev - 1); + } + }, + setPageSize: (size: number) => { + setPageSize(size); + setCurrentPage(1); // Reset to first page when page size changes + }, + canGoNext, + canGoPrevious, + }; + }, [currentPage, paginationState.totalPages]); + + const getPagedItems = (items: T[]): T[] => { + const startIndex = (currentPage - 1) * pageSize; + const endIndex = startIndex + pageSize; + return items.slice(startIndex, endIndex); + }; + + return { + paginationState, + paginationControls, + getPagedItems, + }; +} diff --git a/samples/FluentSample/src/hooks/useTheme.ts b/samples/FluentSample/src/hooks/useTheme.ts new file mode 100644 index 0000000..28df0ad --- /dev/null +++ b/samples/FluentSample/src/hooks/useTheme.ts @@ -0,0 +1,10 @@ +import { useContext } from 'react'; +import { ThemeContext } from '../contexts/ThemeContext.ts'; + +export const useTheme = () => { + const context = useContext(ThemeContext); + if (context === undefined) { + throw new Error('useTheme must be used within a ThemeProvider'); + } + return context; +}; diff --git a/samples/FluentSample/src/index.css b/samples/FluentSample/src/index.css new file mode 100644 index 0000000..4ee0b17 --- /dev/null +++ b/samples/FluentSample/src/index.css @@ -0,0 +1,48 @@ +/* Global CSS Reset and Base Styles */ +* { + box-sizing: border-box; +} + +html, body { + margin: 0; + padding: 0; + height: 100%; + width: 100%; + overflow-x: hidden; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +#root { + width: 100vw; + height: 100vh; + margin: 0; + padding: 0; +} + +/* Remove any default styling that might interfere */ +a { + color: inherit; + text-decoration: none; +} + +a:hover { + text-decoration: none; +} + +/* Ensure proper scrolling behavior */ +html { + scroll-behavior: smooth; +} + +/* Responsive typography */ +@media (max-width: 768px) { + html { + font-size: 14px; + } +} + +@media (max-width: 480px) { + html { + font-size: 13px; + } +} diff --git a/samples/FluentSample/src/main.tsx b/samples/FluentSample/src/main.tsx new file mode 100644 index 0000000..bdc92e5 --- /dev/null +++ b/samples/FluentSample/src/main.tsx @@ -0,0 +1,27 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import { QueryClient } from '@tanstack/react-query' +import PowerProvider from './PowerProvider.tsx' +import { ThemeProvider } from './contexts/ThemeContext.tsx' +import { ThemedApp } from './components/ThemedApp'; +import './index.css' + +// Create a client for TanStack Query +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, // 5 minutes + refetchOnWindowFocus: false, + }, + }, +}); + +createRoot(document.getElementById('root')!).render( + + + + + + + , +) diff --git a/samples/FluentSample/src/mockData/customApiData.ts b/samples/FluentSample/src/mockData/customApiData.ts new file mode 100644 index 0000000..22cafb0 --- /dev/null +++ b/samples/FluentSample/src/mockData/customApiData.ts @@ -0,0 +1,78 @@ +// Mock data for Custom API connector examples +// This file demonstrates the data structure expected from custom API connectors +// Replace this mock data with real custom connector calls in your implementation + +export interface Asset { + // Unique identifier for the asset + id: number; + // Name of the asset + name: string; + // Category/type of the asset + type: string; + // Current status of the asset + status: string; +} + +// Mock assets for API responses - matches the Power Platform custom connector structure +export const mockAssets: Asset[] = [ + { + id: 1, + name: "Dell Laptop XPS 13", + type: "Electronics", + status: "Available" + }, + { + id: 2, + name: "Conference Room Projector", + type: "Electronics", + status: "In Use" + }, + { + id: 3, + name: "Standing Desk", + type: "Furniture", + status: "Available" + }, + { + id: 4, + name: "Wireless Mouse", + type: "Electronics", + status: "Available" + }, + { + id: 5, + name: "Office Chair", + type: "Furniture", + status: "In Use" + }, + { + id: 6, + name: "Monitor 24 inch", + type: "Electronics", + status: "Maintenance" + }, + { + id: 7, + name: "Desk Lamp", + type: "Furniture", + status: "Available" + }, + { + id: 8, + name: "Bluetooth Headphones", + type: "Electronics", + status: "Available" + }, + { + id: 9, + name: "Whiteboard", + type: "Office Supplies", + status: "In Use" + }, + { + id: 10, + name: "Printer", + type: "Electronics", + status: "Maintenance" + } +]; \ No newline at end of file diff --git a/samples/FluentSample/src/mockData/office365Data.ts b/samples/FluentSample/src/mockData/office365Data.ts new file mode 100644 index 0000000..e0821c3 --- /dev/null +++ b/samples/FluentSample/src/mockData/office365Data.ts @@ -0,0 +1,278 @@ +// Mock data for Office 365 Users connector +// This file demonstrates the data structure expected from Office 365 Users connector +// The data structure matches the live Office365UsersService.User interface + +// TODO: Replace this mock interface with the actual Office 365 User type from Power Apps SDK +export interface User { + Id: string; + AccountEnabled: boolean; + BusinessPhones: string[]; + City: string; + CompanyName: string; + Country: string; + Department: string; + DisplayName: string; + GivenName: string; + JobTitle: string; + Mail: string; + MailNickname: string; + mobilePhone?: string; + OfficeLocation: string; + PostalCode: string; + Surname: string; + TelephoneNumber: string; + UserPrincipalName: string; +} + +// Mock user profiles that match the Office 365 User interface +export const mockUsers: User[] = [ + { + Id: "550e8400-e29b-41d4-a716-446655440001", + AccountEnabled: true, + BusinessPhones: ["+1 (425) 555-0100"], + City: "Seattle", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Engineering", + DisplayName: "Alex Johnson", + GivenName: "Alex", + JobTitle: "Senior Software Engineer", + Mail: "alex.johnson@contoso.com", + MailNickname: "alexj", + mobilePhone: "+1 (425) 555-0101", + OfficeLocation: "Building 1, Floor 3", + PostalCode: "98052", + Surname: "Johnson", + TelephoneNumber: "+1 (425) 555-0100", + UserPrincipalName: "alex.johnson@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440002", + AccountEnabled: true, + BusinessPhones: ["+1 (415) 555-0200"], + City: "San Francisco", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Product Management", + DisplayName: "Sarah Chen", + GivenName: "Sarah", + JobTitle: "Senior Product Manager", + Mail: "sarah.chen@contoso.com", + MailNickname: "sarahc", + mobilePhone: "+1 (415) 555-0201", + OfficeLocation: "Building A, Floor 5", + PostalCode: "94105", + Surname: "Chen", + TelephoneNumber: "+1 (415) 555-0200", + UserPrincipalName: "sarah.chen@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440003", + AccountEnabled: true, + BusinessPhones: ["+1 (512) 555-0300"], + City: "Austin", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Design", + DisplayName: "Michael Rodriguez", + GivenName: "Michael", + JobTitle: "Principal UX Designer", + Mail: "michael.rodriguez@contoso.com", + MailNickname: "michaelr", + mobilePhone: "+1 (512) 555-0301", + OfficeLocation: "Building C, Floor 2", + PostalCode: "78701", + Surname: "Rodriguez", + TelephoneNumber: "+1 (512) 555-0300", + UserPrincipalName: "michael.rodriguez@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440004", + AccountEnabled: true, + BusinessPhones: ["+1 (206) 555-0400"], + City: "Seattle", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Marketing", + DisplayName: "Emily Davis", + GivenName: "Emily", + JobTitle: "Marketing Director", + Mail: "emily.davis@contoso.com", + MailNickname: "emilyd", + mobilePhone: "+1 (206) 555-0401", + OfficeLocation: "Building 2, Floor 4", + PostalCode: "98052", + Surname: "Davis", + TelephoneNumber: "+1 (206) 555-0400", + UserPrincipalName: "emily.davis@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440005", + AccountEnabled: true, + BusinessPhones: ["+1 (212) 555-0500"], + City: "New York", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Sales", + DisplayName: "David Wilson", + GivenName: "David", + JobTitle: "Sales Manager", + Mail: "david.wilson@contoso.com", + MailNickname: "davidw", + mobilePhone: "+1 (212) 555-0501", + OfficeLocation: "Building North, Floor 10", + PostalCode: "10001", + Surname: "Wilson", + TelephoneNumber: "+1 (212) 555-0500", + UserPrincipalName: "david.wilson@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440006", + AccountEnabled: true, + BusinessPhones: ["+1 (425) 555-0600"], + City: "Redmond", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Human Resources", + DisplayName: "Lisa Thompson", + GivenName: "Lisa", + JobTitle: "HR Business Partner", + Mail: "lisa.thompson@contoso.com", + MailNickname: "lisat", + mobilePhone: "+1 (425) 555-0601", + OfficeLocation: "Building 4, Floor 1", + PostalCode: "98052", + Surname: "Thompson", + TelephoneNumber: "+1 (425) 555-0600", + UserPrincipalName: "lisa.thompson@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440007", + AccountEnabled: true, + BusinessPhones: ["+1 (310) 555-0700"], + City: "Los Angeles", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Engineering", + DisplayName: "James Anderson", + GivenName: "James", + JobTitle: "DevOps Engineer", + Mail: "james.anderson@contoso.com", + MailNickname: "jamesa", + mobilePhone: "+1 (310) 555-0701", + OfficeLocation: "Building West, Floor 3", + PostalCode: "90210", + Surname: "Anderson", + TelephoneNumber: "+1 (310) 555-0700", + UserPrincipalName: "james.anderson@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440008", + AccountEnabled: true, + BusinessPhones: ["+1 (415) 555-0800"], + City: "San Francisco", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Finance", + DisplayName: "Jennifer Martinez", + GivenName: "Jennifer", + JobTitle: "Financial Analyst", + Mail: "jennifer.martinez@contoso.com", + MailNickname: "jenniferm", + mobilePhone: "+1 (415) 555-0801", + OfficeLocation: "Building A, Floor 8", + PostalCode: "94105", + Surname: "Martinez", + TelephoneNumber: "+1 (415) 555-0800", + UserPrincipalName: "jennifer.martinez@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440009", + AccountEnabled: false, + BusinessPhones: ["+1 (206) 555-0900"], + City: "Seattle", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "IT", + DisplayName: "Robert Taylor", + GivenName: "Robert", + JobTitle: "IT Administrator", + Mail: "robert.taylor@contoso.com", + MailNickname: "robertt", + mobilePhone: "+1 (206) 555-0901", + OfficeLocation: "Building 3, Floor 1", + PostalCode: "98052", + Surname: "Taylor", + TelephoneNumber: "+1 (206) 555-0900", + UserPrincipalName: "robert.taylor@contoso.com" + }, + { + Id: "550e8400-e29b-41d4-a716-446655440010", + AccountEnabled: true, + BusinessPhones: ["+1 (512) 555-1000"], + City: "Austin", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Legal", + DisplayName: "Maria Garcia", + GivenName: "Maria", + JobTitle: "Legal Counsel", + Mail: "maria.garcia@contoso.com", + MailNickname: "mariag", + mobilePhone: "+1 (512) 555-1001", + OfficeLocation: "Building C, Floor 6", + PostalCode: "78701", + Surname: "Garcia", + TelephoneNumber: "+1 (512) 555-1000", + UserPrincipalName: "maria.garcia@contoso.com" + } +]; + +// Helper functions for mock data manipulation +export const getUserById = (id: string): User | undefined => { + return mockUsers.find(user => user.Id === id); +}; + +export const searchUsers = (query: string, top: number = 50): User[] => { + if (!query.trim()) { + return []; + } + + const lowercaseQuery = query.toLowerCase(); + const filtered = mockUsers.filter(user => + user.DisplayName?.toLowerCase().includes(lowercaseQuery) || + user.Mail?.toLowerCase().includes(lowercaseQuery) || + user.Department?.toLowerCase().includes(lowercaseQuery) || + user.JobTitle?.toLowerCase().includes(lowercaseQuery) || + user.GivenName?.toLowerCase().includes(lowercaseQuery) || + user.Surname?.toLowerCase().includes(lowercaseQuery) + ); + + return filtered.slice(0, top); +}; + +export const getUsersByDepartment = (department: string): User[] => { + return mockUsers.filter(user => user.Department === department); +}; + +// Mock current user (for MyProfile functionality) +export const mockCurrentUser: User = { + Id: "550e8400-e29b-41d4-a716-446655440001", + AccountEnabled: true, + BusinessPhones: ["+1 (425) 555-0100"], + City: "Seattle", + CompanyName: "Contoso Corporation", + Country: "United States", + Department: "Engineering", + DisplayName: "Alex Johnson", + GivenName: "Alex", + JobTitle: "Senior Software Engineer", + Mail: "alex.johnson@contoso.com", + MailNickname: "alexj", + mobilePhone: "+1 (425) 555-0101", + OfficeLocation: "Building 1, Floor 3", + PostalCode: "98052", + Surname: "Johnson", + TelephoneNumber: "+1 (425) 555-0100", + UserPrincipalName: "alex.johnson@contoso.com" +}; diff --git a/samples/FluentSample/src/mockData/sqlData.ts b/samples/FluentSample/src/mockData/sqlData.ts new file mode 100644 index 0000000..3c31aa0 --- /dev/null +++ b/samples/FluentSample/src/mockData/sqlData.ts @@ -0,0 +1,243 @@ +// Mock data for SQL connector examples +// This file demonstrates the data structure expected from SQL connectors +// Replace this mock data with real SQL connector calls in your implementation + +export interface MockProject { + id: number; + name: string; + description: string; + status: 'Planning' | 'Active' | 'Completed' | 'On Hold'; + startDate: string; + endDate: string; + budget: number; + ownerId: number; + teamSize: number; + priority: 'Low' | 'Medium' | 'High' | 'Critical'; +} + +export interface MockTask { + id: number; + projectId: number; + title: string; + description: string; + status: 'Not Started' | 'In Progress' | 'Completed' | 'Blocked'; + assigneeId: number; + estimatedHours: number; + actualHours: number; + dueDate: string; + createdDate: string; + priority: 'Low' | 'Medium' | 'High' | 'Critical'; +} + +export interface MockEmployee { + id: number; + firstName: string; + lastName: string; + email: string; + department: string; + role: string; + hireDate: string; + salary: number; + managerId?: number; +} + +// Mock projects (100+ entries for pagination testing) +export const mockProjects: MockProject[] = [ + { + id: 1, + name: "Customer Portal Redesign", + description: "Complete redesign of the customer-facing portal with modern UI/UX", + status: "Active", + startDate: "2025-01-15", + endDate: "2025-06-30", + budget: 150000, + ownerId: 1, + teamSize: 8, + priority: "High" + }, + { + id: 2, + name: "Mobile App Development", + description: "Native mobile app for iOS and Android platforms", + status: "Planning", + startDate: "2025-03-01", + endDate: "2025-12-31", + budget: 300000, + ownerId: 2, + teamSize: 12, + priority: "Critical" + }, + { + id: 3, + name: "Database Migration", + description: "Migrate legacy database to cloud infrastructure", + status: "Completed", + startDate: "2024-08-01", + endDate: "2024-12-15", + budget: 75000, + ownerId: 3, + teamSize: 5, + priority: "Medium" + }, + // Generate additional projects for pagination + ...Array.from({ length: 97 }, (_, i) => ({ + id: i + 4, + name: `Project ${i + 4}`, + description: `Description for project ${i + 4}`, + status: ['Planning', 'Active', 'Completed', 'On Hold'][i % 4] as MockProject['status'], + startDate: new Date(2025, (i % 12), 1).toISOString().split('T')[0], + endDate: new Date(2025, (i % 12) + 6, 30).toISOString().split('T')[0], + budget: Math.floor(Math.random() * 500000) + 50000, + ownerId: (i % 10) + 1, + teamSize: Math.floor(Math.random() * 15) + 3, + priority: ['Low', 'Medium', 'High', 'Critical'][i % 4] as MockProject['priority'] + })) +]; + +// Mock tasks +export const mockTasks: MockTask[] = [ + { + id: 1, + projectId: 1, + title: "UI Wireframe Creation", + description: "Create wireframes for all major portal pages", + status: "Completed", + assigneeId: 4, + estimatedHours: 40, + actualHours: 35, + dueDate: "2025-02-15", + createdDate: "2025-01-20", + priority: "High" + }, + { + id: 2, + projectId: 1, + title: "Frontend Development", + description: "Implement responsive frontend using React and TypeScript", + status: "In Progress", + assigneeId: 5, + estimatedHours: 120, + actualHours: 85, + dueDate: "2025-04-30", + createdDate: "2025-02-01", + priority: "High" + }, + { + id: 3, + projectId: 2, + title: "Market Research", + description: "Research competitor apps and user requirements", + status: "Completed", + assigneeId: 6, + estimatedHours: 80, + actualHours: 75, + dueDate: "2025-02-28", + createdDate: "2025-01-15", + priority: "Critical" + }, + // Generate more tasks + ...Array.from({ length: 47 }, (_, i) => ({ + id: i + 4, + projectId: Math.floor(i / 5) + 1, + title: `Task ${i + 4}`, + description: `Description for task ${i + 4}`, + status: ['Not Started', 'In Progress', 'Completed', 'Blocked'][i % 4] as MockTask['status'], + assigneeId: (i % 20) + 1, + estimatedHours: Math.floor(Math.random() * 80) + 10, + actualHours: Math.floor(Math.random() * 60) + 5, + dueDate: new Date(2025, (i % 12), Math.floor(Math.random() * 28) + 1).toISOString().split('T')[0], + createdDate: new Date(2025, Math.max(0, (i % 12) - 1), 1).toISOString().split('T')[0], + priority: ['Low', 'Medium', 'High', 'Critical'][i % 4] as MockTask['priority'] + })) +]; + +// Mock employees +export const mockEmployees: MockEmployee[] = [ + { + id: 1, + firstName: "Alice", + lastName: "Johnson", + email: "alice.johnson@company.com", + department: "Engineering", + role: "Senior Software Engineer", + hireDate: "2022-03-15", + salary: 95000, + managerId: 10 + }, + { + id: 2, + firstName: "Bob", + lastName: "Smith", + email: "bob.smith@company.com", + department: "Product", + role: "Product Manager", + hireDate: "2021-07-22", + salary: 110000, + managerId: 11 + }, + // Generate more employees + ...Array.from({ length: 48 }, (_, i) => ({ + id: i + 3, + firstName: `FirstName${i + 3}`, + lastName: `LastName${i + 3}`, + email: `employee${i + 3}@company.com`, + department: ['Engineering', 'Product', 'Design', 'Marketing', 'Sales'][i % 5], + role: ['Engineer', 'Manager', 'Designer', 'Analyst', 'Specialist'][i % 5], + hireDate: new Date(2020 + (i % 5), i % 12, (i % 28) + 1).toISOString().split('T')[0], + salary: Math.floor(Math.random() * 100000) + 50000, + managerId: i < 10 ? undefined : Math.floor(i / 10) + 1 + })) +]; + +// Helper functions for mock SQL operations +export const getProjectById = (id: number): MockProject | undefined => { + return mockProjects.find(project => project.id === id); +}; + +export const getTasksByProjectId = (projectId: number): MockTask[] => { + return mockTasks.filter(task => task.projectId === projectId); +}; + +export const getEmployeeById = (id: number): MockEmployee | undefined => { + return mockEmployees.find(employee => employee.id === id); +}; + +export const searchProjects = (query: string): MockProject[] => { + const lowercaseQuery = query.toLowerCase(); + return mockProjects.filter(project => + project.name.toLowerCase().includes(lowercaseQuery) || + project.description.toLowerCase().includes(lowercaseQuery) || + project.status.toLowerCase().includes(lowercaseQuery) + ); +}; + +export const filterProjectsByStatus = (status: MockProject['status']): MockProject[] => { + return mockProjects.filter(project => project.status === status); +}; + +export const createMockProject = (project: Omit): MockProject => { + const newId = Math.max(...mockProjects.map(p => p.id)) + 1; + const newProject = { ...project, id: newId }; + mockProjects.push(newProject); + return newProject; +}; + +export const updateMockProject = (id: number, updates: Partial): MockProject | null => { + const projectIndex = mockProjects.findIndex(p => p.id === id); + if (projectIndex === -1) return null; + + mockProjects[projectIndex] = { ...mockProjects[projectIndex], ...updates }; + return mockProjects[projectIndex]; +}; + +export const deleteMockProject = (id: number): boolean => { + const projectIndex = mockProjects.findIndex(p => p.id === id); + if (projectIndex === -1) return false; + + mockProjects.splice(projectIndex, 1); + // Also delete associated tasks + const taskIndicesToDelete = mockTasks.map((task, index) => task.projectId === id ? index : -1).filter(i => i !== -1); + taskIndicesToDelete.reverse().forEach(index => mockTasks.splice(index, 1)); + + return true; +}; diff --git a/samples/FluentSample/src/pages/CustomApiPage.tsx b/samples/FluentSample/src/pages/CustomApiPage.tsx new file mode 100644 index 0000000..f46b3c3 --- /dev/null +++ b/samples/FluentSample/src/pages/CustomApiPage.tsx @@ -0,0 +1,190 @@ +import { Text, Card, makeStyles, shorthands, tokens, Button, Badge, Tooltip } from '@fluentui/react-components'; +import { CloudRegular } from '@fluentui/react-icons'; +import PageHeader from '../components/PageHeader'; +import { mockAssets, Asset } from '../mockData/customApiData'; +import { useState, useEffect } from 'react'; + +const useStyles = makeStyles({ + container: { + maxWidth: '1200px', + ...shorthands.margin('0', 'auto'), + }, + section: { + marginBottom: '32px', + }, + sectionTitle: { + fontSize: tokens.fontSizeBase400, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + marginBottom: '16px', + }, + dataGrid: { + overflow: 'auto', + border: `1px solid ${tokens.colorNeutralStroke2}`, + borderRadius: tokens.borderRadiusMedium, + backgroundColor: tokens.colorNeutralBackground1, + }, + mockDataBadge: { + marginBottom: '16px', + }, + +}); + +export default function CustomApiPage() { + const styles = useStyles(); + const [assets, setAssets] = useState([]); + const [loadingAssets, setLoadingAssets] = useState(true); + const [error, setError] = useState(null); + + // Load mock assets data (simulating API call) + useEffect(() => { + loadAssets(); + }, []); + + const loadAssets = async () => { + try { + setLoadingAssets(true); + setError(null); + + // Simulate API loading delay + await new Promise(resolve => setTimeout(resolve, 800)); + + // Use static mock data instead of live API + setAssets(mockAssets); + } catch (err) { + setError(err instanceof Error ? err.message : 'An error occurred while loading assets'); + setAssets([]); + } finally { + setLoadingAssets(false); + } + }; + + const getStatusColor = (status: string) => { + switch (status) { + case 'Available': return 'success'; + case 'In Use': return 'brand'; + case 'Maintenance': return 'warning'; + case 'Active': return 'success'; + case 'Inactive': case 'Retired': return 'danger'; + default: return 'subtle'; + } + }; + + return ( +
+ } + /> + + + πŸ“‹ Template Mode - Static Data + + + {/* Sample Data */} +
+

πŸ“¦ Sample Assets Data

+ + {loadingAssets ? ( + + Loading sample assets data... + + ) : error ? ( + + + Error loading assets: {error} + + + + ) : ( + +
+ + πŸ”— Template Ready for Your Custom Connector + + + Replace mockAssets with your custom connector service calls to connect to real data. + +
+
+ )} + + {!loadingAssets && !error && ( + +
+ + + + + + + + + + + {assets.map((asset, index) => ( + + + + + + + ))} + +
Asset IDAsset NameTypeStatus
+ + + {asset.id} + + + + +
+ {asset.name} +
+
+
+ {asset.type} + + + {asset.status} + +
+
+
+ )} +
+ + {/* Integration Note */} + + + οΏ½ Getting Started with Your Custom Connector + + + This template demonstrates Power Platform custom connector integration patterns. To connect to your real API: + 1) Create your custom connector in Power Platform, 2) Generate the connector service using Power Apps SDK, + 3) Replace the mockAssets import with your real connector service calls. + The DataGrid table structure and error handling patterns are ready for your data. + + +
+ ); +} diff --git a/samples/FluentSample/src/pages/HomePage.tsx b/samples/FluentSample/src/pages/HomePage.tsx new file mode 100644 index 0000000..b23c631 --- /dev/null +++ b/samples/FluentSample/src/pages/HomePage.tsx @@ -0,0 +1,293 @@ +import { + Text, + Card, + makeStyles, + shorthands, + Link, + tokens +} from '@fluentui/react-components'; +import { + PeopleRegular, + DatabaseRegular, + CloudRegular, + ArrowRightRegular +} from '@fluentui/react-icons'; +import { useNavigate } from 'react-router-dom'; + +const useStyles = makeStyles({ + container: { + maxWidth: '1200px', + ...shorthands.margin('0', 'auto'), + }, + powerAppsLove: { + textAlign: 'center', + ...shorthands.padding('64px', '24px'), + backgroundColor: tokens.colorNeutralBackground2, + ...shorthands.borderRadius(tokens.borderRadiusLarge), + ...shorthands.border('2px', 'solid', tokens.colorNeutralStroke2), + marginBottom: '48px', + }, + loveText: { + fontSize: '48px', + fontWeight: tokens.fontWeightBold, + color: tokens.colorBrandForeground1, + marginBottom: '16px', + textShadow: `0 2px 4px ${tokens.colorNeutralShadowAmbient}`, + }, + loveSubtext: { + fontSize: tokens.fontSizeBase400, + color: tokens.colorNeutralForeground2, + fontStyle: 'italic', + }, + section: { + marginBottom: '48px', + }, + sectionTitle: { + fontSize: tokens.fontSizeBase600, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + marginBottom: '16px', + }, + grid: { + display: 'grid', + gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', + ...shorthands.gap('24px'), + }, + card: { + height: '100%', + cursor: 'pointer', + transition: 'transform 0.2s ease, box-shadow 0.2s ease', + ...shorthands.border('1px', 'solid', tokens.colorNeutralStroke2), + '&:hover': { + transform: 'translateY(-2px)', + boxShadow: `0 8px 24px ${tokens.colorNeutralShadowAmbient}`, + ...shorthands.border('1px', 'solid', tokens.colorBrandStroke1), + }, + }, + cardIcon: { + fontSize: '48px', + color: tokens.colorBrandForeground1, + marginBottom: '16px', + }, + cardTitle: { + fontSize: tokens.fontSizeBase400, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + marginBottom: '8px', + }, + cardDescription: { + fontSize: tokens.fontSizeBase300, + color: tokens.colorNeutralForeground2, + lineHeight: tokens.lineHeightBase300, + marginBottom: '16px', + }, + cardButton: { + marginTop: 'auto', + }, + featuresGrid: { + display: 'grid', + gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', + ...shorthands.gap('20px'), + marginTop: '24px', + }, + featureCard: { + ...shorthands.padding('24px'), + textAlign: 'center', + }, + featureIcon: { + fontSize: '32px', + color: tokens.colorPaletteGreenForeground1, + marginBottom: '12px', + }, + featureTitle: { + fontSize: tokens.fontSizeBase300, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + marginBottom: '8px', + }, + featureDescription: { + fontSize: tokens.fontSizeBase200, + color: tokens.colorNeutralForeground2, + lineHeight: tokens.lineHeightBase200, + }, +}); + +const connectorExamples = [ + { + path: '/office365', + title: 'Office 365 Connector', + description: 'Explore user profiles and organizational directory integration with live Office 365 data. Learn how to implement authentication and user search patterns.', + icon: , + features: ['User Profiles', 'Directory Search', 'User Photos', 'Live Integration'], + }, + { + path: '/sql', + title: 'SQL Database Connector Template', + description: 'Practice SQL database integration with this ready-to-use template featuring static data. Includes pagination, search, data generation, and professional UI patterns - perfect for learning before connecting to real databases.', + icon: , + features: ['Template Mode', 'Static Data', 'Pagination & Search', 'Easy Real Data Migration'], + }, + { + path: '/custom-api', + title: 'Custom API Connector Template', + description: 'Learn custom connector integration patterns with this ready-to-use template featuring static data. Includes DataGrid table, error handling, and clear guidance for connecting to real APIs.', + icon: , + features: ['Template Mode', 'Static Data', 'DataGrid Table', 'Easy Real Data Migration'], + }, +]; + +export default function HomePage() { + const styles = useStyles(); + const navigate = useNavigate(); + + return ( +
+ {/* Power Apps Love Code Section - Now the Hero */} +
+
Power Apps ❀️ Code
+ + Building amazing experiences with modern web technologies + +
+ + {/* Examples Section */} +
+

Examples

+ + Each example shows UI components, data handling and integration points where you can replace mock data with data from your Power Platform environment, using Power Apps SDK. + + +
+ {connectorExamples.map((example) => ( + navigate(example.path)} + onMouseEnter={(e: React.MouseEvent) => { + e.currentTarget.style.transform = 'translateY(-4px)'; + e.currentTarget.style.boxShadow = tokens.shadow16; + }} + onMouseLeave={(e: React.MouseEvent) => { + e.currentTarget.style.transform = 'translateY(0)'; + e.currentTarget.style.boxShadow = tokens.shadow4; + }} + > +
+
{example.icon}
+
+ +
+ + {example.title} + + + + {example.description} + + +
+ {example.features.map((feature, index) => ( + + {feature} + + ))} +
+ +
+ Explore Example + +
+
+
+ ))} +
+
+ + {/* Getting Started Section */} +
+ +

Getting Started

+ + This template is designed to help you learn Power Apps Code Apps patterns and provide + a foundation for your own projects. + + +
+
+ + 1. Explore Examples + + + Navigate through each connector example to see different patterns and UI components in action. + +
+ +
+ + 2. Understand the Code + + + Review the source code, comments, and mock data structures to understand implementation patterns. + +
+ +
+ + 3. Add Real Connectors + + + Replace mock data with real Power Apps connectors using the clear integration points provided. + +
+
+ +
+ + Learn more about Power Apps Code Apps β†’ + +
+
+
+
+ ); +} diff --git a/samples/FluentSample/src/pages/Office365Page.tsx b/samples/FluentSample/src/pages/Office365Page.tsx new file mode 100644 index 0000000..2fb5d07 --- /dev/null +++ b/samples/FluentSample/src/pages/Office365Page.tsx @@ -0,0 +1,411 @@ +import { Text, Card, makeStyles, shorthands, tokens, Input, Badge, Spinner, Avatar } from '@fluentui/react-components'; +import { PeopleRegular, SearchRegular, PersonRegular } from '@fluentui/react-icons'; +import PageHeader from '../components/PageHeader'; +import { useState, useEffect, useCallback } from 'react'; +// TODO: Replace with live Office365UsersService when connecting to real data +// import { Office365UsersService } from '../Services/Office365UsersService'; +import * as mockData from '../mockData/office365Data'; +import type { User } from '../mockData/office365Data'; + +const useStyles = makeStyles({ + container: { + maxWidth: '1200px', + ...shorthands.margin('0', 'auto'), + backgroundColor: tokens.colorNeutralBackground1, + }, + section: { + marginBottom: '32px', + }, + sectionHeader: { + display: 'flex', + alignItems: 'center', + ...shorthands.gap('12px'), + marginBottom: '16px', + }, + sectionIcon: { + fontSize: '20px', + color: tokens.colorBrandForeground1, + }, + sectionTitle: { + fontSize: tokens.fontSizeBase400, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + }, + grid: { + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', + ...shorthands.gap('16px'), + }, + userCard: { + ...shorthands.padding('16px'), + height: 'fit-content', + backgroundColor: tokens.colorNeutralBackground1, + }, + userCardHeader: { + display: 'flex', + alignItems: 'center', + ...shorthands.gap('12px'), + marginBottom: '8px', + }, + userName: { + fontSize: tokens.fontSizeBase300, + fontWeight: tokens.fontWeightSemibold, + color: tokens.colorNeutralForeground1, + marginBottom: '4px', + }, + userDetails: { + fontSize: tokens.fontSizeBase200, + color: tokens.colorNeutralForeground2, + lineHeight: tokens.lineHeightBase200, + }, + searchBox: { + maxWidth: '600px', + width: '100%', + marginBottom: '16px', + }, + mockDataBadge: { + marginBottom: '16px', + }, +}); + +export default function Office365Page() { + const styles = useStyles(); + const [searchTerm, setSearchTerm] = useState(''); + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(false); + const [currentUser, setCurrentUser] = useState(null); + const [userPhotos, setUserPhotos] = useState>({}); + + // Load current user profile + useEffect(() => { + const loadCurrentUser = async () => { + try { + // TODO: Replace with live Office365UsersService.MyProfile() when connecting to real data + // const result = await Office365UsersService.MyProfile(); + // if (result.data) { + // setCurrentUser(result.data); + // // Load the current user's photo + // const photo = await loadUserPhoto(result.data.Id); + // if (photo) { + // setUserPhotos(prev => ({ ...prev, [result.data.Id]: photo })); + // } + // } + + // Using mock data for demonstration + setCurrentUser(mockData.mockCurrentUser); + // Mock users don't have real photos, so we'll simulate loading + console.log('Loaded current user profile (mock data):', mockData.mockCurrentUser.DisplayName); + } catch (error) { + console.error('Error loading current user:', error); + // Fallback: show message that Office 365 connection is available but may need permissions + } + }; + loadCurrentUser(); + }, []); + + // Load user photo + const loadUserPhoto = async (userId: string): Promise => { + try { + // TODO: Replace with live Office365UsersService.UserPhoto() when connecting to real data + // const result = await Office365UsersService.UserPhoto(userId); + // if (result.data) { + // // The photo comes as base64 data, create a data URL + // return `data:image/jpeg;base64,${result.data}`; + // } + + // For mock data, we don't have real photos + // In a real implementation, this would fetch actual user photos + console.log(`Mock: Would load photo for user ${userId}`); + } catch (error) { + console.error(`Error loading photo for user ${userId}:`, error); + } + return null; + }; + + // Helper function to load user photos + const loadPhotosForUsers = useCallback(async (newUsers: User[]) => { + const photoPromises = newUsers.map(async (user: User) => { + const photo = await loadUserPhoto(user.Id); + return { userId: user.Id, photo }; + }); + + const photoResults = await Promise.all(photoPromises); + const photoMap: Record = {}; + photoResults.forEach(({ userId, photo }: { userId: string, photo: string | null }) => { + if (photo) { + photoMap[userId] = photo; + } + }); + + setUserPhotos(prev => ({ ...prev, ...photoMap })); + }, []); + + // Search users with simple SearchUser approach + useEffect(() => { + const searchUsers = async () => { + // If search term is empty, clear users and don't search + if (!searchTerm.trim()) { + setUsers([]); + setLoading(false); + return; + } + + setLoading(true); + setUsers([]); // Clear existing users when starting new search + + try { + console.log('Searching users with term:', searchTerm); + + // TODO: Replace with live Office365UsersService.SearchUser() when connecting to real data + // const pageSize = 50; + // const result = await Office365UsersService.SearchUser( + // searchTerm.trim(), + // pageSize + // ); + // + // if (result.success && result.data) { + // setUsers(result.data); + // console.log('Users loaded:', result.data.length); + // + // // Load photos for the users + // await loadPhotosForUsers(result.data); + // } else { + // console.error('Search failed:', result.errorMessage); + // setUsers([]); + // } + + // Using mock data for demonstration + const pageSize = 50; + const mockResults = mockData.searchUsers(searchTerm.trim(), pageSize); + setUsers(mockResults); + console.log('Users loaded (mock data):', mockResults.length); + + // Simulate photo loading (no actual photos in mock data) + await loadPhotosForUsers(mockResults); + + } catch (error) { + console.error('Error searching users:', error); + setUsers([]); + } finally { + setLoading(false); + } + }; + + // Add debouncing to avoid too many API calls + const debounceTimer = setTimeout(searchUsers, 500); + return () => clearTimeout(debounceTimer); + }, [searchTerm, loadPhotosForUsers]); + + return ( +
+ } + /> + + {currentUser ? ( + + πŸ“‹ Demo Mode - Using Mock Data (Welcome, {currentUser.DisplayName}!) + + ) : ( + + πŸ”„ Loading user data... + + )} + + {/* Information Note */} + +
+ + πŸ’‘ Ask Copilot to convert to live Office 365 Connector + + + πŸ“š For more information, check out our{' '} + + data connection guide + πŸ”— + +
+
+ + {/* Current User Profile Section */} + {currentUser && ( +
+
+ +

My Profile

+
+ + +
+ +
+
+ {currentUser.DisplayName} +
+
+ {currentUser.JobTitle} +
+
+
+
+
+
+
Email: {currentUser.Mail || 'Not available'}
+
User Principal: {currentUser.UserPrincipalName || 'Not available'}
+
Department: {currentUser.Department || 'Not specified'}
+
Company: {currentUser.CompanyName || 'Not specified'}
+
+
+
Office: {currentUser.OfficeLocation || 'Not specified'}
+
Mobile: {currentUser.mobilePhone || 'Not available'}
+
Business Phone: {currentUser.BusinessPhones?.length ? currentUser.BusinessPhones[0] : 'Not available'}
+
City: {currentUser.City || 'Not specified'}
+
+
+ + {(currentUser.GivenName || currentUser.Surname || currentUser.Country || currentUser.PostalCode) && ( +
+
+
+ {currentUser.GivenName &&
First Name: {currentUser.GivenName}
} + {currentUser.Surname &&
Last Name: {currentUser.Surname}
} +
+
+ {currentUser.Country &&
Country: {currentUser.Country}
} + {currentUser.PostalCode &&
Postal Code: {currentUser.PostalCode}
} +
+
+
+ )} + +
+
Account Status: {currentUser.AccountEnabled ? 'βœ… Active' : '❌ Disabled'}
+
+
+
+
+ )} + + {/* Users Section */} +
+
+ +

Organization Directory

+
+ + } + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} + /> + +
+ {loading && users.length === 0 && ( +
+ +
+ )} + {users.map((user: User) => ( + +
+ +
+
{user.DisplayName}
+
+ {user.JobTitle || 'No title specified'} +
+
+
+
+
+
+
Email: {user.Mail || 'Not available'}
+
Department: {user.Department || 'Not specified'}
+
Office: {user.OfficeLocation || 'Not specified'}
+ {user.mobilePhone &&
Mobile: {user.mobilePhone}
} + {user.BusinessPhones?.length &&
Business Phone: {user.BusinessPhones[0]}
} +
+
+ + {(user.CompanyName || user.City || user.Country) && ( +
+ {user.CompanyName &&
Company: {user.CompanyName}
} + {user.City &&
City: {user.City}
} + {user.Country &&
Country: {user.Country}
} +
+ )} + +
+
Status: {user.AccountEnabled ? 'βœ… Active' : '❌ Disabled'}
+
+
+
+ ))} + {!loading && !searchTerm.trim() && ( +
+ +
Enter a search term to find users in your organization
+
+ )} + {!loading && searchTerm && users.length === 0 && ( +
+ +
No users found for "{searchTerm}"
+
+ )} +
+ + {users.length > 0 && ( + + Showing {users.length} users + + )} +
+ + {/* Integration Note */} + +
+ + πŸ’‘ Currently using mock data - Ask Copilot to convert to live Office 365 Connector + + + πŸ“š For more information on connecting to live data, check out our{' '} + + data connection guide + πŸ”— + +
+
+
+ ); +} diff --git a/samples/FluentSample/src/pages/SqlPage.tsx b/samples/FluentSample/src/pages/SqlPage.tsx new file mode 100644 index 0000000..480da22 --- /dev/null +++ b/samples/FluentSample/src/pages/SqlPage.tsx @@ -0,0 +1,783 @@ +import React from 'react'; +import { + SearchBox, + makeStyles, + Spinner, + MessageBar, + Button, + Input, + Label, + Card, + Text, + Badge, + Tooltip, + tokens, + InputOnChangeData, + SearchBoxChangeEvent, +} from '@fluentui/react-components'; +import { + DatabaseRegular, + ErrorCircleRegular, + SearchRegular, + ChevronLeftRegular, + ChevronRightRegular, + AddRegular, +} from '@fluentui/react-icons'; +import PageHeader from '../components/PageHeader'; + +// Projects type definition - matches SQL database structure +interface Projects { + ProjectId?: number; + Name: string; + Description?: string; + StartDate?: string; + EndDate?: string; + Status: string; + Priority: string; + Budget?: number; + ProjectManagerEmail: string; + CreatedBy?: string; + CreatedDate?: string; + IsActive?: boolean; +} + +// Styling +const useStyles = makeStyles({ + container: { + padding: '24px', + maxWidth: '1400px', + margin: '0 auto', + display: 'flex', + flexDirection: 'column', + gap: '24px', + }, + searchContainer: { + display: 'flex', + gap: '16px', + alignItems: 'flex-end', + marginBottom: '16px', + }, + dataGrid: { + overflow: 'auto', + border: `1px solid ${tokens.colorNeutralStroke2}`, + borderRadius: tokens.borderRadiusMedium, + backgroundColor: tokens.colorNeutralBackground1, + }, + paginationContainer: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '16px', + borderTop: `1px solid ${tokens.colorNeutralStroke2}`, + backgroundColor: tokens.colorNeutralBackground2, + }, + paginationInfo: { + fontSize: tokens.fontSizeBase200, + color: tokens.colorNeutralForeground2, + }, + paginationButtons: { + display: 'flex', + gap: '8px', + }, + messageBar: { + marginBottom: '16px', + }, + generateSection: { + padding: '16px', + backgroundColor: tokens.colorNeutralBackground2, + borderRadius: tokens.borderRadiusMedium, + border: `1px solid ${tokens.colorNeutralStroke2}`, + marginBottom: '24px', + }, + generateControls: { + display: 'flex', + gap: '16px', + alignItems: 'flex-end', + marginTop: '12px', + }, +}); + +// String constants +const STRINGS = { + LOADING_MESSAGE: 'Loading projects...', + ERROR_MESSAGE: 'Unable to load projects. Please check your connection and try again.', + SEARCH_PLACEHOLDER: 'Search projects...', + NO_RESULTS_MESSAGE: 'No projects found matching your search.', + ARIA_LABEL_DATA_GRID: 'Projects data grid', + GENERATE_DATA_TITLE: 'Generate Sample Data', + GENERATE_DATA_DESCRIPTION: 'Add test projects to the static data set', + GENERATE_RECORDS_LABEL: 'Number of records to generate', + GENERATE_BUTTON: 'Generate Projects', + GENERATING_MESSAGE: 'Generating sample data...', + GENERATION_SUCCESS: 'Successfully generated {count} projects!', + GENERATION_ERROR: 'Failed to generate sample data.', + GENERATION_DISABLED: 'Template mode - Sample data generation simulates adding to mock data', + PAGINATION_PREVIOUS: 'Previous page', + PAGINATION_NEXT: 'Next page', + PAGINATION_PAGE_INFO: 'Page {current} of {total}', +} as const; + +// Mock data that matches the SQL database structure +const MOCK_PROJECTS: Projects[] = [ + { + ProjectId: 1, + Name: 'Digital Transformation Initiative 1', + Description: 'Modernize legacy systems and improve operational efficiency', + StartDate: '2024-03-15T00:00:00.000Z', + EndDate: '2024-12-31T00:00:00.000Z', + Status: 'Active', + Priority: 'High', + Budget: 250000, + ProjectManagerEmail: 'john.smith@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-01-15T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 2, + Name: 'Customer Portal Redesign 1', + Description: 'Enhance user experience and streamline customer interactions', + StartDate: '2024-02-01T00:00:00.000Z', + EndDate: '2024-08-30T00:00:00.000Z', + Status: 'Planning', + Priority: 'Medium', + Budget: 180000, + ProjectManagerEmail: 'sarah.johnson@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-01-20T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 3, + Name: 'Mobile App Development 1', + Description: 'Develop native mobile applications for iOS and Android', + StartDate: '2024-04-01T00:00:00.000Z', + EndDate: '2025-01-15T00:00:00.000Z', + Status: 'Active', + Priority: 'Critical', + Budget: 320000, + ProjectManagerEmail: 'mike.wilson@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-03-01T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 4, + Name: 'Data Analytics Platform 1', + Description: 'Build comprehensive analytics and reporting capabilities', + StartDate: '2024-01-15T00:00:00.000Z', + EndDate: '2024-10-31T00:00:00.000Z', + Status: 'Completed', + Priority: 'High', + Budget: 420000, + ProjectManagerEmail: 'lisa.brown@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2023-12-15T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 5, + Name: 'Cloud Migration Project 1', + Description: 'Migrate on-premises infrastructure to cloud services', + StartDate: '2024-05-01T00:00:00.000Z', + EndDate: '2024-11-30T00:00:00.000Z', + Status: 'On Hold', + Priority: 'Medium', + Budget: 380000, + ProjectManagerEmail: 'david.davis@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-04-01T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 6, + Name: 'Security Enhancement Program 1', + Description: 'Implement advanced security measures and compliance standards', + StartDate: '2024-03-01T00:00:00.000Z', + EndDate: '2024-09-30T00:00:00.000Z', + Status: 'Active', + Priority: 'Critical', + Budget: 290000, + ProjectManagerEmail: 'john.smith@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-02-15T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 7, + Name: 'Process Automation Suite 1', + Description: 'Automate manual processes to reduce operational overhead', + StartDate: '2024-06-01T00:00:00.000Z', + EndDate: '2025-02-28T00:00:00.000Z', + Status: 'Planning', + Priority: 'Low', + Budget: 150000, + ProjectManagerEmail: 'sarah.johnson@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-05-15T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 8, + Name: 'User Experience Optimization 1', + Description: 'Optimize user interfaces for better usability and engagement', + StartDate: '2024-04-15T00:00:00.000Z', + EndDate: '2024-10-15T00:00:00.000Z', + Status: 'Active', + Priority: 'Medium', + Budget: 200000, + ProjectManagerEmail: 'mike.wilson@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-03-20T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 9, + Name: 'API Integration Platform 1', + Description: 'Create unified API layer for system integration', + StartDate: '2024-07-01T00:00:00.000Z', + EndDate: '2025-01-31T00:00:00.000Z', + Status: 'Planning', + Priority: 'High', + Budget: 350000, + ProjectManagerEmail: 'lisa.brown@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-06-15T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 10, + Name: 'Business Intelligence Dashboard 1', + Description: 'Develop real-time business intelligence and reporting tools', + StartDate: '2024-08-01T00:00:00.000Z', + EndDate: '2025-03-31T00:00:00.000Z', + Status: 'Planning', + Priority: 'Medium', + Budget: 280000, + ProjectManagerEmail: 'david.davis@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-07-15T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 11, + Name: 'Digital Transformation Initiative 2', + Description: 'Modernize legacy systems and improve operational efficiency', + StartDate: '2024-09-01T00:00:00.000Z', + EndDate: '2025-05-31T00:00:00.000Z', + Status: 'Planning', + Priority: 'Low', + Budget: 190000, + ProjectManagerEmail: 'john.smith@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-08-15T00:00:00.000Z', + IsActive: true + }, + { + ProjectId: 12, + Name: 'Customer Portal Redesign 2', + Description: 'Enhance user experience and streamline customer interactions', + StartDate: '2024-10-01T00:00:00.000Z', + EndDate: '2025-04-30T00:00:00.000Z', + Status: 'Planning', + Priority: 'Medium', + Budget: 220000, + ProjectManagerEmail: 'sarah.johnson@company.com', + CreatedBy: 'system@company.com', + CreatedDate: '2024-09-15T00:00:00.000Z', + IsActive: true + } +]; + +// TEMPLATE: Data service abstraction - Replace this with real API integration +class ProjectsDataService { + // TEMPLATE: Replace this method with real API calls to your SQL database + static async getAll(options?: { + top?: number; + skip?: number; + filter?: string; + orderBy?: string[]; + select?: string[]; + }): Promise<{ success: boolean; data: Projects[]; total: number }> { + // Simulate API delay + await new Promise(resolve => setTimeout(resolve, 300)); + + let filteredData = [...MOCK_PROJECTS]; + + // Apply search filter + if (options?.filter) { + const searchTerm = this.extractSearchTerm(options.filter); + if (searchTerm) { + filteredData = filteredData.filter(project => + project.Name.toLowerCase().includes(searchTerm.toLowerCase()) || + (project.Description || '').toLowerCase().includes(searchTerm.toLowerCase()) || + project.Status.toLowerCase().includes(searchTerm.toLowerCase()) || + project.Priority.toLowerCase().includes(searchTerm.toLowerCase()) || + project.ProjectManagerEmail.toLowerCase().includes(searchTerm.toLowerCase()) + ); + } + } + + // Apply ordering + if (options?.orderBy?.includes('Name')) { + filteredData.sort((a, b) => a.Name.localeCompare(b.Name)); + } + + const total = filteredData.length; + + // Apply pagination + if (options?.skip !== undefined && options?.top !== undefined) { + filteredData = filteredData.slice(options.skip, options.skip + options.top); + } + + return { success: true, data: filteredData, total }; + } + + // TEMPLATE: Replace this method with real API calls to create projects + static async create(project: Omit): Promise<{ success: boolean; data: Projects }> { + // Simulate API delay + await new Promise(resolve => setTimeout(resolve, 500)); + + const newProject: Projects = { + ...project, + ProjectId: Math.max(...MOCK_PROJECTS.map(p => p.ProjectId || 0)) + 1 + }; + + MOCK_PROJECTS.push(newProject); + + return { success: true, data: newProject }; + } + + private static extractSearchTerm(filter: string): string | null { + // Extract search term from OData filter string + const match = filter.match(/contains\([^,]+,\s*'([^']+)'\)/); + return match ? match[1] : null; + } +} + +// Main component +const SqlPage: React.FC = () => { + const styles = useStyles(); + const [currentPage, setCurrentPage] = React.useState(1); + const [searchTerm, setSearchTerm] = React.useState(''); + const [debouncedSearchTerm, setDebouncedSearchTerm] = React.useState(''); + const [recordCount, setRecordCount] = React.useState(5); + const [isGenerating, setIsGenerating] = React.useState(false); + const [generationMessage, setGenerationMessage] = React.useState(''); + + // State for project data + const [projects, setProjects] = React.useState([]); + const [totalRecords, setTotalRecords] = React.useState(0); + const [isLoading, setIsLoading] = React.useState(false); + const [error, setError] = React.useState(null); + + const recordsPerPage = 10; + const totalPages = Math.max(1, Math.ceil(totalRecords / recordsPerPage)); + + // Debounce search term + React.useEffect(() => { + const timer = setTimeout(() => { + setDebouncedSearchTerm(searchTerm); + setCurrentPage(1); // Reset to first page when searching + }, 300); + + return () => clearTimeout(timer); + }, [searchTerm]); + + // Load project data + const loadProjects = React.useCallback(async () => { + setIsLoading(true); + setError(null); + + try { + // Get total count first + const countResult = await ProjectsDataService.getAll({ + filter: debouncedSearchTerm + ? `contains(tolower(Name),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(Description),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(Status),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(Priority),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(ProjectManagerEmail),'${debouncedSearchTerm.toLowerCase()}')` + : undefined + }); + + if (!countResult.success) { + throw new Error('Failed to load projects count'); + } + + setTotalRecords(countResult.total); + + // Get paginated data + const result = await ProjectsDataService.getAll({ + top: recordsPerPage, + skip: (currentPage - 1) * recordsPerPage, + orderBy: ['Name'], + filter: debouncedSearchTerm + ? `contains(tolower(Name),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(Description),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(Status),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(Priority),'${debouncedSearchTerm.toLowerCase()}') or contains(tolower(ProjectManagerEmail),'${debouncedSearchTerm.toLowerCase()}')` + : undefined + }); + + if (!result.success) { + throw new Error('Failed to load projects'); + } + + setProjects(result.data); + } catch (err) { + setError(err instanceof Error ? err.message : 'An error occurred'); + setProjects([]); + setTotalRecords(0); + } finally { + setIsLoading(false); + } + }, [currentPage, debouncedSearchTerm]); + + // Load projects when dependencies change + React.useEffect(() => { + loadProjects(); + }, [loadProjects]); + + // Ensure current page is valid + React.useEffect(() => { + if (currentPage > totalPages && totalPages > 0) { + setCurrentPage(totalPages); + } + }, [currentPage, totalPages]); + + const generateSampleData = React.useCallback(async () => { + setIsGenerating(true); + setGenerationMessage(STRINGS.GENERATING_MESSAGE); + + try { + for (let i = 0; i < recordCount; i++) { + const projectData = { + Name: `Generated Project ${Date.now()}-${i + 1}`, + Description: `This is a test project generated on ${new Date().toLocaleDateString()}`, + StartDate: new Date().toISOString(), + EndDate: new Date(Date.now() + 180 * 24 * 60 * 60 * 1000).toISOString(), // 6 months from now + Status: ['Planning', 'Active', 'Completed', 'On Hold'][Math.floor(Math.random() * 4)], + Priority: ['Low', 'Medium', 'High', 'Critical'][Math.floor(Math.random() * 4)], + Budget: Math.floor(Math.random() * 500000) + 50000, + ProjectManagerEmail: `manager${i + 1}@company.com`, + CreatedBy: 'generator@company.com', + CreatedDate: new Date().toISOString(), + IsActive: true + }; + + const result = await ProjectsDataService.create(projectData); + if (!result.success) { + throw new Error('Failed to create project'); + } + } + + setGenerationMessage(STRINGS.GENERATION_SUCCESS.replace('{count}', recordCount.toString())); + // Reload projects to show new data + await loadProjects(); + + setTimeout(() => { + setGenerationMessage(''); + }, 3000); + } catch (err) { + console.error('Generation error:', err); + setGenerationMessage(STRINGS.GENERATION_ERROR); + setTimeout(() => { + setGenerationMessage(''); + }, 3000); + } finally { + setIsGenerating(false); + } + }, [recordCount, loadProjects]); + + const hasError = !!error; + + // Pagination handlers + const handlePreviousPage = () => { + setCurrentPage(prev => Math.max(1, prev - 1)); + }; + + const handleNextPage = () => { + setCurrentPage(prev => Math.min(totalPages, prev + 1)); + }; + + // Memoize handlers to prevent unnecessary re-renders + const handleSearchChange = React.useCallback((_: SearchBoxChangeEvent, data: InputOnChangeData) => { + setSearchTerm(data.value || ''); + }, []); + + const handleGenerateDataCallback = React.useCallback(() => { + if (recordCount > 0 && recordCount <= 100) { + generateSampleData(); + } + }, [recordCount, generateSampleData]); + + const handleRecordCountChange = React.useCallback((_: React.FormEvent, data: InputOnChangeData) => { + if (data.value !== undefined && data.value !== null) { + const numValue = parseInt(data.value, 10); + if (!isNaN(numValue)) { + setRecordCount(Math.max(1, Math.min(100, numValue))); + } + } + }, []); + + // Show loading spinner only on initial load (when there's no existing data) + const isInitialLoading = isLoading && projects.length === 0 && !searchTerm; + + // Loading state - only show full loading screen on initial load + if (isInitialLoading) { + return ( +
+ } + /> +
+ +
+
+ ); + } + + // Error state + if (hasError) { + return ( +
+ } + /> + + + {STRINGS.ERROR_MESSAGE} + {error && ( +
+ {error} +
+ )} +
+
+ ); + } + + return ( +
+ } + /> + + {/* Template Information */} + +
+ + πŸ“‹ Template Mode - Static Data + + + This template uses mock data. Replace ProjectsDataService with real API calls to connect to your SQL database. + +
+
+ + {/* Sample Data Generation Section */} + + + {STRINGS.GENERATE_DATA_TITLE} + + + {STRINGS.GENERATION_DISABLED} + + +
+
+ + +
+ + +
+ + {generationMessage && ( + + {generationMessage} + + )} +
+ + {/* Search */} +
+ +
+ + {/* Simple Table Implementation */} + +
+ + + + + + + + + + + + + + + {projects.map((project, index) => ( + + + + + + + + + + + ))} + +
Project NameDescriptionStatusPriorityBudgetStart DateEnd DateProject Manager
+ +
+ {project.Name} +
+
+
+ +
+ {project.Description || 'No description'} +
+
+
+ + {project.Status} + + + + {project.Priority} + + + + ${project.Budget?.toLocaleString() || '0'} + + + {project.StartDate ? new Date(project.StartDate).toLocaleDateString() : 'Not set'} + + {project.EndDate ? new Date(project.EndDate).toLocaleDateString() : 'Not set'} + + +
+ {project.ProjectManagerEmail} +
+
+
+
+ + {/* Pagination */} +
+ + {STRINGS.PAGINATION_PAGE_INFO + .replace('{current}', currentPage.toString()) + .replace('{total}', totalPages.toString())} β€’ {totalRecords} total records + + +
+ + +
+
+
+ + {/* No Results Message */} + {!isLoading && projects.length === 0 && searchTerm && ( + + + {STRINGS.NO_RESULTS_MESSAGE} + + )} +
+ ); +}; + +export default SqlPage; diff --git a/samples/FluentSample/src/vite-env.d.ts b/samples/FluentSample/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/samples/FluentSample/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/samples/FluentSample/tsconfig.app.json b/samples/FluentSample/tsconfig.app.json new file mode 100644 index 0000000..028c24e --- /dev/null +++ b/samples/FluentSample/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": false, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/samples/FluentSample/tsconfig.json b/samples/FluentSample/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/samples/FluentSample/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/samples/FluentSample/tsconfig.node.json b/samples/FluentSample/tsconfig.node.json new file mode 100644 index 0000000..abd2eb4 --- /dev/null +++ b/samples/FluentSample/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": false, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/samples/FluentSample/vite.config.ts b/samples/FluentSample/vite.config.ts new file mode 100644 index 0000000..8e9e069 --- /dev/null +++ b/samples/FluentSample/vite.config.ts @@ -0,0 +1,27 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + base: "./", + server: { + host: "::", + port: 3000, + }, + plugins: [react()], + build: { + chunkSizeWarningLimit: 1000, // Increase warning limit to 1000kB to suppress the warning + rollupOptions: { + output: { + manualChunks: { + // Split vendor libraries into separate chunks + 'react-vendor': ['react', 'react-dom'], + 'router-vendor': ['react-router-dom'], + 'fluent-components': ['@fluentui/react-components'], + 'fluent-icons': ['@fluentui/react-icons'], + 'fluent-tokens': ['@fluentui/tokens'], + } + } + } + }, +});