diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2328108219..4791b30ff2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ "hostRequirements": { "cpus": 4 }, - "onCreateCommand": "wget https://download.visualstudio.microsoft.com/download/pr/656a3402-6889-400f-927f-7f956856e58b/93750973d6eedd17c6d963658e7ec214/dotnet-sdk-8.0.203-linux-x64.tar.gz -O $HOME/dotnet.tar.gz && export DOTNET_ROOT=$HOME/.dotnet && mkdir -p \"$DOTNET_ROOT\" && tar zxf $HOME/dotnet.tar.gz -C \"$DOTNET_ROOT\" && export PATH=$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH && sudo dotnet workload install wasm-tools wasm-experimental && dotnet dev-certs https --trust && dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore", + "onCreateCommand": "wget https://download.visualstudio.microsoft.com/download/pr/0a1b3cbd-b4af-4d0d-9ed7-0054f0e200b4/4bcc533c66379caaa91770236667aacb/dotnet-sdk-8.0.204-linux-x64.tar.gz -O $HOME/dotnet.tar.gz && export DOTNET_ROOT=$HOME/.dotnet && mkdir -p \"$DOTNET_ROOT\" && tar zxf $HOME/dotnet.tar.gz -C \"$DOTNET_ROOT\" && export PATH=$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH && sudo dotnet workload install wasm-tools wasm-experimental && dotnet dev-certs https --trust && dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore", "waitFor": "onCreateCommand", "customizations": { "codespaces": { diff --git a/.github/workflows/admin-sample.cd.yml b/.github/workflows/admin-sample.cd.yml index 629b967fd8..2c429dcfd5 100644 --- a/.github/workflows/admin-sample.cd.yml +++ b/.github/workflows/admin-sample.cd.yml @@ -23,10 +23,10 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/Templates/Boilerplate/Bit.Boilerplate/global.json @@ -35,18 +35,19 @@ jobs: cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin + cd ../../../ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin --appInsights - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'AdminPanel/src/Client/AdminPanel.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install wasm run: cd src && dotnet workload install wasm-tools wasm-experimental @@ -67,7 +68,7 @@ jobs: run: dotnet publish AdminPanel/src/AdminPanel.Server/AdminPanel.Server.csproj -c Release -p:PwaEnabled=true --self-contained -r linux-x64 -o ${{env.DOTNET_ROOT}}/server -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" - name: Upload server artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: server-bundle path: ${{env.DOTNET_ROOT}}/server @@ -83,7 +84,7 @@ jobs: steps: - name: Retrieve server bundle - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: server-bundle @@ -92,7 +93,7 @@ jobs: rm IdentityCertificate.pfx - name: Extract identity certificate from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './' fileName: 'IdentityCertificate.pfx' @@ -120,31 +121,32 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src\Templates\Boilerplate\Bit.Boilerplate\global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Create project from Boilerplate run: | cd src\Templates\Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ..\..\..\ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin --windows + cd ..\..\..\ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin --windows --appInsights - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'AdminPanel\src\Client\AdminPanel.Client.Core\appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} WindowsUpdateSettings.FilesUrl: https://windows-adminpanel.bitplatform.dev + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - name: Generate CSS/JS files run: dotnet build AdminPanel\src\Client\AdminPanel.Client.Core\AdminPanel.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore @@ -165,7 +167,7 @@ jobs: echo A | xcopy .\bin\publish-x64 .\publish-result /s /e /h echo A | xcopy .\bin\publish .\publish-result /s /e /h dotnet tool restore - dotnet vpk pack -u AdminPanel.Client.Windows -v "${{ vars.APPLICATION_DISPLAY_VERSION }}" -p .\publish-result -e AdminPanel.Client.Windows-x86.exe -r win-x86 --framework net8.0.2-x86-desktop,webview2 --icon .\wwwroot\favicon.ico --packTitle 'AdminPanel' + dotnet vpk pack -u AdminPanel.Client.Windows -v "${{ vars.APPLICATION_DISPLAY_VERSION }}" -p .\publish-result -e AdminPanel.Client.Windows-x86.exe -r win-x86 --framework net8.0.4-x86-desktop,webview2 --icon .\wwwroot\favicon.ico --packTitle 'AdminPanel' - name: Upload artifact uses: actions/upload-artifact@v2 @@ -180,10 +182,10 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/Templates/Boilerplate/Bit.Boilerplate/global.json @@ -192,25 +194,26 @@ jobs: cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin + cd ../../../ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin --appInsights - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Extract Android signing key from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './AdminPanel/src/Client/AdminPanel.Client.Maui/' fileName: 'AdminPanel.keystore' encodedString: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }} - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'AdminPanel/src/Client/AdminPanel.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - name: Set android universal link run: sed -i 's/bp.bitplatform.dev/adminpanel.bitplatform.dev/g' AdminPanel/src/Client/AdminPanel.Client.Maui/Platforms/Android/MainActivity.cs @@ -222,7 +225,9 @@ jobs: run: ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT "platform-tools" - name: Generate CSS/JS files - run: dotnet build AdminPanel/src/Client/AdminPanel.Client.Core/AdminPanel.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + run: | + dotnet build AdminPanel/src/Client/AdminPanel.Client.Core/AdminPanel.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + dotnet build AdminPanel/src/Client/AdminPanel.Client.Maui/AdminPanel.Client.Maui.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore - name: Build aab run: dotnet build AdminPanel/src/Client/AdminPanel.Client.Maui/AdminPanel.Client.Maui.csproj -c Release -p:AndroidPackageFormat=aab -p:AndroidKeyStore=true -p:AndroidSigningKeyStore="AdminPanel.keystore" -p:AndroidSigningKeyAlias=bitplatform -p:AndroidSigningKeyPass="${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }}" -p:AndroidSigningStorePass="${{ secrets.ANDROID_RELEASE_SIGNING_PASSWORD }}" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" -p:ApplicationTitle="AdminPanel" -p:ApplicationId="com.bitplatform.AdminPanel.Template" -f net8.0-android @@ -235,39 +240,40 @@ jobs: build_blazor_hybrid_ios: name: build blazor hybrid (iOS-macOS) - runs-on: macos-13 + runs-on: macos-14 steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/Templates/Boilerplate/Bit.Boilerplate/global.json - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '15' + xcode-version: '15.3' - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Create project from Boilerplate run: | cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin + cd ../../../ && dotnet new bit-bp --name AdminPanel --database SqlServer --sample Admin --appInsights - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'AdminPanel/src/Client/AdminPanel.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - name: Set iOS universal link run: brew install gnu-sed && gsed -i 's/bp.bitplatform.dev/adminpanel.bitplatform.dev/g' AdminPanel/src/Client/AdminPanel.Client.Maui/Platforms/iOS/Entitlements.plist @@ -276,14 +282,14 @@ jobs: run: cd src && dotnet workload install maui - name: Extract iOS code signing certificate from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './' fileName: 'DistributionCert.p12' encodedString: ${{ secrets.APPSTORE_CODE_SIGNING_CERTIFICATE_FILE_BASE64 }} - name: Import Code-Signing Certificates - uses: Apple-Actions/import-codesign-certs@v1 + uses: apple-actions/import-codesign-certs@v2 with: p12-filepath: './DistributionCert.p12' p12-password: ${{ secrets.APPSTORE_CODE_SIGNING_CERTIFICATE_FILE_PASSWORD }} @@ -297,7 +303,9 @@ jobs: api-private-key: ${{ secrets.APPSTORE_API_KEY_PRIVATE_KEY }} - name: Generate CSS/JS files - run: dotnet build AdminPanel/src/Client/AdminPanel.Client.Core/AdminPanel.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + run: | + dotnet build AdminPanel/src/Client/AdminPanel.Client.Core/AdminPanel.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + dotnet build AdminPanel/src/Client/AdminPanel.Client.Maui/AdminPanel.Client.Maui.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore - name: Build ipa run: dotnet publish AdminPanel/src/Client/AdminPanel.Client.Maui/AdminPanel.Client.Maui.csproj -p:RuntimeIdentifier=ios-arm64 -c Release -p:ArchiveOnBuild=true -p:CodesignKey="iPhone Distribution" -p:CodesignProvision="AdminPanel" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" -p:ApplicationTitle="AdminPanel" -p:ApplicationId="com.bitplatform.AdminPanel.Template" -f net8.0-ios diff --git a/.github/workflows/bit.ci.yml b/.github/workflows/bit.ci.yml index b6e050501a..8a14b01057 100644 --- a/.github/workflows/bit.ci.yml +++ b/.github/workflows/bit.ci.yml @@ -16,13 +16,13 @@ jobs: uses: actions/checkout@v2 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install wasm and maui run: cd src && dotnet workload install maui-android wasm-tools wasm-experimental @@ -44,13 +44,13 @@ jobs: uses: actions/checkout@v2 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install wasm and maui run: cd src && dotnet workload install maui-android wasm-tools wasm-experimental diff --git a/.github/workflows/bit.full.ci.yml b/.github/workflows/bit.full.ci.yml index 6991750d20..9bc101a737 100644 --- a/.github/workflows/bit.full.ci.yml +++ b/.github/workflows/bit.full.ci.yml @@ -15,13 +15,13 @@ jobs: uses: actions/checkout@v2 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install Bit.Boilerplate from local source run: | diff --git a/.github/workflows/blazorui.demo.cd.yml b/.github/workflows/blazorui.demo.cd.yml index b797d8905e..5e3018582a 100644 --- a/.github/workflows/blazorui.demo.cd.yml +++ b/.github/workflows/blazorui.demo.cd.yml @@ -21,23 +21,23 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install wasm run: cd src && dotnet workload install wasm-tools wasm-experimental @@ -52,7 +52,7 @@ jobs: run: dotnet publish src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj -c Release -p:PwaEnabled=true -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --self-contained -r linux-x64 -o ${{env.DOTNET_ROOT}}/server - name: Upload server artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: server-bundle path: ${{env.DOTNET_ROOT}}/server @@ -68,7 +68,7 @@ jobs: steps: - name: Retrieve server bundle - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: server-bundle @@ -94,19 +94,19 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src\global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'src\BlazorUI\Demo\Client\Bit.BlazorUI.Demo.Client.Core\appsettings.json' env: @@ -132,7 +132,7 @@ jobs: echo A | xcopy .\bin\publish-x64 .\publish-result /s /e /h echo A | xcopy .\bin\publish .\publish-result /s /e /h dotnet tool restore - dotnet vpk pack -u Bit.BlazorUI.Demo.Client.Windows -v "${{ vars.APPLICATION_DISPLAY_VERSION }}" -p .\publish-result -e Bit.BlazorUI.Demo.Client.Windows-x86.exe -r win-x86 --framework net8.0.2-x86-desktop,webview2 --icon .\wwwroot\favicon.ico --packTitle 'Bit Blazor UI' + dotnet vpk pack -u Bit.BlazorUI.Demo.Client.Windows -v "${{ vars.APPLICATION_DISPLAY_VERSION }}" -p .\publish-result -e Bit.BlazorUI.Demo.Client.Windows-x86.exe -r win-x86 --framework net8.0.4-x86-desktop,webview2 --icon .\wwwroot\favicon.ico --packTitle 'Bit Blazor UI' - name: Upload artifact uses: actions/upload-artifact@v2 @@ -147,26 +147,26 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Extract Android signing key from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/' fileName: 'BitBlazorUIDemo.keystore' encodedString: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }} - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' env: @@ -192,28 +192,28 @@ jobs: build_blazor_hybrid_ios: name: build blazor hybrid (iOS-macOS) - runs-on: macos-13 + runs-on: macos-14 steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '15' + xcode-version: '15.3' - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' env: @@ -223,14 +223,14 @@ jobs: run: cd src && dotnet workload install maui - name: Extract iOS code signing certificate from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './' fileName: 'DistributionCert.p12' encodedString: ${{ secrets.APPSTORE_CODE_SIGNING_CERTIFICATE_FILE_BASE64 }} - name: Import Code-Signing Certificates - uses: Apple-Actions/import-codesign-certs@v1 + uses: apple-actions/import-codesign-certs@v2 with: p12-filepath: './DistributionCert.p12' p12-password: ${{ secrets.APPSTORE_CODE_SIGNING_CERTIFICATE_FILE_PASSWORD }} diff --git a/.github/workflows/nuget.org.yml b/.github/workflows/nuget.org.yml index 4f06b41daf..d84141686e 100644 --- a/.github/workflows/nuget.org.yml +++ b/.github/workflows/nuget.org.yml @@ -25,20 +25,20 @@ jobs: uses: actions/checkout@v2 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Delete AssemblyOriginatorKeyFile.snk run: | rm src/AssemblyOriginatorKeyFile.snk - name: Extract strong sign certificate from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './src/' fileName: 'AssemblyOriginatorKeyFile.snk' diff --git a/.github/workflows/platform.website.cd.yml b/.github/workflows/platform.website.cd.yml index a5ed1ea09d..83da44d6f6 100644 --- a/.github/workflows/platform.website.cd.yml +++ b/.github/workflows/platform.website.cd.yml @@ -20,10 +20,10 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json @@ -37,7 +37,7 @@ jobs: run: dotnet publish src/Websites/Platform/src/Bit.Websites.Platform.Server/Bit.Websites.Platform.Server.csproj -c Release --self-contained -r linux-x64 -o server - name: Upload server artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: server-bundle path: server @@ -53,7 +53,7 @@ jobs: steps: - name: Retrieve server bundle - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: server-bundle diff --git a/.github/workflows/prerelease.nuget.org.yml b/.github/workflows/prerelease.nuget.org.yml index d19d112cd8..71c1955bfa 100644 --- a/.github/workflows/prerelease.nuget.org.yml +++ b/.github/workflows/prerelease.nuget.org.yml @@ -15,20 +15,20 @@ jobs: uses: actions/checkout@v2 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Delete AssemblyOriginatorKeyFile.snk run: | rm src/AssemblyOriginatorKeyFile.snk - name: Extract strong sign certificate from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './src/' fileName: 'AssemblyOriginatorKeyFile.snk' diff --git a/.github/workflows/sales.website.cd.yml b/.github/workflows/sales.website.cd.yml index 11e6ba6ac7..eaf4643480 100644 --- a/.github/workflows/sales.website.cd.yml +++ b/.github/workflows/sales.website.cd.yml @@ -20,10 +20,10 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/global.json @@ -37,7 +37,7 @@ jobs: run: dotnet publish src/Websites/Sales/src/Bit.Websites.Sales.Server/Bit.Websites.Sales.Server.csproj -c Release --self-contained -r linux-x64 -o server - name: Upload server artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: server-bundle path: server @@ -53,7 +53,7 @@ jobs: steps: - name: Retrieve server bundle - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: server-bundle diff --git a/.github/workflows/todo-sample.cd.yml b/.github/workflows/todo-sample.cd.yml index ddf6074053..cf8cecfbd6 100644 --- a/.github/workflows/todo-sample.cd.yml +++ b/.github/workflows/todo-sample.cd.yml @@ -22,30 +22,31 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/Templates/Boilerplate/Bit.Boilerplate/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Create project from Boilerplate run: | cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo --appInsights - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - name: Install wasm run: cd src && dotnet workload install wasm-tools wasm-experimental @@ -65,7 +66,7 @@ jobs: run: dotnet publish TodoSample/src/TodoSample.Server/TodoSample.Server.csproj -c Release -p:PwaEnabled=true --self-contained -r linux-x64 -o ${{env.DOTNET_ROOT}}/server -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" - name: Upload server artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: server-bundle path: ${{env.DOTNET_ROOT}}/server @@ -82,7 +83,7 @@ jobs: run: dotnet publish TodoSample/src/Client/TodoSample.Client.Web/TodoSample.Client.Web.csproj -c Release -p:BlazorWebAssemblyStandalone=true -o ${{env.DOTNET_ROOT}}/static - name: Upload static artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: static-bundle path: ${{env.DOTNET_ROOT}}/static @@ -98,7 +99,7 @@ jobs: steps: - name: Retrieve server bundle - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: server-bundle @@ -107,7 +108,7 @@ jobs: rm IdentityCertificate.pfx - name: Extract identity certificate from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './' fileName: 'IdentityCertificate.pfx' @@ -135,31 +136,32 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src\Templates\Boilerplate\Bit.Boilerplate\global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Create project from Boilerplate run: | cd src\Templates\Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ..\..\..\ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo --windows + cd ..\..\..\ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo --windows --appInsights - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'TodoSample\src\Client\TodoSample.Client.Core\appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} WindowsUpdateSettings.FilesUrl: https://windows-todo.bitplatform.dev + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - name: Generate CSS/JS files run: dotnet build TodoSample\src\Client\TodoSample.Client.Core\TodoSample.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore @@ -180,7 +182,7 @@ jobs: echo A | xcopy .\bin\publish-x64 .\publish-result /s /e /h echo A | xcopy .\bin\publish .\publish-result /s /e /h dotnet tool restore - dotnet vpk pack -u TodoSample.Client.Windows -v "${{ vars.APPLICATION_DISPLAY_VERSION }}" -p .\publish-result -e TodoSample.Client.Windows-x86.exe -r win-x86 --framework net8.0.2-x86-desktop,webview2 --icon .\wwwroot\favicon.ico --packTitle TodoSample + dotnet vpk pack -u TodoSample.Client.Windows -v "${{ vars.APPLICATION_DISPLAY_VERSION }}" -p .\publish-result -e TodoSample.Client.Windows-x86.exe -r win-x86 --framework net8.0.4-x86-desktop,webview2 --icon .\wwwroot\favicon.ico --packTitle TodoSample - name: Upload artifact uses: actions/upload-artifact@v2 @@ -195,37 +197,38 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/Templates/Boilerplate/Bit.Boilerplate/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Create project from Boilerplate run: | cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo --appInsights - name: Extract Android signing key from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './TodoSample/src/Client/TodoSample.Client.Maui/' fileName: 'TodoSample.keystore' encodedString: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }} - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - name: Set android universal link run: sed -i 's/bp.bitplatform.dev/todo.bitplatform.dev/g' TodoSample/src/Client/TodoSample.Client.Maui/Platforms/Android/MainActivity.cs @@ -240,7 +243,7 @@ jobs: run: rm TodoSample/src/Client/TodoSample.Client.Maui/Resources/AppIcon/appicon.svg - name: Extract App Icon from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './TodoSample/src/Client/TodoSample.Client.Maui/Resources/AppIcon/' fileName: 'appicon.svg' @@ -250,14 +253,16 @@ jobs: run: rm TodoSample/src/Client/TodoSample.Client.Maui/Resources/Splash/splash.svg - name: Extract App Splash Screen from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './TodoSample/src/Client/TodoSample.Client.Maui/Resources/Splash/' fileName: 'splash.svg' encodedString: ${{ vars.TODO_SPLASH_SCREEN }} - name: Generate CSS/JS files - run: dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + run: | + dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + dotnet build TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore - name: Build aab run: dotnet build TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -c Release -p:AndroidPackageFormat=aab -p:AndroidKeyStore=true -p:AndroidSigningKeyStore="TodoSample.keystore" -p:AndroidSigningKeyAlias=bitplatform -p:AndroidSigningKeyPass="${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }}" -p:AndroidSigningStorePass="${{ secrets.ANDROID_RELEASE_SIGNING_PASSWORD }}" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" -p:ApplicationTitle="TodoSample" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-android @@ -270,39 +275,40 @@ jobs: build_blazor_hybrid_ios: name: build blazor hybrid (iOS-macOS) - runs-on: macos-13 + runs-on: macos-14 steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: global-json-file: src/Templates/Boilerplate/Bit.Boilerplate/global.json - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '15' + xcode-version: '15.3' - name: Create project from Boilerplate run: | cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo --appInsights - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 + uses: devops-actions/variable-substitution@v1.2 with: files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} + ApplicationInsights.ConnectionString: ${{ secrets.APPLICATION_INSIGHTS_CONNECTION_STRING }} - name: Set iOS universal link run: brew install gnu-sed && gsed -i 's/bp.bitplatform.dev/todo.bitplatform.dev/g' TodoSample/src/Client/TodoSample.Client.Maui/Platforms/iOS/Entitlements.plist @@ -311,14 +317,14 @@ jobs: run: cd src && dotnet workload install maui - name: Extract iOS code signing certificate from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './' fileName: 'DistributionCert.p12' encodedString: ${{ secrets.APPSTORE_CODE_SIGNING_CERTIFICATE_FILE_BASE64 }} - name: Import Code-Signing Certificates - uses: Apple-Actions/import-codesign-certs@v1 + uses: apple-actions/import-codesign-certs@v2 with: p12-filepath: './DistributionCert.p12' p12-password: ${{ secrets.APPSTORE_CODE_SIGNING_CERTIFICATE_FILE_PASSWORD }} @@ -335,7 +341,7 @@ jobs: run: rm TodoSample/src/Client/TodoSample.Client.Maui/Resources/AppIcon/appicon.svg - name: Extract App Icon from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './TodoSample/src/Client/TodoSample.Client.Maui/Resources/AppIcon/' fileName: 'appicon.svg' @@ -345,14 +351,16 @@ jobs: run: rm TodoSample/src/Client/TodoSample.Client.Maui/Resources/Splash/splash.svg - name: Extract App Splash Screen from env - uses: timheuer/base64-to-file@v1 + uses: timheuer/base64-to-file@v1.2 with: fileDir: './TodoSample/src/Client/TodoSample.Client.Maui/Resources/Splash/' fileName: 'splash.svg' encodedString: ${{ vars.TODO_SPLASH_SCREEN }} - name: Generate CSS/JS files - run: dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + run: | + dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore + dotnet build TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -t:BeforeBuildTasks -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" --no-restore - name: Build ipa run: dotnet publish TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -p:RuntimeIdentifier=ios-arm64 -c Release -p:ArchiveOnBuild=true -p:CodesignKey="iPhone Distribution" -p:CodesignProvision="TodoTemplate" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:Version="${{ vars.APPLICATION_DISPLAY_VERSION}}" -p:ApplicationTitle="Todo" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-ios diff --git a/README.md b/README.md index 701d6ad46a..a208721cef 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,10 @@ For more details, visit us at [bitplatform.dev](https://bitplatform.dev/).
+**Note**: This project is tested with [BrowserStack](https://www.browserstack.com/). + +
+ # 🎁 OSS Showcases The following apps are our open-source projects powered by the bit platform showcasing the different capabilities of our toolchain: diff --git a/docs/how-to-build.md b/docs/how-to-build.md index f60f163b40..caa60f0773 100644 --- a/docs/how-to-build.md +++ b/docs/how-to-build.md @@ -22,7 +22,7 @@ building each one of them requires some specific steps that are explained below. Building each of the bit platform projects needs the following basic requirements other than the specific requirements that are explained later: -- [.NET 8 SDK (8.0.203)](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) +- [.NET 8 SDK (8.0.204)](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) - [Node.js](https://nodejs.org)
diff --git a/src/Besql/Demo/Bit.Besql.Demo.Client/Bit.Besql.Demo.Client.csproj b/src/Besql/Demo/Bit.Besql.Demo.Client/Bit.Besql.Demo.Client.csproj index 019d5892ba..c10cd531d1 100644 --- a/src/Besql/Demo/Bit.Besql.Demo.Client/Bit.Besql.Demo.Client.csproj +++ b/src/Besql/Demo/Bit.Besql.Demo.Client/Bit.Besql.Demo.Client.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Besql/Demo/Bit.Besql.Demo/Bit.Besql.Demo.csproj b/src/Besql/Demo/Bit.Besql.Demo/Bit.Besql.Demo.csproj index 351ab1c20a..d1c6b69376 100644 --- a/src/Besql/Demo/Bit.Besql.Demo/Bit.Besql.Demo.csproj +++ b/src/Besql/Demo/Bit.Besql.Demo/Bit.Besql.Demo.csproj @@ -8,7 +8,7 @@ - + @@ -19,11 +19,11 @@ and open Nuget Package Manager Console, and select `Bit.Besql.Demo` project as default project Then run either Add-Migration MigrationName -OutputDir Data\Migrations or Optimize-DbContext -OutputDir Data/CompiledModel commands. --> - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Bit.Build.props b/src/Bit.Build.props index 03148daaf5..1a46eae8a0 100644 --- a/src/Bit.Build.props +++ b/src/Bit.Build.props @@ -25,7 +25,7 @@ https://github.com/bitfoundation/bitplatform https://avatars.githubusercontent.com/u/22663390 - 8.8.0 + 8.8.1 https://github.com/bitfoundation/bitplatform/releases/tag/v-$(ReleaseVersion) $(ReleaseVersion) diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.ts b/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.ts index cbd12a9b01..5eaa56e62a 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.ts +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/DataGrid/BitDataGrid.ts @@ -86,7 +86,7 @@ class BitDataGrid { document.body.removeEventListener('touchend', handleMouseUp); } - if (evt instanceof TouchEvent) { + if (window.TouchEvent && evt instanceof TouchEvent) { document.body.addEventListener('touchmove', handleMouseMove, { passive: true }); document.body.addEventListener('touchend', handleMouseUp, { passive: true }); } else { diff --git a/src/BlazorUI/Bit.BlazorUI.Tests/Accordion/BitAccordionTests.cs b/src/BlazorUI/Bit.BlazorUI.Tests/Accordion/BitAccordionTests.cs index 88dc0aa9cf..c3dee02275 100644 --- a/src/BlazorUI/Bit.BlazorUI.Tests/Accordion/BitAccordionTests.cs +++ b/src/BlazorUI/Bit.BlazorUI.Tests/Accordion/BitAccordionTests.cs @@ -60,11 +60,12 @@ public void BitAccordionShouldBeExpandWhenClicked() var root = com.Find(".bit-acd"); var header = com.Find(".bit-acd-hdr"); - Assert.IsFalse(root.ClassName.Contains("bit-acd-exp")); - + var icon = com.Find(".bit-acd-hdr > i"); + var content = com.Find(".bit-acd-con"); header.Click(); - Assert.IsTrue(root.ClassName.Contains("bit-acd-exp")); + Assert.IsTrue(icon.ClassName.Contains("bit-acd-hex")); + Assert.IsTrue(content.ClassName.Contains("bit-acd-cex")); } @@ -79,9 +80,11 @@ public void BitAccordionShouldBeSetDefaultIsExpanded(bool defaultIsExpanded) parameters.Add(p => p.DefaultIsExpanded, defaultIsExpanded); }); - var root = com.Find(".bit-acd"); + var header = com.Find(".bit-acd-hdr > i"); + var content = com.Find(".bit-acd-con"); - Assert.AreEqual(defaultIsExpanded, root.ClassName.Contains("bit-acd-exp")); + Assert.AreEqual(defaultIsExpanded, header.ClassName.Contains("bit-acd-hex")); + Assert.AreEqual(defaultIsExpanded, content.ClassName.Contains("bit-acd-cex")); } [DataTestMethod, diff --git a/src/BlazorUI/Bit.BlazorUI.Tests/Bit.BlazorUI.Tests.csproj b/src/BlazorUI/Bit.BlazorUI.Tests/Bit.BlazorUI.Tests.csproj index dd418c4a1b..4ef8141eaf 100644 --- a/src/BlazorUI/Bit.BlazorUI.Tests/Bit.BlazorUI.Tests.csproj +++ b/src/BlazorUI/Bit.BlazorUI.Tests/Bit.BlazorUI.Tests.csproj @@ -15,8 +15,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/BlazorUI/Bit.BlazorUI.Tests/NumberField/BitNumberFieldTests.cs b/src/BlazorUI/Bit.BlazorUI.Tests/NumberField/BitNumberFieldTests.cs index 837fcfad77..28885ac1ed 100644 --- a/src/BlazorUI/Bit.BlazorUI.Tests/NumberField/BitNumberFieldTests.cs +++ b/src/BlazorUI/Bit.BlazorUI.Tests/NumberField/BitNumberFieldTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Bunit; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; @@ -322,10 +323,10 @@ public void BitNumberFieldShouldHaveCorrectMaxMin(int? min, int? max) } [DataTestMethod, - DataRow(4), - DataRow(12) + DataRow(3), + DataRow(5) ] - public void BitNumberFieldOnIncrementTest(int countOfClicks) + public async Task BitNumberFieldOnIncrementTest(int countOfClicks) { int onIncrementEventCounter = 0; var component = RenderComponent>(parameters => @@ -338,6 +339,7 @@ public void BitNumberFieldOnIncrementTest(int countOfClicks) for (int i = 0; i < countOfClicks; i++) { increaseButton.PointerDown(); + await Task.Delay(1); increaseButton.PointerUp(); } @@ -345,10 +347,10 @@ public void BitNumberFieldOnIncrementTest(int countOfClicks) } [DataTestMethod, - DataRow(4), - DataRow(12) + DataRow(3), + DataRow(5) ] - public void BitNumberFieldOnDecrementTest(int countOfClicks) + public async Task BitNumberFieldOnDecrementTest(int countOfClicks) { int onDecrementEventCounter = 20; var component = RenderComponent>(parameters => @@ -361,6 +363,7 @@ public void BitNumberFieldOnDecrementTest(int countOfClicks) for (int i = 0; i < countOfClicks; i++) { decreaseButton.PointerDown(); + await Task.Delay(1); decreaseButton.PointerUp(); } diff --git a/src/BlazorUI/Bit.BlazorUI.Tests/SpinButtons/BitSpinButtonTests.cs b/src/BlazorUI/Bit.BlazorUI.Tests/SpinButtons/BitSpinButtonTests.cs index 2b18afdea6..1438983356 100644 --- a/src/BlazorUI/Bit.BlazorUI.Tests/SpinButtons/BitSpinButtonTests.cs +++ b/src/BlazorUI/Bit.BlazorUI.Tests/SpinButtons/BitSpinButtonTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Bunit; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; @@ -264,7 +265,7 @@ public void BitSpinButtonShouldHaveCorrectMaxMin(double? min, double? max) DataRow(4), DataRow(12) ] - public void BitSpinButtonOnIncrementTest(int countOfClicks) + public async Task BitSpinButtonOnIncrementTest(int countOfClicks) { int onIncrementEventCounter = 0; var component = RenderComponent(parameters => @@ -276,6 +277,7 @@ public void BitSpinButtonOnIncrementTest(int countOfClicks) for (int i = 0; i < countOfClicks; i++) { increaseButton.PointerDown(); + await Task.Delay(1); increaseButton.PointerUp(); } @@ -286,7 +288,7 @@ public void BitSpinButtonOnIncrementTest(int countOfClicks) DataRow(4), DataRow(12) ] - public void BitSpinButtonOnDecrementTest(int countOfClicks) + public async Task BitSpinButtonOnDecrementTest(int countOfClicks) { int onDecrementEventCounter = 20; var component = RenderComponent(parameters => @@ -298,6 +300,7 @@ public void BitSpinButtonOnDecrementTest(int countOfClicks) for (int i = 0; i < countOfClicks; i++) { decreaseButton.PointerDown(); + await Task.Delay(1); decreaseButton.PointerUp(); } @@ -633,7 +636,7 @@ public void BitSpinButtonPrecisionTest(double min, double max, double step, stri DataRow(5, 2, 4), DataRow(1, 15, 1) ] - public void BitSpinButtonTwoWayBoundWithCustomHandlerShouldWorkCorrectly(double value, int countOfIncrements, double step) + public async Task BitSpinButtonTwoWayBoundWithCustomHandlerShouldWorkCorrectly(double value, int countOfIncrements, double step) { _bitSpinButtonTwoWayBoundValue = value; @@ -648,6 +651,7 @@ public void BitSpinButtonTwoWayBoundWithCustomHandlerShouldWorkCorrectly(double for (var i = 0; i < countOfIncrements; i++) { incrementButton.PointerDown(); + await Task.Delay(1); } var expectedValue = value + (step * countOfIncrements); diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor b/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor index 19bd8ff0fb..52dfae9641 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor +++ b/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor @@ -28,13 +28,17 @@ @Description - + } -
- @ChildContent + +
+
+ @ChildContent +
\ No newline at end of file diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor.cs index 2547a32358..883f9135df 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.razor.cs @@ -43,7 +43,6 @@ public bool IsExpanded { if (value == isExpanded) return; isExpanded = value; - ClassBuilder.Reset(); _ = IsExpandedChanged.InvokeAsync(value); } } @@ -76,8 +75,6 @@ public bool IsExpanded protected override void RegisterCssClasses() { ClassBuilder.Register(() => Classes?.Root); - - ClassBuilder.Register(() => IsExpanded ? $"bit-acd-exp {Classes?.Expanded}" : string.Empty); } protected override void RegisterCssStyles() diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.scss b/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.scss index f9d4740ac0..b4fec1bb47 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.scss +++ b/src/BlazorUI/Bit.BlazorUI/Components/Accordion/BitAccordion.scss @@ -60,24 +60,25 @@ color: $color-foreground-secondary; } +.bit-acd-hex { + transform: rotate(-180deg); +} + .bit-acd-con { - opacity: 0; height: auto; - max-height: 0; overflow: hidden; padding: 0 spacing(1.5); transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; } -.bit-acd-exp { - .bit-acd-hic { - transform: rotate(-180deg); - } +.bit-acd-cco { + opacity: 0; + max-height: 0; + margin: spacing(-1.5) 0; +} - .bit-acd-con { - opacity: 1; - height: 100%; - max-height: unset; - padding: spacing(1.5); - } +.bit-acd-cex { + opacity: 1; + height: auto; + margin: spacing(1.5) 0; } diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Buttons/BitActionButton/BitActionButton.razor b/src/BlazorUI/Bit.BlazorUI/Components/Buttons/BitActionButton/BitActionButton.razor index c2d25adb0d..736cefae48 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Buttons/BitActionButton/BitActionButton.razor +++ b/src/BlazorUI/Bit.BlazorUI/Components/Buttons/BitActionButton/BitActionButton.razor @@ -16,7 +16,10 @@ aria-hidden="@AriaHidden" aria-describedby="@AriaDescription"> - + @if (IconName is not null) + { + + } @if (ChildContent is not null) { @@ -40,7 +43,10 @@ else aria-hidden="@AriaHidden" aria-describedby="@AriaDescription"> - + @if (IconName is not null) + { + + } @if (ChildContent is not null) { diff --git a/src/BlazorUI/Bit.BlazorUI/Components/FileUpload/BitFileInfo.cs b/src/BlazorUI/Bit.BlazorUI/Components/FileUpload/BitFileInfo.cs index c3d3c64daf..08d5b67dbf 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/FileUpload/BitFileInfo.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/FileUpload/BitFileInfo.cs @@ -4,23 +4,58 @@ namespace Bit.BlazorUI; public class BitFileInfo { + /// + /// The Content-Type of the selected file. + /// [JsonPropertyName("type")] public string ContentType { get; set; } = string.Empty; + + /// + /// The name of the selected file. + /// [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; + + /// + /// The size of the selected file. + /// [JsonPropertyName("size")] public long Size { get; set; } + + /// + /// The file ID of the selected file, this is a GUID. + /// [JsonPropertyName("fileId")] public string FileId { get; set; } = string.Empty; - [JsonPropertyName("index")] public int Index { get; set; } + /// + /// The index of the selected file. + /// + [JsonPropertyName("index")] public int Index { get; set; } + /// + /// The size of the last uploaded chunk of the file. + /// public long LastChunkUploadedSize { get; internal set; } + + /// + /// The total uploaded size of the file. + /// public long TotalUploadedSize { get; internal set; } internal bool PauseUploadRequested { get; set; } internal bool CancelUploadRequested { get; set; } - + /// + /// The error message is issued during file validation before uploading the file or at the time of uploading. + /// [JsonIgnore] public string? Message { get; internal set; } + + /// + /// The status of the file in the BitFileUpload. + /// [JsonIgnore] public BitFileUploadStatus Status { get; internal set; } - [JsonIgnore] internal DateTime? StartTimeUpload { get; set; } + + /// + /// The HTTP header at upload file. + /// [JsonIgnore] public IReadOnlyDictionary? HttpHeaders { get; set; } + [JsonIgnore] internal DateTime? StartTimeUpload { get; set; } } diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Calendar/BitCalendar.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Calendar/BitCalendar.razor.cs index 1727d1f426..18d78afbb3 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Calendar/BitCalendar.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Calendar/BitCalendar.razor.cs @@ -83,7 +83,6 @@ private int _minuteView private int _currentDay; private int _currentYear; private int _currentMonth; - private bool _isPointerDown; private bool _showYearPicker; private bool _showTimePicker; private bool _showMonthPicker; @@ -94,6 +93,7 @@ private int _minuteView private string _monthTitle = string.Empty; private ElementReference _inputTimeHourRef = default!; private ElementReference _inputTimeMinuteRef = default!; + private CancellationTokenSource _cancellationTokenSource = new(); private int[,] _daysOfCurrentMonth = new int[DEFAULT_WEEK_COUNT, DEFAULT_DAY_COUNT_PER_WEEK]; [Inject] private IJSRuntime _js { get; set; } = default!; @@ -962,15 +962,34 @@ private async Task HandleOnPointerDown(bool isNext, bool isHour) { if (IsEnabled is false) return; - _isPointerDown = true; + ChangeTime(isNext, isHour); + ResetCts(); - await ChangeTime(isNext, isHour, INITIAL_STEP_DELAY); + var cts = _cancellationTokenSource; + await Task.Run(async () => + { + await InvokeAsync(async () => + { + await Task.Delay(INITIAL_STEP_DELAY); + await ContinuousChangeTime(isNext, isHour, cts); + }); + }, cts.Token); } - private async Task ChangeTime(bool isNext, bool isHour, int stepDelay) + private async Task ContinuousChangeTime(bool isNext, bool isHour, CancellationTokenSource cts) { - if (_isPointerDown is false) return; + if (cts.IsCancellationRequested) return; + + ChangeTime(isNext, isHour); + + StateHasChanged(); + await Task.Delay(STEP_DELAY); + await ContinuousChangeTime(isNext, isHour, cts); + } + + private void ChangeTime(bool isNext, bool isHour) + { if (isHour) { ChangeHour(isNext); @@ -979,16 +998,18 @@ private async Task ChangeTime(bool isNext, bool isHour, int stepDelay) { ChangeMinute(isNext); } - StateHasChanged(); - - await Task.Delay(stepDelay); - - await ChangeTime(isNext, isHour, STEP_DELAY); } private void HandleOnPointerUpOrOut() { - _isPointerDown = false; + ResetCts(); + } + + private void ResetCts() + { + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = new(); } private void ChangeHour(bool isNext) @@ -1082,4 +1103,14 @@ private bool MonthPickerIsVisible() (_showTimePicker is false && (ShowMonthPickerAsOverlay is false && ShowTimePickerAsOverlay is false) is false); } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _cancellationTokenSource.Dispose(); + } + + base.Dispose(disposing); + } } diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.razor.cs index 2751ab9e71..b48c6e938b 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DatePicker/BitDatePicker.razor.cs @@ -19,6 +19,7 @@ public partial class BitDatePicker private bool hasBorder = true; private CultureInfo culture = CultureInfo.CurrentUICulture; private BitIconLocation iconLocation = BitIconLocation.Right; + private CancellationTokenSource _cancellationTokenSource = new(); private string focusClass = string.Empty; private string _focusClass @@ -100,7 +101,6 @@ private int _minuteView private int _currentDay; private int _currentYear; private int _currentMonth; - private bool _isPointerDown; private int? _selectedDateWeek; private int _yearPickerEndYear; private int _yearPickerStartYear; @@ -1280,15 +1280,34 @@ private async Task HandleOnPointerDown(bool isNext, bool isHour) { if (IsEnabled is false) return; - _isPointerDown = true; + await ChangeTime(isNext, isHour); + ResetCts(); - await ChangeTime(isNext, isHour, INITIAL_STEP_DELAY); + var cts = _cancellationTokenSource; + await Task.Run(async () => + { + await InvokeAsync(async () => + { + await Task.Delay(INITIAL_STEP_DELAY); + await ContinuousChangeTime(isNext, isHour, cts); + }); + }, cts.Token); } - private async Task ChangeTime(bool isNext, bool isHour, int stepDelay) + private async Task ContinuousChangeTime(bool isNext, bool isHour, CancellationTokenSource cts) { - if (_isPointerDown is false) return; + if (cts.IsCancellationRequested) return; + + await ChangeTime(isNext, isHour); + + StateHasChanged(); + + await Task.Delay(STEP_DELAY); + await ContinuousChangeTime(isNext, isHour, cts); + } + private async Task ChangeTime(bool isNext, bool isHour) + { if (isHour) { await ChangeHour(isNext); @@ -1297,16 +1316,18 @@ private async Task ChangeTime(bool isNext, bool isHour, int stepDelay) { await ChangeMinute(isNext); } - StateHasChanged(); - - await Task.Delay(stepDelay); - - await ChangeTime(isNext, isHour, STEP_DELAY); } private void HandleOnPointerUpOrOut() { - _isPointerDown = false; + ResetCts(); + } + + private void ResetCts() + { + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = new(); } private async Task ChangeHour(bool isNext) @@ -1443,6 +1464,7 @@ protected override void Dispose(bool disposing) if (disposing) { _dotnetObj.Dispose(); + _cancellationTokenSource.Dispose(); } base.Dispose(disposing); diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.razor.cs index 73ac01497f..583f6dc8bb 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/DateRangePicker/BitDateRangePicker.razor.cs @@ -20,6 +20,7 @@ public partial class BitDateRangePicker private bool hasBorder = true; private CultureInfo culture = CultureInfo.CurrentUICulture; private BitIconLocation iconLocation = BitIconLocation.Right; + private CancellationTokenSource _cancellationTokenSource = new(); private string focusClass = string.Empty; private string _focusClass @@ -163,7 +164,6 @@ private int _endTimeMinuteView private int _currentYear; private int _currentMonth; - private bool _isPointerDown; private int _yearPickerEndYear; private int _yearPickerStartYear; private int? _selectedEndDateWeek; @@ -1620,15 +1620,34 @@ private async Task HandleOnPointerDown(bool isNext, bool isHour, bool isStartTim { if (IsEnabled is false) return; - _isPointerDown = true; + await ChangeTime(isNext, isHour, isStartTime); + ResetCts(); - await ChangeTime(isNext, isHour, isStartTime, INITIAL_STEP_DELAY); + var cts = _cancellationTokenSource; + await Task.Run(async () => + { + await InvokeAsync(async () => + { + await Task.Delay(INITIAL_STEP_DELAY); + await ContinuousChangeTime(isNext, isHour, isStartTime, cts); + }); + }, cts.Token); } - private async Task ChangeTime(bool isNext, bool isHour, bool isStartTime, int stepDelay) + private async Task ContinuousChangeTime(bool isNext, bool isHour, bool isStartTime, CancellationTokenSource cts) { - if (_isPointerDown is false) return; + if (cts.IsCancellationRequested) return; + + await ChangeTime(isNext, isHour, isStartTime); + + StateHasChanged(); + + await Task.Delay(STEP_DELAY); + await ContinuousChangeTime(isNext, isHour, isStartTime, cts); + } + private async Task ChangeTime(bool isNext, bool isHour, bool isStartTime) + { if (isHour) { ChangeHour(isNext, isStartTime); @@ -1637,16 +1656,18 @@ private async Task ChangeTime(bool isNext, bool isHour, bool isStartTime, int st { ChangeMinute(isNext, isStartTime); } - StateHasChanged(); - - await Task.Delay(stepDelay); - - await ChangeTime(isNext, isHour, isStartTime, STEP_DELAY); } private void HandleOnPointerUpOrOut() { - _isPointerDown = false; + ResetCts(); + } + + private void ResetCts() + { + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = new(); } private void ChangeHour(bool isNext, bool isStartTime) @@ -1962,6 +1983,7 @@ protected override void Dispose(bool disposing) if (disposing) { _dotnetObj.Dispose(); + _cancellationTokenSource.Dispose(); } base.Dispose(disposing); diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs index 09ef63caed..04b9a63ca5 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/Dropdown/BitDropdown.razor.cs @@ -359,10 +359,26 @@ public bool Chips [Parameter] public Func? DynamicValueGenerator { get; set; } + /// + /// A readonly list of the current selected items in multi-select mode. + /// + public IReadOnlyList SelectedItems => IsMultiSelect ? _selectedItems : []; - public IReadOnlyList SelectedItems => IsMultiSelect ? _selectedItems : Array.Empty(); + /// + /// The current selected item in single-select mode. + /// public TItem? SelectedItem => IsMultiSelect ? default : _selectedItems.FirstOrDefault(); + /// + /// The ElementReference to the input element in combo-box mode. + /// + public ElementReference? InputElement => Combo ? _comboBoxInputRef : null; + + /// + /// Gives focus to the input element in combo-box mode. + /// + public ValueTask FocusAsync() => Combo ? _comboBoxInputRef.FocusAsync() : ValueTask.CompletedTask; + [JSInvokable("CloseCallout")] @@ -751,12 +767,15 @@ private async ValueTask FocusOnComboBoxInput() private ICollection GetSearchedItems() { + if (Items is null) return []; + return _searchText.HasNoValue() ? Items : SearchFunction is not null ? SearchFunction.Invoke(Items, _searchText!) : Items.Where(i => GetItemType(i) == BitDropdownItemType.Normal - && (GetText(i)?.Contains(_searchText!, StringComparison.OrdinalIgnoreCase) ?? false)).ToArray(); + && (GetText(i)?.Contains(_searchText!, StringComparison.OrdinalIgnoreCase) ?? false)) + .ToArray(); } private string GetSearchBoxClasses() diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs index 7ce9e64462..40b259fd50 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/NumberField/BitNumberField.razor.cs @@ -25,11 +25,12 @@ public partial class BitNumberField private ElementReference _buttonIncrement; private ElementReference _buttonDecrement; private readonly Type _typeOfValue; + private readonly bool _isNullableType; private bool _hasFocus; - private bool _isPointerDown; private readonly bool _isDecimals; private readonly double _minGenericValue; private readonly double _maxGenericValue; + private CancellationTokenSource _cancellationTokenSource = new(); private string? _intermediateValue { @@ -40,12 +41,19 @@ private string? _intermediateValue if (ValueHasBeenSet && ValueChanged.HasDelegate is false) return; var cleanValue = GetCleanValue(value); - var isNumber = double.TryParse(cleanValue, out var numericValue); + if (_isNullableType && cleanValue.HasNoValue()) + { + SetValue(null); + } + else + { + var isNumber = double.TryParse(cleanValue, out var numericValue); - if (isNumber is false) return; - if (numericValue == GetDoubleValueOrDefault(CurrentValue)) return; + if (isNumber is false) return; + if (numericValue == GetDoubleValueOrDefault(CurrentValue)) return; + SetValue(numericValue); + } - SetValue(numericValue); _ = OnChange.InvokeAsync(CurrentValue); } } @@ -53,6 +61,7 @@ private string? _intermediateValue public BitNumberField() { _typeOfValue = typeof(TValue); + _isNullableType = Nullable.GetUnderlyingType(_typeOfValue) is not null; _typeOfValue = Nullable.GetUnderlyingType(_typeOfValue) ?? _typeOfValue; _isDecimals = _typeOfValue == typeof(float) || _typeOfValue == typeof(double) || _typeOfValue == typeof(decimal); @@ -307,6 +316,18 @@ public bool Required + /// + /// The ElementReference to the input element of the BitNumberField. + /// + public ElementReference InputElement => _inputRef; + + /// + /// Gives focus to the input element of the BitNumberField. + /// + public ValueTask FocusAsync() => _inputRef.FocusAsync(); + + + protected override string RootElementClass => "bit-nfl"; protected override void RegisterCssClasses() @@ -362,6 +383,8 @@ protected override async Task OnParametersSetAsync() await base.OnParametersSetAsync(); } + + private async Task ApplyValueChange(bool isIncrement) { bool isValid; @@ -402,20 +425,34 @@ private async Task HandleOnPointerDown(bool isIncrement) await _buttonDecrement.FocusAsync(); } - _isPointerDown = true; + await ChangeValue(isIncrement); + ResetCts(); - await ChangeValue(isIncrement, INITIAL_STEP_DELAY); + var cts = _cancellationTokenSource; + await Task.Run(async () => + { + await InvokeAsync(async () => + { + await Task.Delay(INITIAL_STEP_DELAY); + await ContinuousChangeValue(isIncrement, cts); + }); + }, cts.Token); } - private void HandleOnPointerUpOrOut() + private async Task ContinuousChangeValue(bool isIncrement, CancellationTokenSource cts) { - _isPointerDown = false; + if (cts.IsCancellationRequested) return; + + await ChangeValue(isIncrement); + + StateHasChanged(); + + await Task.Delay(STEP_DELAY); + await ContinuousChangeValue(isIncrement, cts); } - private async Task ChangeValue(bool isIncrement, int stepDelay) + private async Task ChangeValue(bool isIncrement) { - if (_isPointerDown is false) return; - await ApplyValueChange(isIncrement); if (isIncrement && OnIncrement.HasDelegate) { @@ -426,12 +463,18 @@ private async Task ChangeValue(bool isIncrement, int stepDelay) { await OnDecrement.InvokeAsync(CurrentValue); } + } - StateHasChanged(); - - await Task.Delay(stepDelay); + private void HandleOnPointerUpOrOut() + { + ResetCts(); + } - await ChangeValue(isIncrement, STEP_DELAY); + private void ResetCts() + { + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = new(); } private async Task HandleOnKeyDown(KeyboardEventArgs e) @@ -526,9 +569,15 @@ private int CalculatePrecision(TValue? value) return 0; } - private void SetValue(double value) + private void SetValue(double? value) { - value = Normalize(value); + if (value is null) + { + CurrentValue = default; + return; + } + + value = Normalize(value.Value); if (value > _internalMax) { @@ -799,4 +848,14 @@ protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(fa var normalValue = Normalize(GetDoubleValueOrDefault(value)!.Value); return string.Format(NumberFormat, normalValue); } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _cancellationTokenSource.Dispose(); + } + + base.Dispose(disposing); + } } diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.razor.cs index 5c96d9ea20..21a9062774 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/OtpInput/BitOtpInput.razor.cs @@ -80,21 +80,15 @@ public partial class BitOtpInput : IDisposable [Parameter] public bool Vertical { get; set; } + /// + /// The ElementReferences to the input elements of the BitOtpInput. + /// + public ElementReference[] InputElements => _inputRefs; - [JSInvokable] - public async Task SetPastedData(string pastedValue) - { - if (IsEnabled is false) return; - if (ValueHasBeenSet && ValueChanged.HasDelegate is false) return; - if (pastedValue.HasNoValue()) return; - if (InputType is BitOtpInputType.Number && int.TryParse(pastedValue, out _) is false) return; - - SetInputsValue(pastedValue); - - CurrentValue = string.Join(string.Empty, _inputValues); - - await OnChange.InvokeAsync(CurrentValue); - } + /// + /// Gives focus to a specific input element of the BitOtpInput. + /// + public ValueTask FocusAsync(int index = 0) => _inputRefs[index].FocusAsync(); @@ -171,6 +165,23 @@ protected override void Dispose(bool disposing) + [JSInvokable] + public async Task SetPastedData(string pastedValue) + { + if (IsEnabled is false) return; + if (ValueHasBeenSet && ValueChanged.HasDelegate is false) return; + if (pastedValue.HasNoValue()) return; + if (InputType is BitOtpInputType.Number && int.TryParse(pastedValue, out _) is false) return; + + SetInputsValue(pastedValue); + + CurrentValue = string.Join(string.Empty, _inputValues); + + await OnChange.InvokeAsync(CurrentValue); + } + + + private string GetInputType() => InputType switch { BitOtpInputType.Text => "text", diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.razor.cs index 4db3b3472b..885b6f6597 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SearchBox/BitSearchBox.razor.cs @@ -12,14 +12,14 @@ public partial class BitSearchBox private bool showSearchButton; private bool disableAnimation; + private int _selectedIndex = -1; private string _inputId = string.Empty; + private List _searchItems = []; private string _calloutId = string.Empty; - private string _scrollContainerId = string.Empty; private ElementReference _inputRef = default!; + private string _scrollContainerId = string.Empty; private CancellationTokenSource _cancellationTokenSource = new(); private DotNetObjectReference _dotnetObj = default!; - private List _searchItems = []; - private int _selectedIndex = -1; private bool _inputHasFocus { @@ -213,9 +213,15 @@ public bool ShowSearchButton - public ElementReference InputReference => _inputRef; + /// + /// The ElementReference to the input element of the BitSearchBox. + /// + public ElementReference InputElement => _inputRef; - public ValueTask FocusInput() => _inputRef.FocusAsync(); + /// + /// Gives focus to the input element of the BitSearchBox. + /// + public ValueTask FocusAsync() => _inputRef.FocusAsync(); diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SpinButton/BitSpinButton.razor b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SpinButton/BitSpinButton.razor index 4d7dcc77b6..7643a7aa76 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SpinButton/BitSpinButton.razor +++ b/src/BlazorUI/Bit.BlazorUI/Components/Inputs/SpinButton/BitSpinButton.razor @@ -47,7 +47,7 @@