diff --git a/.github/workflows/build-arm64.yml b/.github/workflows/build-arm64.yml index 2ff9bcaa82..cc8cc4b8e8 100644 --- a/.github/workflows/build-arm64.yml +++ b/.github/workflows/build-arm64.yml @@ -33,7 +33,7 @@ jobs: run: "echo ref: ${{github.ref}} event: ${{github.event_name}}" - name: Build Version run: | - dotnet tool install --global minver-cli --version 4.3.0 + dotnet tool install --global minver-cli --version 5.0.0 version=$(minver --tag-prefix v) echo "MINVERVERSIONOVERRIDE=$version" >> $GITHUB_ENV echo "VERSION=$version" >> $GITHUB_ENV diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 85863d9568..2a4f3363a4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -38,7 +38,7 @@ jobs: - name: Version id: version run: | - dotnet tool install --global minver-cli --version 4.3.0 + dotnet tool install --global minver-cli --version 5.0.0 version=$(minver --tag-prefix v) echo "version=$version" >> $GITHUB_OUTPUT echo "### $version" >> $GITHUB_STEP_SUMMARY @@ -121,17 +121,10 @@ jobs: with: fetch-depth: 0 - - name: Setup .NET Core - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.* - #dotnet-quality: preview - - name: Cache node_modules uses: actions/cache@v4 with: - path: | - node_modules + path: node_modules key: node-modules-${{ hashFiles('package-lock.json') }} - name: Setup Node.js environment diff --git a/.github/workflows/elasticsearch-docker-7.yml b/.github/workflows/elasticsearch-docker-7.yml index 7fe17f147f..fa044a20ef 100644 --- a/.github/workflows/elasticsearch-docker-7.yml +++ b/.github/workflows/elasticsearch-docker-7.yml @@ -26,7 +26,7 @@ jobs: run: "echo ref: ${{github.ref}} event: ${{github.event_name}}" - name: Build Version run: | - dotnet tool install --global minver-cli --version 4.3.0 + dotnet tool install --global minver-cli --version 5.0.0 version=$(minver --tag-prefix v) echo "MINVERVERSIONOVERRIDE=$version" >> $GITHUB_ENV echo "VERSION=$version" >> $GITHUB_ENV diff --git a/.github/workflows/elasticsearch-docker-8.yml b/.github/workflows/elasticsearch-docker-8.yml index 9f22cbd251..7c1d8bbecc 100644 --- a/.github/workflows/elasticsearch-docker-8.yml +++ b/.github/workflows/elasticsearch-docker-8.yml @@ -26,7 +26,7 @@ jobs: run: "echo ref: ${{github.ref}} event: ${{github.event_name}}" - name: Build Version run: | - dotnet tool install --global minver-cli --version 4.3.0 + dotnet tool install --global minver-cli --version 5.0.0 version=$(minver --tag-prefix v) echo "MINVERVERSIONOVERRIDE=$version" >> $GITHUB_ENV echo "VERSION=$version" >> $GITHUB_ENV diff --git a/src/Directory.Build.props b/src/Directory.Build.props index bd755e5e63..1b7eefa9b5 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,7 +5,7 @@ Exceptionless true v - Copyright (c) 2023 Exceptionless. All rights reserved. + Copyright (c) 2024 Exceptionless. All rights reserved. https://github.com/exceptionless/exceptionless Exceptionless $(NoWarn);CS1591 @@ -15,13 +15,13 @@ true false false - 10.7.0 + 10.7.1 true - + diff --git a/src/Exceptionless.Core/Exceptionless.Core.csproj b/src/Exceptionless.Core/Exceptionless.Core.csproj index 4fc6afdc0d..cd1ec13c5e 100644 --- a/src/Exceptionless.Core/Exceptionless.Core.csproj +++ b/src/Exceptionless.Core/Exceptionless.Core.csproj @@ -25,16 +25,16 @@ - + - + - + - + diff --git a/src/Exceptionless.Core/Pipeline/030_CheckForRegressionAction.cs b/src/Exceptionless.Core/Pipeline/030_CheckForRegressionAction.cs index ede8dc7eb1..d5b052ec72 100644 --- a/src/Exceptionless.Core/Pipeline/030_CheckForRegressionAction.cs +++ b/src/Exceptionless.Core/Pipeline/030_CheckForRegressionAction.cs @@ -23,7 +23,7 @@ public CheckForRegressionAction(IStackRepository stackRepository, SemanticVersio public override async Task ProcessBatchAsync(ICollection contexts) { var stacks = contexts - .Where(c => c.Stack is not null && c.Stack.Status != StackStatus.Regressed && c.Stack.DateFixed.HasValue) + .Where(c => c.Stack is { Status: StackStatus.Fixed, DateFixed: not null }) .OrderBy(c => c.Event.Date) .GroupBy(c => c.Event.StackId); @@ -52,7 +52,16 @@ public override async Task ProcessBatchAsync(ICollection contexts) { var version = _semanticVersionParser.Parse(versionGroup.Key, versionCache) ?? _semanticVersionParser.Default; if (version < fixedInVersion) + { + foreach (var ctx in stackGroup.Where(s => s.Organization.HasPremiumFeatures)) + { + _logger.LogDebug("Discarding fixed stack event: Version {Version} is older than fixed in version {FixedInVersion}", version, fixedInVersion); + ctx.IsDiscarded = true; + ctx.IsCancelled = true; + } + continue; + } regressedVersion = version; regressedContext = versionGroup.First(); @@ -63,7 +72,7 @@ public override async Task ProcessBatchAsync(ICollection contexts) if (regressedContext is null) return; - _logger.LogTrace("Marking stack and events as regressed in version: {Version}", regressedVersion); + _logger.LogDebug("Marking stack and events as regressed in version: {Version}", regressedVersion); stack.Status = StackStatus.Regressed; await _stackRepository.MarkAsRegressedAsync(stack.Id); @@ -79,7 +88,10 @@ public override async Task ProcessBatchAsync(ICollection contexts) { cont = HandleError(ex, context); } - catch { } + catch (Exception hex) + { + _logger.LogError(hex, "Error calling HandleError: {Message}", ex.Message); + } if (!cont) context.SetError(ex.Message, ex); diff --git a/src/Exceptionless.Insulation/Exceptionless.Insulation.csproj b/src/Exceptionless.Insulation/Exceptionless.Insulation.csproj index 660dc9137a..a40922ed4f 100644 --- a/src/Exceptionless.Insulation/Exceptionless.Insulation.csproj +++ b/src/Exceptionless.Insulation/Exceptionless.Insulation.csproj @@ -2,27 +2,26 @@ - - - - - - - + + + + + + - + - + - - + + diff --git a/src/Exceptionless.Job/Exceptionless.Job.csproj b/src/Exceptionless.Job/Exceptionless.Job.csproj index 2d1cc0d7b2..e4c3e34404 100644 --- a/src/Exceptionless.Job/Exceptionless.Job.csproj +++ b/src/Exceptionless.Job/Exceptionless.Job.csproj @@ -4,22 +4,22 @@ - - + + - - - - - - - + + + + + + + - + diff --git a/src/Exceptionless.Web/ClientApp.angular/app/app.tpl.html b/src/Exceptionless.Web/ClientApp.angular/app/app.tpl.html index 838ca1d235..49b42df70e 100644 --- a/src/Exceptionless.Web/ClientApp.angular/app/app.tpl.html +++ b/src/Exceptionless.Web/ClientApp.angular/app/app.tpl.html @@ -30,7 +30,7 @@ > - © 2023 Exceptionless + © 2024 Exceptionless Exceptionless + © 2024 Exceptionless News Privacy Policy Terms of Use diff --git a/src/Exceptionless.Web/ClientApp.angular/app/auth/signup-controller.js b/src/Exceptionless.Web/ClientApp.angular/app/auth/signup-controller.js index d1ae9dbe8c..80228dd0eb 100644 --- a/src/Exceptionless.Web/ClientApp.angular/app/auth/signup-controller.js +++ b/src/Exceptionless.Web/ClientApp.angular/app/auth/signup-controller.js @@ -148,7 +148,7 @@ this.$onInit = function $onInit() { vm._source = "app.auth.Signup"; - vm._canSignup = !!ENABLE_ACCOUNT_CREATION; + vm._canSignup = !!ENABLE_ACCOUNT_CREATION || !!$stateParams.token; vm.authenticate = authenticate; vm.isExternalLoginEnabled = isExternalLoginEnabled; vm.signup = signup; diff --git a/src/Exceptionless.Web/ClientApp/.vscode/extensions.json b/src/Exceptionless.Web/ClientApp/.vscode/extensions.json index e50aa07750..89a970e36b 100644 --- a/src/Exceptionless.Web/ClientApp/.vscode/extensions.json +++ b/src/Exceptionless.Web/ClientApp/.vscode/extensions.json @@ -2,10 +2,9 @@ "recommendations": [ "svelte.svelte-vscode", "bradlc.vscode-tailwindcss", - "digitalbrainstem.javascript-ejs-support", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "selemondev.vscode-shadcn-svelte", - "zixuanchen.vitest-explorer" + "vitest.explorer" ] } diff --git a/src/Exceptionless.Web/ClientApp/.vscode/settings.json b/src/Exceptionless.Web/ClientApp/.vscode/settings.json index 20de551c91..45c29bb1b2 100644 --- a/src/Exceptionless.Web/ClientApp/.vscode/settings.json +++ b/src/Exceptionless.Web/ClientApp/.vscode/settings.json @@ -2,7 +2,10 @@ "debug.allowBreakpointsEverywhere": true, "cSpell.words": [ "clsx", + "cmdk", "colour", + "echarts", + "formsnap", "haserror", "iconify", "keyof", @@ -16,6 +19,8 @@ "satellizer", "sessionend", "shadcn", + "sonner", + "superforms", "tailwindcss", "tanstack" ], @@ -43,5 +48,10 @@ "tailwindCSS.includeLanguages": { "svelte": "html" }, - "typescript.tsdk": "node_modules\\typescript\\lib" + "typescript.tsdk": "node_modules\\typescript\\lib", + "workbench.editor.customLabels.patterns": { + "**/routes/**/+page.svelte": "${dirname(1)}/${dirname}", + "**/routes/**/+layout.svelte": "${dirname}/+layout.svelte", + "**/lib/**/index.ts": "${dirname}/index.ts" + } } diff --git a/src/Exceptionless.Web/ClientApp/package-lock.json b/src/Exceptionless.Web/ClientApp/package-lock.json index d29b9f58fd..2d98dff123 100644 --- a/src/Exceptionless.Web/ClientApp/package-lock.json +++ b/src/Exceptionless.Web/ClientApp/package-lock.json @@ -8,54 +8,56 @@ "name": "exceptionless", "version": "8.0.0", "dependencies": { - "@exceptionless/browser": "^3.0.5", - "@iconify-json/mdi": "^1.1.64", - "@tanstack/svelte-query": "^5.22.2", - "@tanstack/svelte-query-devtools": "^5.24.0", - "@tanstack/svelte-table": "^8.12.0", + "@exceptionless/browser": "^3.1.0", + "@iconify-json/mdi": "^1.1.65", + "@tanstack/svelte-query": "^5.29.0", + "@tanstack/svelte-query-devtools": "^5.29.0", + "@tanstack/svelte-table": "^8.15.3", "@web3-storage/parse-link-header": "^3.1.0", - "bits-ui": "^0.18.1", + "bits-ui": "^0.21.2", "class-validator": "^0.14.1", "clsx": "^2.1.0", - "cmdk-sv": "^0.0.13", + "cmdk-sv": "^0.0.17", "echarts": "^5.5.0", - "mode-watcher": "^0.2.1", + "formsnap": "^1.0.0", + "mode-watcher": "^0.3.0", "oidc-client-ts": "^3.0.1", "pretty-ms": "^9.0.0", "svelte-echarts": "^0.1.1", "svelte-legos": "^0.2.2", - "svelte-local-storage-store": "^0.6.4", - "svelte-sonner": "^0.3.18", + "svelte-persisted-store": "^0.9.1", + "svelte-sonner": "^0.3.21", "svelte-time": "^0.8.2", - "tailwind-merge": "^2.2.1", - "tailwind-variants": "^0.2.0", - "tailwindcss": "^3.4.1", + "sveltekit-superforms": "^2.12.2", + "tailwind-merge": "^2.2.2", + "tailwind-variants": "^0.2.1", + "tailwindcss": "^3.4.3", "unplugin-icons": "^0.18.5" }, "devDependencies": { - "@playwright/test": "^1.41.2", + "@playwright/test": "^1.43.0", "@sveltejs/adapter-static": "^3.0.1", - "@sveltejs/kit": "^2.5.0", + "@sveltejs/kit": "^2.5.5", "@sveltejs/vite-plugin-svelte": "^3.0.2", - "@typescript-eslint/eslint-plugin": "^7.0.2", - "@typescript-eslint/parser": "^7.0.2", - "autoprefixer": "^10.4.17", + "@typescript-eslint/eslint-plugin": "^7.5.0", + "@typescript-eslint/parser": "^7.5.0", + "autoprefixer": "^10.4.19", "cross-env": "^7.0.3", - "eslint": "^8.56.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.35.1", "npm-run-all": "^4.1.5", - "postcss": "^8.4.35", + "postcss": "^8.4.38", "prettier": "^3.2.5", - "prettier-plugin-svelte": "^3.2.1", - "prettier-plugin-tailwindcss": "^0.5.11", - "svelte": "^4.2.11", - "svelte-check": "^3.6.4", + "prettier-plugin-svelte": "^3.2.2", + "prettier-plugin-tailwindcss": "^0.5.13", + "svelte": "^4.2.12", + "svelte-check": "^3.6.9", "swagger-typescript-api": "^13.0.3", "tslib": "^2.6.2", - "typescript": "^5.4.0-beta", - "vite": "^5.1.3", - "vitest": "^1.3.1" + "typescript": "^5.4.4", + "vite": "^5.2.8", + "vitest": "^1.4.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -288,9 +290,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -298,14 +300,28 @@ "node": ">=6.9.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.9.tgz", - "integrity": "sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -315,13 +331,12 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.9.tgz", - "integrity": "sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -331,13 +346,12 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.9.tgz", - "integrity": "sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "android" @@ -347,13 +361,12 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.9.tgz", - "integrity": "sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -363,13 +376,12 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.9.tgz", - "integrity": "sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -379,13 +391,12 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.9.tgz", - "integrity": "sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -395,13 +406,12 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.9.tgz", - "integrity": "sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -411,13 +421,12 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.9.tgz", - "integrity": "sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -427,13 +436,12 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.9.tgz", - "integrity": "sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -443,13 +451,12 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.9.tgz", - "integrity": "sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "linux" @@ -459,13 +466,12 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.9.tgz", - "integrity": "sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -475,13 +481,12 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.9.tgz", - "integrity": "sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", "cpu": [ "mips64el" ], - "dev": true, "optional": true, "os": [ "linux" @@ -491,13 +496,12 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.9.tgz", - "integrity": "sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -507,13 +511,12 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.9.tgz", - "integrity": "sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -523,13 +526,12 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.9.tgz", - "integrity": "sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -539,13 +541,12 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.9.tgz", - "integrity": "sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -555,13 +556,12 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.9.tgz", - "integrity": "sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "netbsd" @@ -571,13 +571,12 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.9.tgz", - "integrity": "sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -587,13 +586,12 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.9.tgz", - "integrity": "sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "sunos" @@ -603,13 +601,12 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.9.tgz", - "integrity": "sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -619,13 +616,12 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.9.tgz", - "integrity": "sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -635,13 +631,12 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.9.tgz", - "integrity": "sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -698,27 +693,27 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@exceptionless/browser": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@exceptionless/browser/-/browser-3.0.5.tgz", - "integrity": "sha512-CbbX9fBCdhODeBwuklE+uqNQ4lqGH5ztFJjxfLseeBgg0RcGvmom7io9+nXNnc38Lp7yKRBnpWWxGoYViHlNGQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@exceptionless/browser/-/browser-3.1.0.tgz", + "integrity": "sha512-RzQDR2ua+CdaJAepxo8SIy/kEcNlnvrd6AsecYJ3cY0JSNIS0r+oNgfT/QNX+I8Vzp1CjUUHiZs5E3U+haoShg==", "dependencies": { - "@exceptionless/core": "3.0.5", + "@exceptionless/core": "3.1.0", "stacktrace-js": "^2.0.2" } }, "node_modules/@exceptionless/core": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@exceptionless/core/-/core-3.0.5.tgz", - "integrity": "sha512-whBT9bfGdeYNt1ig7jd4ZnrmwIVXLF1nFaJGRd2XfNn9O7bQnnSWan962e1qu7DKnCLTCZV9aVGvQ/F8XG5hUg==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@exceptionless/core/-/core-3.1.0.tgz", + "integrity": "sha512-BwyKIsaL61lqsOcI8+rSr1M55w+iyGw1G/XXNd7BWU/oOoWZRTBRM/RPDQIzycqphq52LWdDWS1aHDnUcKNnKw==" }, "node_modules/@exodus/schemasafe": { "version": "1.2.3", @@ -748,14 +743,44 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" }, + "node_modules/@gcornut/valibot-json-schema": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@gcornut/valibot-json-schema/-/valibot-json-schema-0.0.27.tgz", + "integrity": "sha512-xcMaUStVgQzPrK3d7PuLFbQ+3qSp6LzaLExAm52E3FKmUfjQa7Sw5cDK6Hfu/8WT0yfGsuSCuJ5uT1sosjR9Qg==", + "optional": true, + "bin": { + "valibot-json-schema": "bin/index.js" + }, + "peerDependencies": { + "@types/json-schema": ">= 7.0.14", + "esbuild": ">= 0.18.20", + "esbuild-runner": ">= 2.2.2", + "valibot": ">= 0.21.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "optional": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -776,15 +801,15 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@iconify-json/mdi": { - "version": "1.1.64", - "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.1.64.tgz", - "integrity": "sha512-zGeo5TjhNFAY6FmSDBLAzDO811t77r6v/mDi7CAL9w5eXqKez6bIjk8R9AL/RHIeq44ALP4Ozr4lMqFTkHr7ug==", + "version": "1.1.65", + "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.1.65.tgz", + "integrity": "sha512-P9ovos4pKjqwbcUaF5axnHKc1J4djfwLQ6vheJSzbTuZ7gLyonAI/mDDc+ekC4HFCnrYWPjdpkKT+mIujuqOaA==", "dependencies": { "@iconify/types": "*" } @@ -982,9 +1007,9 @@ } }, "node_modules/@melt-ui/svelte": { - "version": "0.71.2", - "resolved": "https://registry.npmjs.org/@melt-ui/svelte/-/svelte-0.71.2.tgz", - "integrity": "sha512-GDUErhAphEoEOLpcBjQ84BgzRR6M3344fQE4QYFffwT7aedWak7CvNsECgeig1Y5xvfDmeEaFnGlOQXIBucJYw==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@melt-ui/svelte/-/svelte-0.76.2.tgz", + "integrity": "sha512-7SbOa11tXUS95T3fReL+dwDs5FyJtCEqrqG3inRziDws346SYLsxOQ6HmX+4BkIsQh1R8U3XNa+EMmdMt38lMA==", "dependencies": { "@floating-ui/core": "^1.3.1", "@floating-ui/dom": "^1.4.5", @@ -998,9 +1023,9 @@ } }, "node_modules/@melt-ui/svelte/node_modules/nanoid": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.5.tgz", - "integrity": "sha512-/Veqm+QKsyMY3kqi4faWplnY1u+VuKO3dD2binyPIybP31DRO29bPF+1mszgLnrR2KqSLceFLBNw0zmvDzN1QQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.6.tgz", + "integrity": "sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==", "funding": [ { "type": "github", @@ -1047,12 +1072,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.41.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz", - "integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==", + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.0.tgz", + "integrity": "sha512-Ebw0+MCqoYflop7wVKj711ccbNlrwTBCtjY5rlbiY9kHL2bCYxq+qltK6uPsVBGGAOb033H2VO0YobcQVxoW7Q==", "dev": true, "dependencies": { - "playwright": "1.41.2" + "playwright": "1.43.0" }, "bin": { "playwright": "cli.js" @@ -1064,178 +1089,194 @@ "node_modules/@polka/url": { "version": "1.0.0-next.24", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz", - "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==", - "dev": true + "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==" + }, + "node_modules/@poppinss/macroable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@poppinss/macroable/-/macroable-1.0.1.tgz", + "integrity": "sha512-bO3+rnqGhE+gdx4DOyYjY9jCm2+c5Ncyl2Gmst0w271rIFnsB00btonpdmAqvFNzS8rcas+APGm+47fYMmkpQA==", + "optional": true, + "engines": { + "node": ">=18.16.0" + } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.0.tgz", - "integrity": "sha512-+1ge/xmaJpm1KVBuIH38Z94zj9fBD+hp+/5WLaHgyY8XLq1ibxk/zj6dTXaqM2cAbYKq8jYlhHd6k05If1W5xA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.0.tgz", - "integrity": "sha512-im6hUEyQ7ZfoZdNvtwgEJvBWZYauC9KVKq1w58LG2Zfz6zMd8gRrbN+xCVoqA2hv/v6fm9lp5LFGJ3za8EQH3A==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.0.tgz", - "integrity": "sha512-u7aTMskN6Dmg1lCT0QJ+tINRt+ntUrvVkhbPfFz4bCwRZvjItx2nJtwJnJRlKMMaQCHRjrNqHRDYvE4mBm3DlQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.0.tgz", - "integrity": "sha512-8FvEl3w2ExmpcOmX5RJD0yqXcVSOqAJJUJ29Lca29Ik+3zPS1yFimr2fr5JSZ4Z5gt8/d7WqycpgkX9nocijSw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.0.tgz", - "integrity": "sha512-lHoKYaRwd4gge+IpqJHCY+8Vc3hhdJfU6ukFnnrJasEBUvVlydP8PuwndbWfGkdgSvZhHfSEw6urrlBj0TSSfg==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.0.tgz", - "integrity": "sha512-JbEPfhndYeWHfOSeh4DOFvNXrj7ls9S/2omijVsao+LBPTPayT1uKcK3dHW3MwDJ7KO11t9m2cVTqXnTKpeaiw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.0.tgz", - "integrity": "sha512-ahqcSXLlcV2XUBM3/f/C6cRoh7NxYA/W7Yzuv4bDU1YscTFw7ay4LmD7l6OS8EMhTNvcrWGkEettL1Bhjf+B+w==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.0.tgz", - "integrity": "sha512-uwvOYNtLw8gVtrExKhdFsYHA/kotURUmZYlinH2VcQxNCQJeJXnkmWgw2hI9Xgzhgu7J9QvWiq9TtTVwWMDa+w==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.0.tgz", - "integrity": "sha512-m6pkSwcZZD2LCFHZX/zW2aLIISyzWLU3hrLLzQKMI12+OLEzgruTovAxY5sCZJkipklaZqPy/2bEEBNjp+Y7xg==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.0.tgz", - "integrity": "sha512-VFAC1RDRSbU3iOF98X42KaVicAfKf0m0OvIu8dbnqhTe26Kh6Ym9JrDulz7Hbk7/9zGc41JkV02g+p3BivOdAg==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.0.tgz", - "integrity": "sha512-9jPgMvTKXARz4inw6jezMLA2ihDBvgIU9Ml01hjdVpOcMKyxFBJrn83KVQINnbeqDv0+HdO1c09hgZ8N0s820Q==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.0.tgz", - "integrity": "sha512-WE4pT2kTXQN2bAv40Uog0AsV7/s9nT9HBWXAou8+++MBCnY51QS02KYtm6dQxxosKi1VIz/wZIrTQO5UP2EW+Q==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.0.tgz", - "integrity": "sha512-aPP5Q5AqNGuT0tnuEkK/g4mnt3ZhheiXrDIiSVIHN9mcN21OyXDVbEMqmXPE7e2OplNLDkcvV+ZoGJa2ZImFgw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" ] }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "optional": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "optional": true + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -1254,6 +1295,12 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sodaru/yup-to-json-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@sodaru/yup-to-json-schema/-/yup-to-json-schema-2.0.1.tgz", + "integrity": "sha512-lWb0Wiz8KZ9ip/dY1eUqt7fhTPmL24p6Hmv5Fd9pzlzAdw/YNcWZr+tiCT4oZ4Zyxzi9+1X4zv82o7jYvcFxYA==", + "optional": true + }, "node_modules/@sveltejs/adapter-static": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.1.tgz", @@ -1264,10 +1311,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.0.tgz", - "integrity": "sha512-1uyXvzC2Lu1FZa30T4y5jUAC21R309ZMRG0TPt+PPPbNUoDpy8zSmSNVWYaBWxYDqLGQ5oPNWvjvvF2IjJ1jmA==", - "dev": true, + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.5.tgz", + "integrity": "sha512-ULe3PB00q4+wYRL+IS5FDPsCEVnhEITofm7b9Yz8malcH3r1SAnW/JJ6T13hIMeu8QNRIuVQWo+P4+2VklbnLQ==", "hasInstallScript": true, "dependencies": { "@types/cookie": "^0.6.0", @@ -1299,7 +1345,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz", "integrity": "sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==", - "dev": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0", "debug": "^4.3.4", @@ -1321,7 +1366,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz", "integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==", - "dev": true, "dependencies": { "debug": "^4.3.4" }, @@ -1343,29 +1387,29 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.22.2", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.22.2.tgz", - "integrity": "sha512-z3PwKFUFACMUqe1eyesCIKg3Jv1mysSrYfrEW5ww5DCDUD4zlpTKBvUDaEjsfZzL3ULrFLDM9yVUxI/fega1Qg==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.29.0.tgz", + "integrity": "sha512-WgPTRs58hm9CMzEr5jpISe8HXa3qKQ8CxewdYZeVnA54JrPY9B1CZiwsCoLpLkf0dGRZq+LcX5OiJb0bEsOFww==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/query-devtools": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.24.0.tgz", - "integrity": "sha512-pThim455t69zrZaQKa7IRkEIK8UBTS+gHVAdNfhO72Xh4rWpMc63ovRje5/n6iw63+d6QiJzVadsJVdPoodSeQ==", + "version": "5.28.10", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.28.10.tgz", + "integrity": "sha512-5UN629fKa5/1K/2Pd26gaU7epxRrYiT1gy+V+pW5K6hnf1DeUKK3pANSb2eHKlecjIKIhTwyF7k9XdyE2gREvQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/svelte-query": { - "version": "5.22.2", - "resolved": "https://registry.npmjs.org/@tanstack/svelte-query/-/svelte-query-5.22.2.tgz", - "integrity": "sha512-7ZK/EoAAIB6KIKiSC3NSTJPJYo2meOZjsyBXLtbEpLYr7U/mCJwgJ0dXKOUt9n3eKwUyX9N/stqwyD10F+KS8Q==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@tanstack/svelte-query/-/svelte-query-5.29.0.tgz", + "integrity": "sha512-PhcyCKyd7Q74bShyCdySYDAWbuH+RGK/GDYY9EgyEqsRfg78eFTRSlhNnGS38jFd/QrAFHj1iomqF7fRWc2nGg==", "dependencies": { - "@tanstack/query-core": "5.22.2" + "@tanstack/query-core": "5.29.0" }, "funding": { "type": "github", @@ -1376,11 +1420,11 @@ } }, "node_modules/@tanstack/svelte-query-devtools": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/@tanstack/svelte-query-devtools/-/svelte-query-devtools-5.24.0.tgz", - "integrity": "sha512-XIIeyhvN4XjyBT3jmp3T448K30Ut4cFqR0EzHnbEYSyHkNrpl2K3YKj/PSHyksq5+yF3ACPbuwEwqaXmXAao6w==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@tanstack/svelte-query-devtools/-/svelte-query-devtools-5.29.0.tgz", + "integrity": "sha512-uQYJvHnJf790cQpXsl/ID1mjgceGJd/Gq8e6TQi5vr/+c2r3R0t57DMJ/e3xB4ZJh1jbmz/WGRvx2jBZgiCzfg==", "dependencies": { - "@tanstack/query-devtools": "5.24.0", + "@tanstack/query-devtools": "5.28.10", "esm-env": "^1.0.0" }, "funding": { @@ -1388,16 +1432,16 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/svelte-query": "^5.22.2", + "@tanstack/svelte-query": "^5.29.0", "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0-next.0" } }, "node_modules/@tanstack/svelte-table": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/@tanstack/svelte-table/-/svelte-table-8.12.0.tgz", - "integrity": "sha512-IgmCj4tVUgjQAUa895XommqNkNdlbi5K3MgcuyB7SbgRMXZXWUrz4chDSrFSseosLz+hcizXsoavmDcDm/WYwA==", + "version": "8.15.3", + "resolved": "https://registry.npmjs.org/@tanstack/svelte-table/-/svelte-table-8.15.3.tgz", + "integrity": "sha512-Ely1Z4PZTb3+npKaU5bhNxeonssGAFLy657r1eBYiSCtA5LVJtV7R9H4jmFmRwpaQ2t4XGnGlFiZ3RHA/Wdq3w==", "dependencies": { - "@tanstack/table-core": "8.12.0" + "@tanstack/table-core": "8.15.3" }, "engines": { "node": ">=12" @@ -1411,9 +1455,9 @@ } }, "node_modules/@tanstack/table-core": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.12.0.tgz", - "integrity": "sha512-cq/ylWVrOwixmwNXQjgZaQw1Izf7+nPxjczum7paAnMtwPg1S2qRAJU+Jb8rEBUWm69voC/zcChmePlk2hc6ug==", + "version": "8.15.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.15.3.tgz", + "integrity": "sha512-wOgV0HfEvuMOv8RlqdR9MdNNqq0uyvQtP39QOvGlggHvIObOE4exS+D5LGO8LZ3LUXxId2IlUKcHDHaGujWhUg==", "engines": { "node": ">=12" }, @@ -1425,25 +1469,23 @@ "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "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 + "devOptional": true }, "node_modules/@types/node": { "version": "20.5.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==", - "dev": true, "optional": true, "peer": true }, @@ -1454,9 +1496,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", - "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/swagger-schema-official": { @@ -1466,21 +1508,21 @@ "dev": true }, "node_modules/@types/validator": { - "version": "13.11.8", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz", - "integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ==" + "version": "13.11.9", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.9.tgz", + "integrity": "sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.2.tgz", - "integrity": "sha512-/XtVZJtbaphtdrWjr+CJclaCVGPtOdBpFEnvtNf/jRV0IiEemRrL0qABex/nEt8isYcnFacm3nPHYQwL+Wb7qg==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz", + "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/type-utils": "7.0.2", - "@typescript-eslint/utils": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/type-utils": "7.5.0", + "@typescript-eslint/utils": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1489,7 +1531,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1505,46 +1547,20 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "dev": true, - "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.2.tgz", - "integrity": "sha512-GdwfDglCxSmU+QTS9vhz2Sop46ebNCXpPPvsByK7hu0rFGRHL+AusKQJ7SoN+LbLh6APFpQwHKmDSwN35Z700Q==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz", + "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/typescript-estree": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/typescript-estree": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1560,16 +1576,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", - "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz", + "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2" + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1577,18 +1593,18 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.2.tgz", - "integrity": "sha512-IKKDcFsKAYlk8Rs4wiFfEwJTQlHcdn8CLwLaxwd6zb8HNiMcQIFX9sWax2k4Cjj7l7mGS5N1zl7RCHOVwHq2VQ==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz", + "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.0.2", - "@typescript-eslint/utils": "7.0.2", + "@typescript-eslint/typescript-estree": "7.5.0", + "@typescript-eslint/utils": "7.5.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1603,39 +1619,13 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@typescript-eslint/types": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", - "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz", + "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1643,13 +1633,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", - "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz", + "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1658,7 +1648,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1694,48 +1684,22 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", - "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz", + "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/typescript-estree": "7.0.2", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/typescript-estree": "7.5.0", "semver": "^7.5.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1746,16 +1710,16 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", - "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz", + "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/types": "7.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1768,14 +1732,42 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@vinejs/compiler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vinejs/compiler/-/compiler-2.4.1.tgz", + "integrity": "sha512-WZqCZEQBvuPEghAxnpvNLclyyfqkmU+2V2K4zoZhOUJRD9KRJ+hCNQQ6LSzt7ZwSh+wwxq0r9FpAfeC3tswB8Q==", + "optional": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@vinejs/vine": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@vinejs/vine/-/vine-1.8.0.tgz", + "integrity": "sha512-Qq3XxbA26jzqS9ICifkqzT399lMQZ2fWtqeV3luI2as+UIK7qDifJFU2Q4W3q3IB5VXoWxgwAZSZEO0em9I/qQ==", + "optional": true, + "dependencies": { + "@poppinss/macroable": "^1.0.1", + "@types/validator": "^13.11.9", + "@vinejs/compiler": "^2.4.1", + "camelcase": "^8.0.0", + "dayjs": "^1.11.10", + "dlv": "^1.1.3", + "normalize-url": "^8.0.1", + "validator": "^13.11.0" + }, + "engines": { + "node": ">=18.16.0" + } + }, "node_modules/@vitest/expect": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", - "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz", + "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==", "dev": true, "dependencies": { - "@vitest/spy": "1.3.1", - "@vitest/utils": "1.3.1", + "@vitest/spy": "1.4.0", + "@vitest/utils": "1.4.0", "chai": "^4.3.10" }, "funding": { @@ -1783,12 +1775,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", - "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz", + "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==", "dev": true, "dependencies": { - "@vitest/utils": "1.3.1", + "@vitest/utils": "1.4.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -1824,9 +1816,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", - "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz", + "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -1838,9 +1830,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", - "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz", + "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -1850,9 +1842,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", - "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -1974,6 +1966,12 @@ "dequal": "^2.0.3" } }, + "node_modules/arktype": { + "version": "1.0.29-alpha", + "resolved": "https://registry.npmjs.org/arktype/-/arktype-1.0.29-alpha.tgz", + "integrity": "sha512-glMLgVhIQRSkR3tymiS+POAcWVJH09sfrgic0jHnyFL8BlhHAJZX2BzdImU9zYr1y9NBqy+U93ZNrRTHXsKRDw==", + "optional": true + }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", @@ -2027,9 +2025,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.17", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", - "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", "dev": true, "funding": [ { @@ -2046,8 +2044,8 @@ } ], "dependencies": { - "browserslist": "^4.22.2", - "caniuse-lite": "^1.0.30001578", + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -2097,14 +2095,17 @@ } }, "node_modules/bits-ui": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.18.1.tgz", - "integrity": "sha512-6junivBQ3EIHeF9j8wDa5pgzegtOwaI61ny4X8F7h2SIJi4RJWwZknkT7O5qPLeGoIYNeYV7N6EOBrr1w9/Mxg==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.21.2.tgz", + "integrity": "sha512-tDOvNdJ+uC/VWlzCZ6Pwv3enQJBw1D7leUfdIqg8WvqcDHnvn3fk4V3Y9VmpMOPnl+xTaiKxSiVpO/Dh8wD6jA==", "dependencies": { "@internationalized/date": "^3.5.1", - "@melt-ui/svelte": "0.71.2", + "@melt-ui/svelte": "0.76.2", "nanoid": "^5.0.5" }, + "funding": { + "url": "https://github.com/sponsors/huntabyte" + }, "peerDependencies": { "svelte": "^4.0.0" } @@ -2147,9 +2148,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -2166,8 +2167,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -2187,6 +2188,13 @@ "node": "*" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "optional": true, + "peer": true + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -2224,6 +2232,18 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "optional": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -2233,9 +2253,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001579", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", - "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", "dev": true, "funding": [ { @@ -2386,9 +2406,9 @@ } }, "node_modules/cmdk-sv": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/cmdk-sv/-/cmdk-sv-0.0.13.tgz", - "integrity": "sha512-WrYn0MMdVyzJx+KuOQy028/7mv+uMwO1cxVBM0uJ4KA+50PX792epsj8Yw3It8WfWR8Rae7siBCg54mIAlKsiw==", + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/cmdk-sv/-/cmdk-sv-0.0.17.tgz", + "integrity": "sha512-28QTrK1tT1TSNoGq9MVnzjeLNNjCgjmsM8c2HJfDpRt9t+GD+9m3wX/WdAPaP9jdoNYU0SSdZVdgsGgpaSQOYQ==", "dependencies": { "bits-ui": "^0.9.0", "nanoid": "^5.0.2" @@ -2506,7 +2526,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -2635,7 +2654,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2691,8 +2709,7 @@ "node_modules/devalue": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", - "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", - "dev": true + "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==" }, "node_modules/didyoumean": { "version": "1.2.2", @@ -2752,9 +2769,9 @@ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, "node_modules/electron-to-chromium": { - "version": "1.4.642", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.642.tgz", - "integrity": "sha512-M4+u22ZJGpk4RY7tne6W+APkZhnnhmAH48FNl8iEFK2lEgob+U5rUQsIqQhvAwCXYpfd3H20pHK/ENsCvwTbsA==", + "version": "1.4.690", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.690.tgz", + "integrity": "sha512-+2OAGjUx68xElQhydpcbqH50hE8Vs2K6TkAeLhICYfndb67CVH0UsZaijmRUE3rHlIxU1u0jxwhgVe6fK3YANA==", "dev": true }, "node_modules/emoji-regex": { @@ -2877,10 +2894,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.19.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.9.tgz", - "integrity": "sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==", - "dev": true, + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -2889,30 +2905,55 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.19.9", - "@esbuild/android-arm64": "0.19.9", - "@esbuild/android-x64": "0.19.9", - "@esbuild/darwin-arm64": "0.19.9", - "@esbuild/darwin-x64": "0.19.9", - "@esbuild/freebsd-arm64": "0.19.9", - "@esbuild/freebsd-x64": "0.19.9", - "@esbuild/linux-arm": "0.19.9", - "@esbuild/linux-arm64": "0.19.9", - "@esbuild/linux-ia32": "0.19.9", - "@esbuild/linux-loong64": "0.19.9", - "@esbuild/linux-mips64el": "0.19.9", - "@esbuild/linux-ppc64": "0.19.9", - "@esbuild/linux-riscv64": "0.19.9", - "@esbuild/linux-s390x": "0.19.9", - "@esbuild/linux-x64": "0.19.9", - "@esbuild/netbsd-x64": "0.19.9", - "@esbuild/openbsd-x64": "0.19.9", - "@esbuild/sunos-x64": "0.19.9", - "@esbuild/win32-arm64": "0.19.9", - "@esbuild/win32-ia32": "0.19.9", - "@esbuild/win32-x64": "0.19.9" + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/esbuild-runner": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/esbuild-runner/-/esbuild-runner-2.2.2.tgz", + "integrity": "sha512-fRFVXcmYVmSmtYm2mL8RlUASt2TDkGh3uRcvHFOKNr/T58VrfVeKD9uT9nlgxk96u0LS0ehS/GY7Da/bXWKkhw==", + "optional": true, + "peer": true, + "dependencies": { + "source-map-support": "0.5.21", + "tslib": "2.4.0" + }, + "bin": { + "esr": "bin/esr.js" + }, + "peerDependencies": { + "esbuild": "*" } }, + "node_modules/esbuild-runner/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "optional": true, + "peer": true + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2935,16 +2976,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -3349,6 +3390,35 @@ "node": ">=12.20.0" } }, + "node_modules/formsnap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/formsnap/-/formsnap-1.0.0.tgz", + "integrity": "sha512-NQEbkCS1tKGnn6gBojIuNutxImmq/9bUk9JQ5kW8WOY37QNFtJxYr/SbX8ONWuiVLaczSvGSWXIv3hNu19arqQ==", + "dependencies": { + "nanoid": "^5.0.5" + }, + "peerDependencies": { + "svelte": "^4.0.0", + "sveltekit-superforms": "^2.3.0" + } + }, + "node_modules/formsnap/node_modules/nanoid": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.6.tgz", + "integrity": "sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -3536,8 +3606,7 @@ "node_modules/globalyzer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==" }, "node_modules/globby": { "version": "11.1.0", @@ -3562,8 +3631,7 @@ "node_modules/globrex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" }, "node_modules/gopd": { "version": "1.0.1", @@ -3718,7 +3786,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", - "dev": true, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4046,13 +4113,26 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/jiti": { - "version": "1.19.3", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz", - "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "bin": { "jiti": "bin/jiti.js" } }, + "node_modules/joi": { + "version": "17.12.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.2.tgz", + "integrity": "sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4100,6 +4180,11 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" }, + "node_modules/just-clone": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-6.2.0.tgz", + "integrity": "sha512-1IynUYEc/HAwxhi3WDpIpxJbZpMCvvrrmZVqvj9EhpvbH8lls7HhdhiByjL7DkAaWlLIzpC0Xc/VPvy/UxLNjA==" + }, "node_modules/jwt-decode": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", @@ -4112,7 +4197,6 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, "engines": { "node": ">=6" } @@ -4294,6 +4378,11 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, + "node_modules/memoize-weak": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/memoize-weak/-/memoize-weak-1.0.2.tgz", + "integrity": "sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==" + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -4392,9 +4481,9 @@ } }, "node_modules/mode-watcher": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/mode-watcher/-/mode-watcher-0.2.1.tgz", - "integrity": "sha512-HLmJgG5kmJCFR/+rcG2te54HjIxqk7BTAsFnsygZR5hcOYlhLEJQ0V8rh1axv2JQIbOAZs1yPlUBSpVATRFtUw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mode-watcher/-/mode-watcher-0.3.0.tgz", + "integrity": "sha512-k8jjuTx94HaaRKWO6JDf8wL761hFatrTIHJKl+E+3JWcnv+GnMBH062zcLsy0lbCI3n7RZxxHaWi66auFnUO4g==", "peerDependencies": { "svelte": "^4.0.0" } @@ -4403,7 +4492,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true, "engines": { "node": ">=4" } @@ -4412,7 +4500,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", - "dev": true, "engines": { "node": ">=10" } @@ -4576,6 +4663,18 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -5122,12 +5221,12 @@ } }, "node_modules/playwright": { - "version": "1.41.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz", - "integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==", + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz", + "integrity": "sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==", "dev": true, "dependencies": { - "playwright-core": "1.41.2" + "playwright-core": "1.43.0" }, "bin": { "playwright": "cli.js" @@ -5140,9 +5239,9 @@ } }, "node_modules/playwright-core": { - "version": "1.41.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz", - "integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==", + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz", + "integrity": "sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -5166,9 +5265,9 @@ } }, "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -5186,7 +5285,7 @@ "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -5374,9 +5473,9 @@ } }, "node_modules/prettier-plugin-svelte": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.1.tgz", - "integrity": "sha512-ENAPbIxASf2R79IZwgkG5sBdeNA9kLRlXVvKKmTXh79zWTy0KKoT86XO2pHrTitUPINd+iXWy12MRmgzKGVckA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.2.tgz", + "integrity": "sha512-ZzzE/wMuf48/1+Lf2Ffko0uDa6pyCfgHV6+uAhtg2U0AAXGrhCSW88vEJNAkAxW5qyrFY1y1zZ4J8TgHrjW++Q==", "dev": true, "peerDependencies": { "prettier": "^3.0.0", @@ -5384,9 +5483,9 @@ } }, "node_modules/prettier-plugin-tailwindcss": { - "version": "0.5.11", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.11.tgz", - "integrity": "sha512-AvI/DNyMctyyxGOjyePgi/gqj5hJYClZ1avtQvLlqMT3uDZkRbi4HhGUpok3DRzv9z7Lti85Kdj3s3/1CeNI0w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.13.tgz", + "integrity": "sha512-2tPWHCFNC+WRjAC4SIWQNSOdcL1NNkydXim8w7TDqlZi+/ulZYz2OouAI6qMtkggnPt7lGamboj6LcTMwcCvoQ==", "dev": true, "engines": { "node": ">=14.21.3" @@ -5396,6 +5495,7 @@ "@prettier/plugin-pug": "*", "@shopify/prettier-plugin-liquid": "*", "@trivago/prettier-plugin-sort-imports": "*", + "@zackad/prettier-plugin-twig-melody": "*", "prettier": "^3.0", "prettier-plugin-astro": "*", "prettier-plugin-css-order": "*", @@ -5404,6 +5504,7 @@ "prettier-plugin-marko": "*", "prettier-plugin-organize-attributes": "*", "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", "prettier-plugin-style-order": "*", "prettier-plugin-svelte": "*" }, @@ -5420,6 +5521,9 @@ "@trivago/prettier-plugin-sort-imports": { "optional": true }, + "@zackad/prettier-plugin-twig-melody": { + "optional": true + }, "prettier-plugin-astro": { "optional": true }, @@ -5441,13 +5545,13 @@ "prettier-plugin-organize-imports": { "optional": true }, - "prettier-plugin-style-order": { + "prettier-plugin-sort-imports": { "optional": true }, - "prettier-plugin-svelte": { + "prettier-plugin-style-order": { "optional": true }, - "prettier-plugin-twig-melody": { + "prettier-plugin-svelte": { "optional": true } } @@ -5505,6 +5609,12 @@ "node": ">=6" } }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "optional": true + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5683,10 +5793,12 @@ } }, "node_modules/rollup": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.0.tgz", - "integrity": "sha512-bUHW/9N21z64gw8s6tP4c88P382Bq/L5uZDowHlHx6s/QWpjJXivIAbEw6LZthgSvlEizZBfLC4OAvWe7aoF7A==", - "dev": true, + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, @@ -5695,19 +5807,19 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.0", - "@rollup/rollup-android-arm64": "4.9.0", - "@rollup/rollup-darwin-arm64": "4.9.0", - "@rollup/rollup-darwin-x64": "4.9.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.0", - "@rollup/rollup-linux-arm64-gnu": "4.9.0", - "@rollup/rollup-linux-arm64-musl": "4.9.0", - "@rollup/rollup-linux-riscv64-gnu": "4.9.0", - "@rollup/rollup-linux-x64-gnu": "4.9.0", - "@rollup/rollup-linux-x64-musl": "4.9.0", - "@rollup/rollup-win32-arm64-msvc": "4.9.0", - "@rollup/rollup-win32-ia32-msvc": "4.9.0", - "@rollup/rollup-win32-x64-msvc": "4.9.0", + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", "fsevents": "~2.3.2" } }, @@ -5737,7 +5849,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dev": true, "dependencies": { "mri": "^1.1.0" }, @@ -5819,8 +5930,7 @@ "node_modules/set-cookie-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", - "dev": true + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" }, "node_modules/set-function-name": { "version": "2.0.1", @@ -5953,7 +6063,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", - "dev": true, "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", @@ -6008,9 +6117,30 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "optional": true, + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6281,6 +6411,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/superstruct": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", + "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", + "optional": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6305,9 +6444,9 @@ } }, "node_modules/svelte": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.11.tgz", - "integrity": "sha512-YIQk3J4X89wOLhjsqIW8tqY3JHPuBdtdOIkASP2PZeAMcSW9RsIjQzMesCrxOF3gdWYC0mKknlKF7OqmLM+Zqg==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.12.tgz", + "integrity": "sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==", "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", @@ -6329,9 +6468,9 @@ } }, "node_modules/svelte-check": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.4.tgz", - "integrity": "sha512-mY/dqucqm46p72M8yZmn81WPZx9mN6uuw8UVfR3ZKQeLxQg5HDGO3HHm5AZuWZPYNMLJ+TRMn+TeN53HfQ/vsw==", + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.9.tgz", + "integrity": "sha512-hDQrk3L0osX07djQyMiXocKysTLfusqi8AriNcCiQxhQR49/LonYolcUGMtZ0fbUR8HTR198Prrgf52WWU9wEg==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", @@ -6340,7 +6479,7 @@ "import-fresh": "^3.2.1", "picocolors": "^1.0.0", "sade": "^1.7.4", - "svelte-preprocess": "^5.1.0", + "svelte-preprocess": "^5.1.3", "typescript": "^5.0.3" }, "bin": { @@ -6413,19 +6552,6 @@ } } }, - "node_modules/svelte-check/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/svelte-echarts": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/svelte-echarts/-/svelte-echarts-0.1.1.tgz", @@ -6466,7 +6592,6 @@ "version": "0.15.3", "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", - "dev": true, "engines": { "node": "^12.20 || ^14.13.1 || >= 16" }, @@ -6487,21 +6612,21 @@ "svelte": "^4.0.0" } }, - "node_modules/svelte-local-storage-store": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/svelte-local-storage-store/-/svelte-local-storage-store-0.6.4.tgz", - "integrity": "sha512-45WoY2vSGPQM1sIQJ9jTkPPj20hYeqm+af6mUGRFSPP5WglZf36YYoZqwmZZ8Dt/2SU8lem+BTA8/Z/8TkqNLg==", + "node_modules/svelte-persisted-store": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/svelte-persisted-store/-/svelte-persisted-store-0.9.1.tgz", + "integrity": "sha512-l00I8Dy5GKjdjnE9ZcMeXLLMhvgV0+Iuru0Mue7eU3tB+pHBwBB2RVVqw2uC2Hbrf7cyZtsV/lnPKhjTHIWphQ==", "engines": { "node": ">=0.14" }, "peerDependencies": { - "svelte": "^3.48.0 || >4.0.0" + "svelte": "^3.48.0 || ^4.0.0 || ^5.0.0-next.0" } }, "node_modules/svelte-sonner": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/svelte-sonner/-/svelte-sonner-0.3.18.tgz", - "integrity": "sha512-DkpbeLB1yZ6CQ0vg/tpFUv2KGxdugODBjZYk9KWsxIAMOsnKg2VEyV2h1ycDztaEbiwoIGBObPvv+MG/4z1HSg==", + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/svelte-sonner/-/svelte-sonner-0.3.21.tgz", + "integrity": "sha512-OodylZ4ZwX4XNnpujEGzUiX66aIwve4QulI7qNmKIw49LIfAxV1LTQaJ6Xj5KsNqWz72NsO1txxV3im3021vEg==", "peerDependencies": { "svelte": ">=3 <5" } @@ -6514,6 +6639,88 @@ "dayjs": "^1.11.10" } }, + "node_modules/sveltekit-superforms": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/sveltekit-superforms/-/sveltekit-superforms-2.12.2.tgz", + "integrity": "sha512-fFOXaluP1os/Tamx7gzwhT3tXPAfqZ8KYRC0UfXdXeUtlUIUfiGrIifDJ26/9uePmF8Zhqy2M0XjG8W9kQnJpg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ciscoheat" + }, + { + "type": "ko-fi", + "url": "https://ko-fi.com/ciscoheat" + }, + { + "type": "paypal", + "url": "https://www.paypal.com/donate/?hosted_button_id=NY7F5ALHHSVQS" + } + ], + "dependencies": { + "devalue": "^4.3.2", + "just-clone": "^6.2.0", + "memoize-weak": "^1.0.2", + "ts-deepmerge": "^7.0.0" + }, + "optionalDependencies": { + "@gcornut/valibot-json-schema": "^0.0.27", + "@sinclair/typebox": "^0.32.20", + "@sodaru/yup-to-json-schema": "^2.0.1", + "@vinejs/vine": "^1.8.0", + "arktype": "1.0.29-alpha", + "joi": "^17.12.2", + "superstruct": "^1.0.4", + "valibot": "^0.30.0", + "yup": "^1.4.0", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.5" + }, + "peerDependencies": { + "@sinclair/typebox": ">=0.32.13 <1", + "@sveltejs/kit": "1.x || 2.x", + "@vinejs/vine": "^1.7.1", + "arktype": "1.0.29-alpha", + "joi": "^17.12.1", + "superstruct": "^1.0.3", + "svelte": "3.x || 4.x || >=5.0.0-next.51", + "valibot": ">=0.28.1 <1", + "yup": "^1.3.3", + "zod": "^3.22.4" + }, + "peerDependenciesMeta": { + "@sinclair/typebox": { + "optional": true + }, + "@vinejs/vine": { + "optional": true + }, + "arktype": { + "optional": true + }, + "joi": { + "optional": true + }, + "superstruct": { + "optional": true + }, + "valibot": { + "optional": true + }, + "yup": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/sveltekit-superforms/node_modules/@sinclair/typebox": { + "version": "0.32.20", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.32.20.tgz", + "integrity": "sha512-ziK497ILSIYMxD/thl496idIb03IZPlha04itLQu1xAFQbumWZ+Dj4PMMCkDRpAYhvVSdmRlTjGu2B2MA5RplQ==", + "optional": true + }, "node_modules/swagger-schema-official": { "version": "2.0.0-bab6bed", "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", @@ -6627,11 +6834,11 @@ "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" }, "node_modules/tailwind-merge": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.1.tgz", - "integrity": "sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.2.tgz", + "integrity": "sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==", "dependencies": { - "@babel/runtime": "^7.23.7" + "@babel/runtime": "^7.24.0" }, "funding": { "type": "github", @@ -6639,9 +6846,9 @@ } }, "node_modules/tailwind-variants": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.2.0.tgz", - "integrity": "sha512-EuW5Sic7c0tzp+p5rJwAgb7398Jb0hi4zkyCstOoZPW0DWwr+EWkNtnZYEo5CjgE1tazHUzyt4oIhss64UXRVA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.2.1.tgz", + "integrity": "sha512-2xmhAf4UIc3PijOUcJPA1LP4AbxhpcHuHM2C26xM0k81r0maAO6uoUSHl3APmvHZcY5cZCY/bYuJdfFa4eGoaw==", "dependencies": { "tailwind-merge": "^2.2.0" }, @@ -6654,9 +6861,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", - "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", + "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -6666,7 +6873,7 @@ "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.19.1", + "jiti": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -6750,11 +6957,16 @@ "node": ">=0.8" } }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "optional": true + }, "node_modules/tiny-glob": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" @@ -6795,11 +7007,16 @@ "node": ">=8.0" } }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "optional": true + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, "engines": { "node": ">=6" } @@ -6810,6 +7027,26 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-deepmerge": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.0.tgz", + "integrity": "sha512-WZ/iAJrKDhdINv1WG6KZIGHrZDar6VfhftG1QJFpVbOYZMYJLJOvZOo1amictRXVdBXZIgBHKswMTXzElngprA==", + "engines": { + "node": ">=14.13.1" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -6919,9 +7156,9 @@ } }, "node_modules/typescript": { - "version": "5.4.0-beta", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.0-beta.tgz", - "integrity": "sha512-KgekV5JS7TQ7Bb8eO64QGxdM7MSBUUXOXq28OWX23d2MA8SiVtNYoo4s33tCTEGV8+6AGBRD2+KiXNNnexRRYw==", + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", + "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -7056,6 +7293,12 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/valibot": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.30.0.tgz", + "integrity": "sha512-5POBdbSkM+3nvJ6ZlyQHsggisfRtyT4tVTo1EIIShs6qCdXJnyWU5TJ68vr8iTg5zpOLjXLRiBqNx+9zwZz/rA==", + "optional": true + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -7075,14 +7318,13 @@ } }, "node_modules/vite": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.3.tgz", - "integrity": "sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==", - "dev": true, + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", + "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" @@ -7130,9 +7372,9 @@ } }, "node_modules/vite-node": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", - "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz", + "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -7155,7 +7397,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", - "dev": true, "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" }, @@ -7166,16 +7407,16 @@ } }, "node_modules/vitest": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", - "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz", + "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==", "dev": true, "dependencies": { - "@vitest/expect": "1.3.1", - "@vitest/runner": "1.3.1", - "@vitest/snapshot": "1.3.1", - "@vitest/spy": "1.3.1", - "@vitest/utils": "1.3.1", + "@vitest/expect": "1.4.0", + "@vitest/runner": "1.4.0", + "@vitest/snapshot": "1.4.0", + "@vitest/spy": "1.4.0", + "@vitest/utils": "1.4.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -7189,7 +7430,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.2", "vite": "^5.0.0", - "vite-node": "1.3.1", + "vite-node": "1.4.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -7204,8 +7445,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.3.1", - "@vitest/ui": "1.3.1", + "@vitest/browser": "1.4.0", + "@vitest/ui": "1.4.0", "happy-dom": "*", "jsdom": "*" }, @@ -7417,6 +7658,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yup": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", + "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", + "optional": true, + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "optional": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", + "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "optional": true, + "peerDependencies": { + "zod": "^3.22.4" + } + }, "node_modules/zrender": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz", diff --git a/src/Exceptionless.Web/ClientApp/package.json b/src/Exceptionless.Web/ClientApp/package.json index 5dae95e2e4..1a9f6e07da 100644 --- a/src/Exceptionless.Web/ClientApp/package.json +++ b/src/Exceptionless.Web/ClientApp/package.json @@ -21,53 +21,55 @@ "upgrade": "ncu -i" }, "devDependencies": { - "@playwright/test": "^1.41.2", + "@playwright/test": "^1.43.0", "@sveltejs/adapter-static": "^3.0.1", - "@sveltejs/kit": "^2.5.0", + "@sveltejs/kit": "^2.5.5", "@sveltejs/vite-plugin-svelte": "^3.0.2", - "@typescript-eslint/eslint-plugin": "^7.0.2", - "@typescript-eslint/parser": "^7.0.2", - "autoprefixer": "^10.4.17", + "@typescript-eslint/eslint-plugin": "^7.5.0", + "@typescript-eslint/parser": "^7.5.0", + "autoprefixer": "^10.4.19", "cross-env": "^7.0.3", - "eslint": "^8.56.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.35.1", "npm-run-all": "^4.1.5", - "postcss": "^8.4.35", + "postcss": "^8.4.38", "prettier": "^3.2.5", - "prettier-plugin-svelte": "^3.2.1", - "prettier-plugin-tailwindcss": "^0.5.11", - "svelte": "^4.2.11", - "svelte-check": "^3.6.4", + "prettier-plugin-svelte": "^3.2.2", + "prettier-plugin-tailwindcss": "^0.5.13", + "svelte": "^4.2.12", + "svelte-check": "^3.6.9", "swagger-typescript-api": "^13.0.3", "tslib": "^2.6.2", - "typescript": "^5.4.0-beta", - "vite": "^5.1.3", - "vitest": "^1.3.1" + "typescript": "^5.4.4", + "vite": "^5.2.8", + "vitest": "^1.4.0" }, "dependencies": { - "@exceptionless/browser": "^3.0.5", - "@iconify-json/mdi": "^1.1.64", - "@tanstack/svelte-query": "^5.22.2", - "@tanstack/svelte-query-devtools": "^5.24.0", - "@tanstack/svelte-table": "^8.12.0", + "@exceptionless/browser": "^3.1.0", + "@iconify-json/mdi": "^1.1.65", + "@tanstack/svelte-query": "^5.29.0", + "@tanstack/svelte-query-devtools": "^5.29.0", + "@tanstack/svelte-table": "^8.15.3", "@web3-storage/parse-link-header": "^3.1.0", - "bits-ui": "^0.18.1", + "bits-ui": "^0.21.2", "class-validator": "^0.14.1", "clsx": "^2.1.0", - "cmdk-sv": "^0.0.13", + "cmdk-sv": "^0.0.17", "echarts": "^5.5.0", - "mode-watcher": "^0.2.1", + "formsnap": "^1.0.0", + "mode-watcher": "^0.3.0", "oidc-client-ts": "^3.0.1", "pretty-ms": "^9.0.0", "svelte-echarts": "^0.1.1", "svelte-legos": "^0.2.2", - "svelte-local-storage-store": "^0.6.4", - "svelte-sonner": "^0.3.18", + "svelte-persisted-store": "^0.9.1", + "svelte-sonner": "^0.3.21", "svelte-time": "^0.8.2", - "tailwind-merge": "^2.2.1", - "tailwind-variants": "^0.2.0", - "tailwindcss": "^3.4.1", + "sveltekit-superforms": "^2.12.2", + "tailwind-merge": "^2.2.2", + "tailwind-variants": "^0.2.1", + "tailwindcss": "^3.4.3", "unplugin-icons": "^0.18.5" }, "type": "module" diff --git a/src/Exceptionless.Web/ClientApp/resources.md b/src/Exceptionless.Web/ClientApp/resources.md index 7a60ac0657..4b8e6a646a 100644 --- a/src/Exceptionless.Web/ClientApp/resources.md +++ b/src/Exceptionless.Web/ClientApp/resources.md @@ -68,7 +68,7 @@ ## Storage -- +- ## i18n diff --git a/src/Exceptionless.Web/ClientApp/src/app.css b/src/Exceptionless.Web/ClientApp/src/app.css index e6a1c398a1..517ad0e4e3 100644 --- a/src/Exceptionless.Web/ClientApp/src/app.css +++ b/src/Exceptionless.Web/ClientApp/src/app.css @@ -38,34 +38,34 @@ } .dark { - --background: 223 64% 2%; - --foreground: 207 30% 93%; + --background: 220 60% 1.96%; + --foreground: 0 0% 100%; - --muted: 221 39% 11%; - --muted-foreground: 240 5% 64.9%; + --muted: 210 16.13% 12.16%; + --muted-foreground: 207.69 35.14% 92.75%; - --popover: 222 17% 11%; - --popover-foreground: 0 0% 100%; + --popover: 216 27.78% 7.06%; + --popover-foreground: 207.69 35.14% 92.75%; - --card: 216 28% 7%; - --card-foreground: 0 0% 100%; + --card: 216 27.78% 7.06%; + --card-foreground: 210 40% 98%; - --border: 216 13% 15%; - --input: 217 19% 27%; + --border: 215 14.63% 16.08%; + --input: 215 12.24% 19.22%; - --primary: 96 64% 46%; - --primary-foreground: 240 5.9% 10%; + --primary: 96 64.1% 45.88%; + --primary-foreground: 60 100% 96.27%; - --secondary: 225 21% 7%; - --secondary-foreground: 0 0% 100%; + --secondary: 215 15.38% 15.29%; + --secondary-foreground: 0 0% 97.25%; - --accent: 221 39% 11%; - --accent-foreground: 0 0% 100%; + --accent: 210 16.13% 12.16%; + --accent-foreground: 207.69 35.14% 92.75%; - --destructive: 0 62.8% 30.6%; + --destructive: 359.59 67.74% 42.55%; --destructive-foreground: 0 0% 100%; - --ring: 85 57% 41%; + --ring: 96 64.1% 45.88%; } } diff --git a/src/Exceptionless.Web/ClientApp/src/lib/api/auth.ts b/src/Exceptionless.Web/ClientApp/src/lib/api/auth.ts index 1d37f6286c..9f8b0220b0 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/api/auth.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/api/auth.ts @@ -1,14 +1,20 @@ import { goto } from '$app/navigation'; import { page } from '$app/stores'; import { env } from '$env/dynamic/public'; -import { persisted } from 'svelte-local-storage-store'; +import { persisted } from 'svelte-persisted-store'; import { derived, get } from 'svelte/store'; import { globalFetchClient } from './FetchClient'; import type { Login, TokenResult } from '$lib/models/api'; -export const accessToken = persisted('satellizer_token', null); +export const accessToken = persisted('satellizer_token', null, { + serializer: { + parse: (s) => (s === 'null' ? null : s), + stringify: (s) => s as string + } +}); + export const isAuthenticated = derived(accessToken, ($accessToken) => $accessToken !== null); export const enableAccountCreation = env.PUBLIC_ENABLE_ACCOUNT_CREATION === 'true'; export const facebookClientId = env.PUBLIC_FACEBOOK_APPID; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/api/eventsApi.ts b/src/Exceptionless.Web/ClientApp/src/lib/api/eventsApi.ts index 6a3b4b80ae..98d3088e87 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/api/eventsApi.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/api/eventsApi.ts @@ -2,6 +2,7 @@ import { createQuery, useQueryClient } from '@tanstack/svelte-query'; import type { PersistentEvent } from '$lib/models/api'; import { FetchClient, type ProblemDetails } from '$api/FetchClient'; import { derived, readable, type Readable } from 'svelte/store'; +import { accessToken } from '$api/auth'; export const queryKeys = { all: ['PersistentEvent'] as const, @@ -14,8 +15,8 @@ export const queryKeys = { export function getEventByIdQuery(id: string | Readable) { const readableId = typeof id === 'string' || id === null ? readable(id) : id; return createQuery( - derived(readableId, ($id) => ({ - enabled: !!$id, + derived([accessToken, readableId], ([$accessToken, $id]) => ({ + enabled: !!$accessToken && !!$id, queryKey: queryKeys.id($id), queryFn: async ({ signal }: { signal: AbortSignal }) => { const { getJSON } = new FetchClient(); @@ -37,8 +38,8 @@ export function getEventsByStackIdQuery(stackId: string | Readable( - derived(readableStackId, ($id) => ({ - enabled: !!$id, + derived([accessToken, readableStackId], ([$accessToken, $id]) => ({ + enabled: !!$accessToken && !!$id, queryClient, queryKey: queryKeys.stacks($id), queryFn: async ({ signal }: { signal: AbortSignal }) => { diff --git a/src/Exceptionless.Web/ClientApp/src/lib/api/organizationsApi.ts b/src/Exceptionless.Web/ClientApp/src/lib/api/organizationsApi.ts new file mode 100644 index 0000000000..77c02c2849 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/api/organizationsApi.ts @@ -0,0 +1,41 @@ +import { createQuery, useQueryClient } from '@tanstack/svelte-query'; +import type { ViewOrganization } from '$lib/models/api'; +import { FetchClient, type ProblemDetails } from '$api/FetchClient'; +import { derived } from 'svelte/store'; +import { accessToken } from '$api/auth'; + +export const queryKeys = { + all: ['Organization'] as const, + allWithMode: (mode: 'stats' | null) => [...queryKeys.all, { mode }] as const, + id: (id: string | null) => [...queryKeys.all, id] as const +}; + +export function getOrganizationQuery(mode: 'stats' | null = null) { + const queryClient = useQueryClient(); + return createQuery( + derived(accessToken, ($accessToken) => ({ + enabled: !!$accessToken, + queryClient, + queryKey: mode ? queryKeys.allWithMode(mode) : queryKeys.all, + queryFn: async ({ signal }: { signal: AbortSignal }) => { + const { getJSON } = new FetchClient(); + const response = await getJSON('organizations', { + signal, + params: { + mode + } + }); + + if (response.ok) { + response.data?.forEach((organization) => { + queryClient.setQueryData(queryKeys.id(organization.id!), organization); + }); + + return response.data!; + } + + throw response.problem; + } + })) + ); +} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/api/projectsApi.ts b/src/Exceptionless.Web/ClientApp/src/lib/api/projectsApi.ts index fa951ea381..09dd8fed12 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/api/projectsApi.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/api/projectsApi.ts @@ -2,18 +2,21 @@ import { createMutation, createQuery, useQueryClient } from '@tanstack/svelte-qu import { derived, readable, type Readable } from 'svelte/store'; import type { ViewProject } from '$lib/models/api'; import { FetchClient, type FetchClientResponse, type ProblemDetails } from '$api/FetchClient'; +import { accessToken } from '$api/auth'; export const queryKeys = { all: ['Project'] as const, allWithFilters: (filters: string) => [...queryKeys.all, { filters }] as const, + organization: (id: string | null) => [...queryKeys.all, 'organization', id] as const, + organizationWithFilters: (id: string | null, filters: string) => [...queryKeys.organization(id), { filters }] as const, id: (id: string | null) => [...queryKeys.all, id] as const }; export function getProjectByIdQuery(id: string | Readable) { const readableId = typeof id === 'string' || id === null ? readable(id) : id; return createQuery( - derived(readableId, ($id) => ({ - enabled: !!$id, + derived([accessToken, readableId], ([$accessToken, $id]) => ({ + enabled: !!$accessToken && !!$id, queryKey: queryKeys.id($id), queryFn: async ({ signal }: { signal: AbortSignal }) => { const { getJSON } = new FetchClient(); @@ -31,14 +34,45 @@ export function getProjectByIdQuery(id: string | Readable) { ); } +export function getProjectsByOrganizationIdQuery(organizationId: string | Readable, limit: number = 1000) { + const queryClient = useQueryClient(); + const readableOrganizationId = typeof organizationId === 'string' || organizationId === null ? readable(organizationId) : organizationId; + return createQuery( + derived([accessToken, readableOrganizationId], ([$accessToken, $id]) => ({ + enabled: !!$accessToken && !!$id, + queryClient, + queryKey: queryKeys.organization($id), + queryFn: async ({ signal }: { signal: AbortSignal }) => { + const { getJSON } = new FetchClient(); + const response = await getJSON(`organizations/${$id}/projects`, { + signal, + params: { + limit + } + }); + + if (response.ok) { + response.data?.forEach((project) => { + queryClient.setQueryData(queryKeys.id(project.id!), project); + }); + + return response.data!; + } + + throw response.problem; + } + })) + ); +} + export function mutatePromoteTab(id: string) { const client = useQueryClient(); return createMutation, ProblemDetails, { name: string }>({ mutationKey: queryKeys.id(id), - mutationFn: async ({ name }) => { + mutationFn: async (params: { name: string }) => { const { post } = new FetchClient(); const response = await post(`projects/${id}/promotedtabs`, undefined, { - params: { name } + params }); if (response.ok) { diff --git a/src/Exceptionless.Web/ClientApp/src/lib/api/stacksApi.ts b/src/Exceptionless.Web/ClientApp/src/lib/api/stacksApi.ts index 98460fc181..7598eded42 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/api/stacksApi.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/api/stacksApi.ts @@ -1,7 +1,8 @@ import { createQuery, useQueryClient } from '@tanstack/svelte-query'; +import { derived, get, readable, type Readable } from 'svelte/store'; import type { Stack } from '$lib/models/api'; import { FetchClient, type ProblemDetails } from '$api/FetchClient'; -import { derived, readable, type Readable } from 'svelte/store'; +import { accessToken } from '$api/auth'; export const queryKeys = { all: ['Stack'] as const, @@ -10,6 +11,10 @@ export const queryKeys = { }; export async function prefetchStack(id: string) { + if (!get(accessToken)) { + return; + } + const queryClient = useQueryClient(); await queryClient.prefetchQuery({ queryKey: queryKeys.id(id), @@ -31,8 +36,8 @@ export async function prefetchStack(id: string) { export function getStackByIdQuery(id: string | Readable) { const readableId = typeof id === 'string' || id === null ? readable(id) : id; return createQuery( - derived(readableId, ($id) => ({ - enabled: !!$id, + derived([accessToken, readableId], ([$accessToken, $id]) => ({ + enabled: !!$accessToken && !!$id, queryKey: queryKeys.id($id), queryFn: async ({ signal }: { signal: AbortSignal }) => { const { getJSON } = new FetchClient(); diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-faceted-filter-container.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-faceted-filter-container.svelte deleted file mode 100644 index 776a384758..0000000000 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-faceted-filter-container.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - - - -{#if $showReset} - -{/if} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-faceted-filter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-faceted-filter.svelte deleted file mode 100644 index aab29dc734..0000000000 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-faceted-filter.svelte +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - No results found. - - {#each options as option (option.value)} - -
- -
- - {option.label} - -
- {/each} -
- {#if values.length > 0} - - Clear filters - {/if} -
-
-
-
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-page-size.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-page-size.svelte index fb166787a1..44c50d142d 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-page-size.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-page-size.svelte @@ -35,7 +35,7 @@

Rows per page

- + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-toolbar.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-toolbar.svelte index de6733ca8c..ac9cbfc2f3 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-toolbar.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/data-table-toolbar.svelte @@ -8,12 +8,11 @@ export let table: Readable>; -
-
+
+
-
- -
- +
+ +
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/index.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/index.ts index 33caf4941c..c907a941d5 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/index.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/data-table/index.ts @@ -1,8 +1,6 @@ import Root from './data-table.svelte'; import Body from './data-table-body.svelte'; import Toolbar from './data-table-toolbar.svelte'; -import FacetedFilterContainer from './data-table-faceted-filter-container.svelte'; -import FacetedFilter from './data-table-faceted-filter.svelte'; import PageSize from './data-table-page-size.svelte'; import Pagination from './data-table-pagination.svelte'; @@ -10,16 +8,12 @@ export { Root, Body, Toolbar, - FacetedFilterContainer, - FacetedFilter, PageSize, Pagination, // Root as DataTable, Body as DataTableBody, Toolbar as DataTableToolbar, - FacetedFilterContainer as DataTableFacetedFilterContainer, - FacetedFilter as DataTableFacetedFilter, PageSize as DataTablePageSize, Pagination as DataTablePagination }; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/events/EventsDrawer.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/events/EventsDrawer.svelte index 43de4fa582..d63628ae3c 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/events/EventsDrawer.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/events/EventsDrawer.svelte @@ -21,6 +21,7 @@ import * as Table from '$comp/ui/table'; import * as Tabs from '$comp/ui/tabs'; import P from '$comp/typography/P.svelte'; + import ClickableProjectFilter from '$comp/filters/ClickableProjectFilter.svelte'; export let id: string; @@ -136,7 +137,9 @@ Project {$projectResponse.data.name}{$projectResponse.data.name} {/if} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsDataTable.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsDataTable.svelte index 52d9e8c1a9..cac5f2d721 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsDataTable.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsDataTable.svelte @@ -10,11 +10,10 @@ import * as DataTable from '$comp/data-table'; import { getOptions } from './options'; import { DEFAULT_LIMIT } from '$lib/helpers/api'; - import SearchInput from '$comp/SearchInput.svelte'; - import { limit, onFilterInputChanged } from '$lib/stores/events'; export let filter: Readable; export let pageFilter: string | undefined = undefined; + export let limit: Readable; export let time: Readable; export let mode: GetEventsMode = 'summary'; @@ -63,9 +62,7 @@ - - - + dispatch('rowclick', event.detail)}> diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsTailLogDataTable.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsTailLogDataTable.svelte index 30f925bfb4..3df27ca97d 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsTailLogDataTable.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/EventsTailLogDataTable.svelte @@ -11,11 +11,10 @@ import CustomEventMessage from '$comp/messaging/CustomEventMessage.svelte'; import Muted from '$comp/typography/Muted.svelte'; import { getOptions } from './options'; - import SearchInput from '$comp/SearchInput.svelte'; - import { limit, onFilterInputChanged } from '$lib/stores/events'; import { DEFAULT_LIMIT } from '$lib/helpers/api'; export let filter: Readable; + export let limit: Readable; const parameters = writable({ mode: 'summary', limit: $limit }); const options = getOptions>(parameters, (options) => ({ @@ -93,9 +92,7 @@ - - - + dispatch('rowclick', event.detail)}> diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/options.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/options.ts index d4fbea9a13..07021c5815 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/options.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/events/table/options.ts @@ -9,7 +9,7 @@ import { renderComponent, type RowSelectionState } from '@tanstack/svelte-table'; -import { persisted } from 'svelte-local-storage-store'; +import { persisted } from 'svelte-persisted-store'; import { get, writable, type Writable } from 'svelte/store'; import type { EventSummaryModel, GetEventsMode, IGetEventsParams, StackSummaryModel, SummaryModel, SummaryTemplateKeys } from '$lib/models/api'; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/events/views/Overview.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/events/views/Overview.svelte index 342a9f81ad..9241cba105 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/events/views/Overview.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/events/views/Overview.svelte @@ -27,6 +27,7 @@ import { Button } from '$comp/ui/button'; import H4 from '$comp/typography/H4.svelte'; import A from '$comp/typography/A.svelte'; + import ClickableTypeFilter from '$comp/filters/ClickableTypeFilter.svelte'; export let event: PersistentEvent; @@ -97,9 +98,9 @@ Reference {#if isSessionStart} - {event.reference_id} + {event.reference_id} {:else} - {event.reference_id} + {event.reference_id} {/if} @@ -107,7 +108,7 @@ {#each references as reference (reference.id)} {reference.name} - {reference.id} + {reference.id} {/each} {#if level} @@ -119,7 +120,7 @@ {#if event.type !== 'error'} Event Type - {event.type} + {event.type} {/if} {#if hasError} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-actions.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-actions.svelte new file mode 100644 index 0000000000..9089a5fecd --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-actions.svelte @@ -0,0 +1,24 @@ + + + + + + {#if showApply} + dispatch('apply')}>Apply filter + + {/if} + {#if showClear} + dispatch('clear')}>Clear filter + {/if} + dispatch('remove')}>Remove filter + dispatch('close')}>Close + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-loading.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-loading.svelte new file mode 100644 index 0000000000..2e2593e786 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-loading.svelte @@ -0,0 +1,8 @@ + + + + Loading + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-value.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-value.svelte new file mode 100644 index 0000000000..9c2fda156a --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-value.svelte @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-values.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-values.svelte new file mode 100644 index 0000000000..7b970274ea --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-badge-values.svelte @@ -0,0 +1,24 @@ + + +{#if values.length > 0} + + {values.length} + + +{/if} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-builder.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-builder.svelte new file mode 100644 index 0000000000..04102b3748 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-builder.svelte @@ -0,0 +1,105 @@ + + + + + + + + + + + No results found. + + {#each $facets as facet (facet.filter.key)} + onFacetSelected(facet)}>{facet.title} + {/each} + + + + + + + {#if visible.length > 0} + Clear filters + {/if} + Close + + + + + +{#each $facets as facet (facet.filter.key)} + {#if visible.includes(facet.filter.key)} + + {/if} +{/each} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/index.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/index.ts new file mode 100644 index 0000000000..cf0cfba87b --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/index.ts @@ -0,0 +1,27 @@ +import type { ComponentType } from 'svelte'; +import type { Writable } from 'svelte/store'; + +import type { IFilter } from '$comp/filters/filters'; + +import Root from './faceted-filter-builder.svelte'; +import Actions from './faceted-filter-actions.svelte'; + +import BadgeLoading from './faceted-filter-badge-loading.svelte'; +import BadgeValue from './faceted-filter-badge-value.svelte'; +import BadgeValues from './faceted-filter-badge-values.svelte'; + +export type FacetedFilter = { title: string; component: ComponentType; filter: IFilter; open: Writable }; + +export { + Root, + Actions, + BadgeLoading, + BadgeValue, + BadgeValues, + // + Root as FacetedFilterBuilder, + Actions as FacetedFilterActions, + BadgeLoading as FacetedFilterBadgeLoading, + BadgeValue as FacetedFilterBadgeValue, + BadgeValues as FacetedFilterBadgeValues +}; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableOrganizationFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableOrganizationFilter.svelte new file mode 100644 index 0000000000..0d2c9d0408 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableOrganizationFilter.svelte @@ -0,0 +1,21 @@ + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableProjectFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableProjectFilter.svelte new file mode 100644 index 0000000000..81df1b0fc5 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableProjectFilter.svelte @@ -0,0 +1,22 @@ + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableReferenceFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableReferenceFilter.svelte index ae14db186d..682da0c18d 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableReferenceFilter.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableReferenceFilter.svelte @@ -2,15 +2,15 @@ import A from '$comp/typography/A.svelte'; import { ReferenceFilter } from './filters'; - export let referenceId: string; + export let value: string; - const title = `Search reference:${referenceId}`; + const title = `Search reference:${value}`; function onSearchClick(e: Event) { e.preventDefault(); document.dispatchEvent( new CustomEvent('filter', { - detail: new ReferenceFilter(referenceId) + detail: new ReferenceFilter(value) }) ); } diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableSessionFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableSessionFilter.svelte index debfa8e89a..53b9d0c25b 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableSessionFilter.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableSessionFilter.svelte @@ -2,15 +2,15 @@ import A from '$comp/typography/A.svelte'; import { SessionFilter } from './filters'; - export let sessionId: string; + export let value: string; - const title = `Search ref.session:${sessionId}`; + const title = `Search ref.session:${value}`; function onSearchClick(e: Event) { e.preventDefault(); document.dispatchEvent( new CustomEvent('filter', { - detail: new SessionFilter(sessionId) + detail: new SessionFilter(value) }) ); } diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableStatusFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableStatusFilter.svelte new file mode 100644 index 0000000000..91ac4dc3b5 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableStatusFilter.svelte @@ -0,0 +1,22 @@ + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableTypeFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableTypeFilter.svelte new file mode 100644 index 0000000000..fd4ed8843d --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/ClickableTypeFilter.svelte @@ -0,0 +1,21 @@ + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/BooleanFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/BooleanFacetedFilter.svelte new file mode 100644 index 0000000000..555821c2bd --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/BooleanFacetedFilter.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/DateFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/DateFacetedFilter.svelte new file mode 100644 index 0000000000..abf6196e8d --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/DateFacetedFilter.svelte @@ -0,0 +1,49 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/KeywordFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/KeywordFacetedFilter.svelte new file mode 100644 index 0000000000..688e6a7f43 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/KeywordFacetedFilter.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/NumberFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/NumberFacetedFilter.svelte new file mode 100644 index 0000000000..757043c16d --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/NumberFacetedFilter.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/OrganizationFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/OrganizationFacetedFilter.svelte new file mode 100644 index 0000000000..6d70d09b2f --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/OrganizationFacetedFilter.svelte @@ -0,0 +1,54 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/ProjectFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/ProjectFacetedFilter.svelte new file mode 100644 index 0000000000..839fc1b544 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/ProjectFacetedFilter.svelte @@ -0,0 +1,57 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/ReferenceFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/ReferenceFacetedFilter.svelte new file mode 100644 index 0000000000..2dcfa24813 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/ReferenceFacetedFilter.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/SessionFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/SessionFacetedFilter.svelte new file mode 100644 index 0000000000..dbeef15b99 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/SessionFacetedFilter.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/StatusFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/StatusFacetedFilter.svelte new file mode 100644 index 0000000000..4b12f0f169 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/StatusFacetedFilter.svelte @@ -0,0 +1,24 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/StringFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/StringFacetedFilter.svelte new file mode 100644 index 0000000000..5f1a2b89dd --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/StringFacetedFilter.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/TypeFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/TypeFacetedFilter.svelte new file mode 100644 index 0000000000..d50579465f --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/TypeFacetedFilter.svelte @@ -0,0 +1,23 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/VersionFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/VersionFacetedFilter.svelte new file mode 100644 index 0000000000..6ea571f503 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/VersionFacetedFilter.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/BooleanFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/BooleanFacetedFilter.svelte new file mode 100644 index 0000000000..b52fb4c0a9 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/BooleanFacetedFilter.svelte @@ -0,0 +1,66 @@ + + + + + + + +
+ +
+ open.set(false)} + > +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/DropDownFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/DropDownFacetedFilter.svelte new file mode 100644 index 0000000000..4a0b648ddc --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/DropDownFacetedFilter.svelte @@ -0,0 +1,130 @@ + + + + + + + + + {#if options.length > 10} + + {/if} + + {#if loading} +
Loading...
+ {/if} + {noOptionsText} + {#if options.length > 0} + + {#each options as option (option.value)} + onValueSelected(option.value)}> +
+ +
+ + {option.label} + +
+ {/each} +
{/if} +
+
+ open.set(false)} + > +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/KeywordFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/KeywordFacetedFilter.svelte new file mode 100644 index 0000000000..c3d57087f7 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/KeywordFacetedFilter.svelte @@ -0,0 +1,66 @@ + + + + + + + +
+ +
+ open.set(false)} + > +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/MultiselectFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/MultiselectFacetedFilter.svelte new file mode 100644 index 0000000000..0f27688e7f --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/MultiselectFacetedFilter.svelte @@ -0,0 +1,137 @@ + + + + + + + + + {#if options.length > 10} + + {/if} + + {#if loading} +
Loading...
+ {/if} + {noOptionsText} + {#if options.length > 0} + + {#each options as option (option.value)} + onValueSelected(option.value)}> +
+ +
+ + {option.label} + +
+ {/each} +
+ {/if} +
+
+ 0} + on:clear={onClearFilter} + on:remove={onRemoveFilter} + on:close={() => open.set(false)} + > +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/NumberFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/NumberFacetedFilter.svelte new file mode 100644 index 0000000000..4e0f8106d7 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/NumberFacetedFilter.svelte @@ -0,0 +1,66 @@ + + + + + + + +
+ +
+ open.set(false)} + > +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/StringFacetedFilter.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/StringFacetedFilter.svelte new file mode 100644 index 0000000000..9f4cf83c5f --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/base/StringFacetedFilter.svelte @@ -0,0 +1,66 @@ + + + + + + + +
+ +
+ open.set(false)} + > +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/index.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/index.ts new file mode 100644 index 0000000000..98579dc24a --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/index.ts @@ -0,0 +1,68 @@ +import type { FacetedFilter } from '$comp/faceted-filter'; +import { writable } from 'svelte/store'; +import { type BooleanFilter, type DateFilter, type IFilter, type NumberFilter, type StringFilter, type VersionFilter } from '../filters'; + +import BooleanFacetedFilter from './BooleanFacetedFilter.svelte'; +import DateFacetedFilter from './DateFacetedFilter.svelte'; +import KeywordFacetedFilter from './KeywordFacetedFilter.svelte'; +import NumberFacetedFilter from './NumberFacetedFilter.svelte'; +import OrganizationFacetedFilter from './OrganizationFacetedFilter.svelte'; +import ProjectFacetedFilter from './ProjectFacetedFilter.svelte'; +import ReferenceFacetedFilter from './ReferenceFacetedFilter.svelte'; +import SessionFacetedFilter from './SessionFacetedFilter.svelte'; +import StatusFacetedFilter from './StatusFacetedFilter.svelte'; +import StringFacetedFilter from './StringFacetedFilter.svelte'; +import TypeFacetedFilter from './TypeFacetedFilter.svelte'; +import VersionFacetedFilter from './VersionFacetedFilter.svelte'; + +export function toFacetedFilters(filters: IFilter[]): FacetedFilter[] { + return filters.map((filter) => { + switch (filter.type) { + case 'boolean': { + const booleanFilter = filter as BooleanFilter; + return { title: (booleanFilter.term as string) ?? 'Boolean', component: BooleanFacetedFilter, filter, open: writable(false) }; + } + case 'date': { + const dateFilter = filter as DateFilter; + const title = dateFilter.term === 'date' ? 'Date Range' : dateFilter.term ?? 'Date'; + return { title, component: DateFacetedFilter, filter, open: writable(false) }; + } + case 'keyword': { + return { title: 'Keyword', component: KeywordFacetedFilter, filter, open: writable(false) }; + } + case 'number': { + const numberFilter = filter as NumberFilter; + return { title: (numberFilter.term as string) ?? 'Number', component: NumberFacetedFilter, filter: numberFilter, open: writable(false) }; + } + case 'organization': { + return { title: 'Organization', component: OrganizationFacetedFilter, filter, open: writable(false) }; + } + case 'project': { + return { title: 'Project', component: ProjectFacetedFilter, filter, open: writable(false) }; + } + case 'reference': { + return { title: 'Reference', component: ReferenceFacetedFilter, filter, open: writable(false) }; + } + case 'session': { + return { title: 'Session', component: SessionFacetedFilter, filter, open: writable(false) }; + } + case 'status': { + return { title: 'Status', component: StatusFacetedFilter, filter, open: writable(false) }; + } + case 'string': { + const stringFilter = filter as StringFilter; + return { title: (stringFilter.term as string) ?? 'String', component: StringFacetedFilter, filter, open: writable(false) }; + } + case 'type': { + return { title: 'Type', component: TypeFacetedFilter, filter, open: writable(false) }; + } + case 'version': { + const versionFilter = filter as VersionFilter; + return { title: (versionFilter.term as string) ?? 'Version', component: VersionFacetedFilter, filter, open: writable(false) }; + } + default: { + throw new Error(`Unknown filter type: ${filter.type}`); + } + } + }); +} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/filters.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/filters.ts index 72716bc26e..bc52cc6986 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/filters/filters.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/filters/filters.ts @@ -1,27 +1,41 @@ import type { PersistentEventKnownTypes } from '$lib/models/api'; import type { StackStatus } from '$lib/models/api'; -import type { Serializer } from 'svelte-local-storage-store'; +import type { Serializer } from 'svelte-persisted-store'; +import { get, type Writable } from 'svelte/store'; export interface IFilter { readonly type: string; + readonly key: string; + isEmpty(): boolean; + reset(): void; toFilter(): string; } -export interface IFacetedFilter extends IFilter { - term: string; - values: unknown[]; - faceted: boolean; -} - export class BooleanFilter implements IFilter { constructor( - public term: string, + public term?: string, public value?: boolean ) {} public type: string = 'boolean'; + public get key(): string { + return `${this.type}:${this.term}`; + } + + public isEmpty(): boolean { + return this.value === undefined; + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { + if (this.term === undefined) { + return ''; + } + if (this.value === undefined) { return `_missing_:${this.term}`; } @@ -32,13 +46,29 @@ export class BooleanFilter implements IFilter { export class DateFilter implements IFilter { constructor( - public term: string, + public term?: string, public value?: Date | string ) {} public type: string = 'date'; + public get key(): string { + return `${this.type}:${this.term}`; + } + + public isEmpty(): boolean { + return this.value === undefined; + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { + if (this.term === undefined) { + return ''; + } + if (this.value === undefined) { return `_missing_:${this.term}`; } @@ -49,24 +79,56 @@ export class DateFilter implements IFilter { } export class KeywordFilter implements IFilter { - constructor(public keyword: string) {} + constructor(public value?: string) {} public type: string = 'keyword'; + public get key(): string { + return this.type; + } + + public isEmpty(): boolean { + return !this.value?.trim(); + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { - return this.keyword; + if (this.isEmpty()) { + return ''; + } + + return this.value!.trim(); } } export class NumberFilter implements IFilter { constructor( - public term: string, + public term?: string, public value?: number ) {} public type: string = 'number'; + public get key(): string { + return `${this.type}:${this.term}`; + } + + public isEmpty(): boolean { + return this.value === undefined; + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { + if (this.term === undefined) { + return ''; + } + if (this.value === undefined) { return `_missing_:${this.term}`; } @@ -75,56 +137,173 @@ export class NumberFilter implements IFilter { } } +export class OrganizationFilter implements IFilter { + constructor(public value?: string) {} + + public type: string = 'organization'; + + public get key(): string { + return this.type; + } + + public isEmpty(): boolean { + return !this.value?.trim(); + } + + public reset(): void { + this.value = undefined; + } + + public toFilter(): string { + if (this.isEmpty()) { + return ''; + } + + return `organization:${this.value}`; + } +} + +export class ProjectFilter implements IFilter { + constructor( + public organization: string | undefined, + public value: string[] + ) {} + + public type: string = 'project'; + + public get key(): string { + return this.type; + } + + public isEmpty(): boolean { + return this.value.length === 0; + } + + public reset(): void { + this.value = []; + } + + public toFilter(): string { + if (this.value.length == 0) { + return ''; + } + + if (this.value.length == 1) { + return `project:${this.value[0]}`; + } + + return `(${this.value.map((val) => `project:${val}`).join(' OR ')})`; + } +} + export class ReferenceFilter implements IFilter { - constructor(public referenceId: string) {} + constructor(public value?: string) {} public type: string = 'reference'; + public get key(): string { + return this.type; + } + + public isEmpty(): boolean { + return !this.value?.trim(); + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { - return `reference:${quoteIfSpecialCharacters(this.referenceId)}`; + if (this.isEmpty()) { + return ''; + } + + return `reference:${quoteIfSpecialCharacters(this.value)}`; } } export class SessionFilter implements IFilter { - constructor(public sessionId: string) {} + constructor(public value?: string) {} public type: string = 'session'; + public get key(): string { + return this.type; + } + + public isEmpty(): boolean { + return !this.value?.trim(); + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { - const session = quoteIfSpecialCharacters(this.sessionId); + if (this.isEmpty()) { + return ''; + } + + const session = quoteIfSpecialCharacters(this.value); return `(reference:${session} OR ref.session:${session})`; } } -export class StatusFilter implements IFacetedFilter { - constructor(public values: StackStatus[]) {} +export class StatusFilter implements IFilter { + constructor(public value: StackStatus[]) {} - public term: string = 'status'; public type: string = 'status'; - public faceted: boolean = true; + + public get key(): string { + return this.type; + } + + public isEmpty(): boolean { + return this.value.length === 0; + } + + public reset(): void { + this.value = []; + } public toFilter(): string { - if (this.values.length == 0) { + if (this.value.length == 0) { return ''; } - if (this.values.length == 1) { - return `${this.term}:${this.values[0]}`; + if (this.value.length == 1) { + return `status:${this.value[0]}`; } - return `(${this.values.map((val) => `${this.term}:${val}`).join(' OR ')})`; + return `(${this.value.map((val) => `status:${val}`).join(' OR ')})`; } } export class StringFilter implements IFilter { constructor( - public term: string, - public value?: string | null + public term?: string, + public value?: string ) {} public type: string = 'string'; + public get key(): string { + return `${this.type}:${this.term}`; + } + + public isEmpty(): boolean { + return this.value === undefined; + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { + if (this.term === undefined) { + return ''; + } + if (this.value === undefined) { return `_missing_:${this.term}`; } @@ -133,35 +312,61 @@ export class StringFilter implements IFilter { } } -export class TypeFilter implements IFacetedFilter { - constructor(public values: PersistentEventKnownTypes[]) {} +export class TypeFilter implements IFilter { + constructor(public value: PersistentEventKnownTypes[]) {} - public term: string = 'type'; public type: string = 'type'; - public faceted: boolean = true; + + public get key(): string { + return this.type; + } + + public isEmpty(): boolean { + return this.value.length === 0; + } + + public reset(): void { + this.value = []; + } public toFilter(): string { - if (this.values.length == 0) { + if (this.value.length == 0) { return ''; } - if (this.values.length == 1) { - return `${this.term}:${this.values[0]}`; + if (this.value.length == 1) { + return `type:${this.value[0]}`; } - return `(${this.values.map((val) => `${this.term}:${val}`).join(' OR ')})`; + return `(${this.value.map((val) => `type:${val}`).join(' OR ')})`; } } export class VersionFilter implements IFilter { constructor( - public term: string, + public term?: string, public value?: string ) {} public type: string = 'version'; + public get key(): string { + return `${this.type}:${this.term}`; + } + + public isEmpty(): boolean { + return this.value === undefined; + } + + public reset(): void { + this.value = undefined; + } + public toFilter(): string { + if (this.term === undefined) { + return ''; + } + if (this.value === undefined) { return `_missing_:${this.term}`; } @@ -185,154 +390,59 @@ export function quote(value?: string | null): string | undefined { return value ? `"${value}"` : undefined; } -export function toFilter(filters: IFilter[], includeFaceted: boolean = false): string { +export function toFilter(filters: IFilter[]): string { return filters - .filter((f) => includeFaceted || !isFaceted(f)) .map((f) => f.toFilter()) + .filter(Boolean) .join(' ') .trim(); } -/** - * Update the filters with the given filter. If the filter already exists, it will be removed. - * @param filters The filters - * @param filter The filter to add or remove - * @returns The updated filters - */ -export function toggleFilter(filters: IFilter[], filter: IFilter): IFilter[] { - const index = filters.findIndex((f) => (f.type === filter.type && isFaceted(f) && isFaceted(filter)) || f.toFilter() === filter.toFilter()); - - if (index >= 0) { - filters.splice(index, 1); - } else { - filters.push(filter); - } - - return filters; -} - -/** - * Adds or updates a given faceted filter if it has values, otherwise it will be removed - * @param filters The filters - * @param filter The filter to add, update or remove. - * @returns true if filters has been modified - */ -export function upsertOrRemoveFacetFilter(filters: IFilter[], filter: IFacetedFilter): boolean { - const index = filters.findIndex((f) => f.type === filter.type && isFaceted(f)); - - // If the filter has no values, remove it. - if (!filter.values || filter.values.length == 0) { - if (index >= 0) { - filters.splice(index, 1); - return true; - } - - return false; - } - - if (index >= 0) { - if (filter.toFilter() === filters[index].toFilter()) { - return false; - } - - filters[index] = filter; - } else { - filters.push(filter); - } - - return true; -} - -/** - * Given the existing filters try and parse out any existing filters while adding new user filters as a keyword filter. - * @param filters The current filters - * @param filter The current filter string that was modified by the user - * @returns The updated filter - */ -export function parseFilter(filters: IFilter[], input: string): IFilter[] { - const resolvedFilters: IFilter[] = []; - - const keywordFilterParts = []; - for (const filter of filters) { - if (isFaceted(filter)) { - resolvedFilters.push(filter); - continue; - } - - input = input?.trim(); - if (!input) { - continue; - } - - // NOTE: This is a super naive implementation... - const part = filter.toFilter(); - if (part) { - // Check for whole word / phrase match - const regex = new RegExp(`(^|\\s)${part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\s|$)`); - if (regex.test(input)) { - input = input.replace(regex, ''); - if (filter instanceof KeywordFilter) { - keywordFilterParts.push(part); - } else { - resolvedFilters.push(filter); - } - } - } - } - - input = `${keywordFilterParts.join(' ')} ${input ?? ''}`.trim(); - if (input) { - resolvedFilters.push(new KeywordFilter(input)); - } - - return resolvedFilters; -} - -export function getFilter(filter: Record): IFilter | undefined { +export function getFilter(filter: Omit & Record): IFilter | undefined { switch (filter.type) { case 'boolean': return new BooleanFilter(filter.term as string, filter.value as boolean); case 'date': return new DateFilter(filter.term as string, filter.value as Date); case 'keyword': - return new KeywordFilter(filter.keyword as string); + return new KeywordFilter(filter.value as string); case 'number': return new NumberFilter(filter.term as string, filter.value as number); + case 'organization': + return new OrganizationFilter(filter.value as string); + case 'project': + return new ProjectFilter(filter.organization as string, filter.value as string[]); case 'reference': - return new ReferenceFilter(filter.referenceId as string); + return new ReferenceFilter(filter.value as string); case 'session': - return new SessionFilter(filter.sessionId as string); + return new SessionFilter(filter.value as string); case 'status': - return new StatusFilter(filter.values as StackStatus[]); + return new StatusFilter(filter.value as StackStatus[]); case 'string': return new StringFilter(filter.term as string, filter.value as string); case 'type': - return new TypeFilter(filter.values as PersistentEventKnownTypes[]); + return new TypeFilter(filter.value as PersistentEventKnownTypes[]); case 'version': return new VersionFilter(filter.term as string, filter.value as string); + default: + throw new Error(`Unknown filter type: ${filter.type}`); } } -function isFaceted(filter: IFilter): filter is IFacetedFilter { - return 'faceted' in filter; -} - -const FACETED_FILTER_TYPES = ['status', 'type']; -export function toFacetedValues(filters: IFilter[]): Record { - const values: Record = {}; - for (const filterType of FACETED_FILTER_TYPES) { - const filter = filters.find((f) => f.type === filterType && isFaceted(f)) as IFacetedFilter | undefined; - values[filterType] = filter?.values ?? []; - } - - return values; -} - -export function resetFacetedValues(filters: IFilter[]): IFilter[] { - for (const filter of filters) { - if (isFaceted(filter)) { - upsertOrRemoveFacetFilter(filters, { ...filter, values: [] }); +export function setFilter(filters: IFilter[], filter: IFilter): IFilter[] { + const existingFilter = filters.find((f) => f.key === filter.key && ('term' in f && 'term' in filter ? f.term === filter.term : true)); + if (existingFilter) { + if ('value' in existingFilter && 'value' in filter) { + if (Array.isArray(existingFilter.value) && Array.isArray(filter.value)) { + existingFilter.value = [...new Set([...existingFilter.value, ...filter.value])]; + } else { + existingFilter.value = filter.value; + } + } else { + Object.assign(existingFilter, filter); } + } else { + filters.push(filter); } return filters; @@ -347,7 +457,7 @@ export class FilterSerializer implements Serializer { const data: unknown[] = JSON.parse(text); const filters: IFilter[] = []; for (const filterData of data) { - const filter = getFilter(filterData as Record); + const filter = getFilter(filterData as Omit); if (filter) { filters.push(filter); } @@ -360,3 +470,71 @@ export class FilterSerializer implements Serializer { return JSON.stringify(object); } } + +export function getDefaultFilters(includeDateFilter = true): IFilter[] { + return [ + new OrganizationFilter(), + new ProjectFilter(undefined, []), + new StatusFilter([]), + new TypeFilter([]), + new DateFilter('date', 'last week'), + new ReferenceFilter(), + new SessionFilter(), + new KeywordFilter() + ].filter((f) => includeDateFilter || f.type !== 'date'); +} + +export function filterChanged(filters: Writable, updated: IFilter): void { + filters.set(processFilterRules(setFilter(get(filters), updated), updated)); +} + +export function filterRemoved(filters: Writable, defaultFilters: IFilter[], removed?: IFilter): void { + // If detail is undefined, remove all filters. + if (!removed) { + filters.set(defaultFilters); + } else if (defaultFilters.find((f) => f.key === removed.key)) { + filters.set(processFilterRules(setFilter(get(filters), removed), removed)); + } else { + filters.set( + processFilterRules( + get(filters).filter((f) => f.key !== removed.key), + removed + ) + ); + } +} + +export function processFilterRules(filters: IFilter[], changed?: IFilter): IFilter[] { + // Allow only one filter per type and term. + const groupedFilters: Partial> = Object.groupBy(filters, (f: IFilter) => f.key); + const filtered: IFilter[] = []; + Object.entries(groupedFilters).forEach(([, items]) => { + if (items && items.length > 0) { + filtered.push(items[0]); + } + }); + + const projectFilter = filtered.find((f) => f.type === 'project') as ProjectFilter; + if (projectFilter) { + let organizationFilter = filtered.find((f) => f.type === 'organization') as OrganizationFilter; + + // If there is a project filter, verify the organization filter is set + if (!organizationFilter) { + organizationFilter = new OrganizationFilter(projectFilter.organization); + filtered.push(organizationFilter); + } + + // If the organization filter changes and organization is not set on the project filter, clear the project filter + if (changed?.type === 'organization' && projectFilter.organization !== organizationFilter.value) { + projectFilter.organization = organizationFilter.value; + projectFilter.value = []; + } + + // If the project filter changes and the organization filter is not set, set it + if (organizationFilter.value !== projectFilter.organization) { + organizationFilter.value = projectFilter.organization; + } + } + + return filtered; +} diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/avatar/avatar-fallback.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/avatar/avatar-fallback.svelte index 76c244f0cf..b2f87391bd 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/avatar/avatar-fallback.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/avatar/avatar-fallback.svelte @@ -1,6 +1,6 @@ - + import { Command as CommandPrimitive } from 'cmdk-sv'; - import { cn } from '$lib/utils'; + import { cn } from '$lib/utils.js'; type $$Props = CommandPrimitive.EmptyProps; let className: string | undefined | null = undefined; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-group.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-group.svelte index b286709bc9..1ec78d4c41 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-group.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-group.svelte @@ -1,6 +1,6 @@
- + import { Command as CommandPrimitive } from 'cmdk-sv'; - import { cn } from '$lib/utils'; + import { cn } from '$lib/utils.js'; type $$Props = CommandPrimitive.ItemProps; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-list.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-list.svelte index 42732c8ecd..82ba18b33c 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-list.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/command/command-list.svelte @@ -1,6 +1,6 @@ + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-description.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-description.svelte new file mode 100644 index 0000000000..bad00a1251 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-description.svelte @@ -0,0 +1,12 @@ + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-element-field.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-element-field.svelte new file mode 100644 index 0000000000..270f011870 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-element-field.svelte @@ -0,0 +1,25 @@ + + + + + +
+ +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-field-errors.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-field-errors.svelte new file mode 100644 index 0000000000..cb19b63805 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-field-errors.svelte @@ -0,0 +1,20 @@ + + + + + {#each errors as error} +
{error}
+ {/each} +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-field.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-field.svelte new file mode 100644 index 0000000000..6f6f50ed71 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-field.svelte @@ -0,0 +1,25 @@ + + + + + +
+ +
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-fieldset.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-fieldset.svelte new file mode 100644 index 0000000000..3fbd692e17 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-fieldset.svelte @@ -0,0 +1,22 @@ + + + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-label.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-label.svelte new file mode 100644 index 0000000000..4d19eedf2b --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-label.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-legend.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-legend.svelte new file mode 100644 index 0000000000..344692a2a3 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/form-legend.svelte @@ -0,0 +1,13 @@ + + + + + diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/index.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/index.ts new file mode 100644 index 0000000000..e550824d47 --- /dev/null +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/form/index.ts @@ -0,0 +1,33 @@ +import * as FormPrimitive from 'formsnap'; +import Description from './form-description.svelte'; +import Label from './form-label.svelte'; +import FieldErrors from './form-field-errors.svelte'; +import Field from './form-field.svelte'; +import Button from './form-button.svelte'; +import Fieldset from './form-fieldset.svelte'; +import Legend from './form-legend.svelte'; +import ElementField from './form-element-field.svelte'; + +const Control = FormPrimitive.Control; + +export { + Field, + Control, + Label, + FieldErrors, + Description, + Fieldset, + Legend, + ElementField, + Button, + // + Field as FormField, + Control as FormControl, + Description as FormDescription, + Label as FormLabel, + FieldErrors as FormFieldErrors, + Fieldset as FormFieldset, + Legend as FormLegend, + ElementField as FormElementField, + Button as FormButton +}; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/index.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/index.ts index 5722094fc9..11a6791f38 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/index.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/index.ts @@ -1,6 +1,6 @@ import Root from './input.svelte'; -type FormInputEvent = T & { +export type FormInputEvent = T & { currentTarget: EventTarget & HTMLInputElement; }; export type InputEvents = { diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/input.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/input.svelte index 182148bc52..4a0e9496f2 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/input.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/input/input.svelte @@ -1,7 +1,7 @@ import { Label as LabelPrimitive } from 'bits-ui'; - import { cn } from '$lib/utils'; + import { cn } from '$lib/utils.js'; type $$Props = LabelPrimitive.Props; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/index.ts b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/index.ts index 57c9d6d258..ab5acc49fb 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/index.ts +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/index.ts @@ -2,13 +2,16 @@ import { Popover as PopoverPrimitive } from 'bits-ui'; import Content from './popover-content.svelte'; const Root = PopoverPrimitive.Root; const Trigger = PopoverPrimitive.Trigger; +const Close = PopoverPrimitive.Close; export { Root, Content, Trigger, + Close, // Root as Popover, Content as PopoverContent, - Trigger as PopoverTrigger + Trigger as PopoverTrigger, + Close as PopoverClose }; diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/popover-content.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/popover-content.svelte index 5a0ff3ada8..f9f0a01951 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/popover-content.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/popover/popover-content.svelte @@ -1,6 +1,6 @@ @@ -32,7 +32,7 @@ - + Close diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/sheet/sheet-description.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/sheet/sheet-description.svelte index 1b977d638d..f2e7b90135 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/sheet/sheet-description.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/sheet/sheet-description.svelte @@ -1,6 +1,6 @@ -
+
diff --git a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/tabs/tabs-content.svelte b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/tabs/tabs-content.svelte index bb0f017161..a05d3057bb 100644 --- a/src/Exceptionless.Web/ClientApp/src/lib/components/ui/tabs/tabs-content.svelte +++ b/src/Exceptionless.Web/ClientApp/src/lib/components/ui/tabs/tabs-content.svelte @@ -1,6 +1,6 @@ @@ -36,30 +45,13 @@ Events - + - - - - - - - - - + - -
(selectedEventId = null)}> diff --git a/src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte b/src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte index 09dc3168b5..4377643175 100644 --- a/src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte +++ b/src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte @@ -1,17 +1,21 @@ @@ -31,11 +54,9 @@ Issues - + - - - + @@ -45,7 +66,9 @@ selectedStackId.set(null)}> - Event Details + Event Details diff --git a/src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte b/src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte index 800dbd7941..8f1f407352 100644 --- a/src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte +++ b/src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte @@ -1,17 +1,43 @@ @@ -19,14 +45,21 @@ Event Stream - + + + + + (selectedEventId = null)}> - Event Details + Event Details diff --git a/src/Exceptionless.Web/ClientApp/src/routes/(auth)/logout/+page.svelte b/src/Exceptionless.Web/ClientApp/src/routes/(auth)/logout/+page.svelte index 77ae799a97..fb81cfbae2 100644 --- a/src/Exceptionless.Web/ClientApp/src/routes/(auth)/logout/+page.svelte +++ b/src/Exceptionless.Web/ClientApp/src/routes/(auth)/logout/+page.svelte @@ -8,7 +8,7 @@ import H2 from '$comp/typography/H2.svelte'; $: if (!$isAuthenticated) { - goto('next/login', { replaceState: true }); + goto('/next/login', { replaceState: true }); } let problem = new ProblemDetails(); diff --git a/src/Exceptionless.Web/ClientApp/src/routes/routes.ts b/src/Exceptionless.Web/ClientApp/src/routes/routes.ts index cf22b77c87..170e853a2f 100644 --- a/src/Exceptionless.Web/ClientApp/src/routes/routes.ts +++ b/src/Exceptionless.Web/ClientApp/src/routes/routes.ts @@ -1,4 +1,5 @@ import type { User } from '$lib/models/api'; +import type { ComponentType } from 'svelte'; import { routes as appRoutes } from './(app)/routes'; import { routes as authRoutes } from './(auth)/routes'; @@ -11,7 +12,7 @@ export type NavigationItem = { group: string; title: string; href: string; - icon: ConstructorOfATypedSvelteComponent; + icon: ComponentType; show?: (context: NavigationItemContext) => boolean; }; diff --git a/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs b/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs index ed192a45f4..4f0eb6b013 100644 --- a/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs +++ b/src/Exceptionless.Web/Controllers/Base/ExceptionlessApiController.cs @@ -20,6 +20,7 @@ public abstract class ExceptionlessApiController : Controller protected const int DEFAULT_LIMIT = 10; protected const int MAXIMUM_LIMIT = 100; protected const int MAXIMUM_SKIP = 1000; + protected static readonly char[] TIME_PARTS = ['|']; protected TimeSpan GetOffset(string? offset) { @@ -35,9 +36,9 @@ protected TimeSpan GetOffset(string? offset) protected virtual TimeInfo GetTimeInfo(string? time, string? offset, DateTime? minimumUtcStartDate = null) { string field = DefaultDateField; - if (!String.IsNullOrEmpty(time) && time.Contains("|")) + if (!String.IsNullOrEmpty(time) && time.Contains('|')) { - string[] parts = time.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = time.Split(TIME_PARTS, StringSplitOptions.RemoveEmptyEntries); field = parts.Length > 0 && AllowedDateFields.Contains(parts[0]) ? parts[0] : DefaultDateField; time = parts.Length > 1 ? parts[1] : null; } @@ -56,8 +57,7 @@ protected virtual TimeInfo GetTimeInfo(string? time, string? offset, DateTime? m protected int GetLimit(int limit, int maximumLimit = MAXIMUM_LIMIT) { - if (maximumLimit < MAXIMUM_LIMIT) - throw new ArgumentOutOfRangeException(nameof(maximumLimit)); + ArgumentOutOfRangeException.ThrowIfLessThan(maximumLimit, MAXIMUM_LIMIT); if (limit < 1) limit = DEFAULT_LIMIT; diff --git a/src/Exceptionless.Web/Controllers/EventController.cs b/src/Exceptionless.Web/Controllers/EventController.cs index 7ce8ba5db1..832e8ebada 100644 --- a/src/Exceptionless.Web/Controllers/EventController.cs +++ b/src/Exceptionless.Web/Controllers/EventController.cs @@ -88,7 +88,7 @@ ILoggerFactory loggerFactory /// A list of values you want returned. Example: avg:value cardinality:value sum:users max:value min:value /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// Invalid filter. [HttpGet("count")] [Authorize(Policy = AuthorizationRoles.UserPolicy)] @@ -111,7 +111,7 @@ public async Task> GetCountAsync(string? filter = null /// A list of values you want returned. Example: avg:value cardinality:value sum:users max:value min:value /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// Invalid filter. [HttpGet("~/" + API_PREFIX + "/organizations/{organizationId:objectid}/events/count")] [Authorize(Policy = AuthorizationRoles.UserPolicy)] @@ -137,7 +137,7 @@ public async Task> GetCountByOrganizationAsync(string /// A list of values you want returned. Example: avg:value cardinality:value sum:users max:value min:value /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// Invalid filter. [HttpGet("~/" + API_PREFIX + "/projects/{projectId:objectid}/events/count")] [Authorize(Policy = AuthorizationRoles.UserPolicy)] @@ -198,7 +198,7 @@ public async Task> GetAsync(string id, string? tim /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -210,7 +210,7 @@ public async Task> GetAsync(string id, string? tim [ProducesResponseType(typeof(ICollection), 200)] [ProducesResponseType(typeof(ICollection), 200)] [ProducesResponseType(typeof(ICollection), 200)] - public async Task>> GetAsync(string? filter = null, string? sort = null, string? time = null, string? offset = null, string? mode = null, int? page = null, int limit = 10, string? before = null, string? after = null) + public async Task>> GetAllAsync(string? filter = null, string? sort = null, string? time = null, string? offset = null, string? mode = null, int? page = null, int limit = 10, string? before = null, string? after = null) { var organizations = await GetSelectedOrganizationsAsync(_organizationRepository, _projectRepository, _stackRepository, filter); if (organizations.All(o => o.IsSuspended)) @@ -421,7 +421,7 @@ private Task> GetEventsInternalAsync(AppFilter sf, /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -456,7 +456,7 @@ public async Task>> GetByOrganizationA /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -495,7 +495,7 @@ public async Task>> GetByProjectAsync( /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -531,7 +531,7 @@ public async Task>> GetByStackAsync(st /// /// An identifier used that references an event instance. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -560,7 +560,7 @@ public async Task>> GetByReferenceIdAs /// An identifier used that references an event instance. /// The identifier of the project. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -599,7 +599,7 @@ public async Task>> GetByReferenceIdAs /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -631,7 +631,7 @@ public async Task>> GetBySessionIdAsyn /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -669,7 +669,7 @@ public async Task>> GetBySessionIdAndP /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -699,7 +699,7 @@ public async Task>> GetSessionsAsync(s /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. @@ -734,7 +734,7 @@ public async Task>> GetSessionByOrgani /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole event object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// The before parameter is a cursor used for pagination and defines your place in the list of results. diff --git a/src/Exceptionless.Web/Controllers/OrganizationController.cs b/src/Exceptionless.Web/Controllers/OrganizationController.cs index 4ca0afbf1f..52453d2876 100644 --- a/src/Exceptionless.Web/Controllers/OrganizationController.cs +++ b/src/Exceptionless.Web/Controllers/OrganizationController.cs @@ -81,7 +81,7 @@ public OrganizationController( /// /// If no mode is set then a lightweight organization object will be returned. If the mode is set to stats than the fully populated object will be returned. [HttpGet] - public async Task> GetAsync(string? mode = null) + public async Task>> GetAllAsync(string? mode = null) { var organizations = await GetModelsAsync(GetAssociatedOrganizationIds().ToArray()); var viewOrganizations = await MapCollectionAsync(organizations, true); @@ -120,7 +120,7 @@ public async Task> PlanStatsAsync() /// Get by id /// /// The identifier of the organization. - /// If no mode is set then the a light weight organization object will be returned. If the mode is set to stats than the fully populated object will be returned. + /// If no mode is set then the a lightweight organization object will be returned. If the mode is set to stats than the fully populated object will be returned. /// The organization could not be found. [HttpGet("{id:objectid}", Name = "GetOrganizationById")] public async Task> GetAsync(string id, string? mode = null) diff --git a/src/Exceptionless.Web/Controllers/ProjectController.cs b/src/Exceptionless.Web/Controllers/ProjectController.cs index 08bc8e9586..a2ecb99c7e 100644 --- a/src/Exceptionless.Web/Controllers/ProjectController.cs +++ b/src/Exceptionless.Web/Controllers/ProjectController.cs @@ -75,10 +75,10 @@ ILoggerFactory loggerFactory /// Controls the sort order that the data is returned in. In this example -created returns the results descending by the created date. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. - /// If no mode is set then the a light weight project object will be returned. If the mode is set to stats than the fully populated object will be returned. + /// If no mode is set then the lightweight project object will be returned. If the mode is set to stats than the fully populated object will be returned. [HttpGet] [Authorize(Policy = AuthorizationRoles.UserPolicy)] - public async Task>> GetAsync(string? filter = null, string? sort = null, int page = 1, int limit = 10, string? mode = null) + public async Task>> GetAllAsync(string? filter = null, string? sort = null, int page = 1, int limit = 10, string? mode = null) { var organizations = await GetSelectedOrganizationsAsync(_organizationRepository, _projectRepository, _stackRepository, filter); if (organizations.Count == 0) @@ -105,7 +105,7 @@ public async Task>> GetAsync(strin /// The identifier of the organization. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. - /// If no mode is set then the a light weight project object will be returned. If the mode is set to stats than the fully populated object will be returned. + /// If no mode is set then the lightweight project object will be returned. If the mode is set to stats than the fully populated object will be returned. /// The organization could not be found. [HttpGet("~/" + API_PREFIX + "/organizations/{organizationId:objectid}/projects")] [Authorize(Policy = AuthorizationRoles.UserPolicy)] @@ -131,7 +131,7 @@ public async Task>> GetByOrganizat /// Get by id /// /// The identifier of the project. - /// If no mode is set then the a light weight project object will be returned. If the mode is set to stats than the fully populated object will be returned. + /// If no mode is set then the lightweight project object will be returned. If the mode is set to stats than the fully populated object will be returned. /// The project could not be found. [HttpGet("{id:objectid}", Name = "GetProjectById")] [Authorize(Policy = AuthorizationRoles.UserPolicy)] @@ -212,7 +212,7 @@ protected override async Task> DeleteModelsAsync(ICollection #endregion - [Obsolete] + [Obsolete("Use /api/v2/projects/config instead")] [HttpGet("~/api/v1/project/config")] public Task> GetV1ConfigAsync(int? v = null) { @@ -331,7 +331,7 @@ public async Task> ResetDataAsync(string id) ProjectId = project.Id }); - return WorkInProgress(new[] { workItemId }); + return WorkInProgress([workItemId]); } [HttpGet("{id:objectid}/notifications")] @@ -473,9 +473,8 @@ public async Task DeleteNotificationSettingsAsync(string id, stri if (!Request.IsGlobalAdmin() && !String.Equals(user.Id, userId)) return NotFound(); - if (project.NotificationSettings.ContainsKey(userId)) + if (project.NotificationSettings.Remove(userId)) { - project.NotificationSettings.Remove(userId); await _repository.SaveAsync(project, o => o.Cache()); } @@ -560,7 +559,7 @@ private async Task IsProjectNameAvailableInternalAsync(string? organizatio if (String.IsNullOrWhiteSpace(name)) return false; - var organizationIds = IsInOrganization(organizationId) ? new List { organizationId } : GetAssociatedOrganizationIds(); + var organizationIds = IsInOrganization(organizationId) ? [organizationId] : GetAssociatedOrganizationIds(); var projects = await _repository.GetByOrganizationIdsAsync(organizationIds); string decodedName = Uri.UnescapeDataString(name).Trim().ToLowerInvariant(); @@ -580,7 +579,7 @@ private async Task IsProjectNameAvailableInternalAsync(string? organizatio [Authorize(Policy = AuthorizationRoles.UserPolicy)] public async Task PostDataAsync(string id, string key, ValueFromBody value) { - if (String.IsNullOrWhiteSpace(key) || String.IsNullOrWhiteSpace(value?.Value) || key.StartsWith("-")) + if (String.IsNullOrWhiteSpace(key) || String.IsNullOrWhiteSpace(value?.Value) || key.StartsWith('-')) return BadRequest(); var project = await GetModelAsync(id, false); @@ -605,7 +604,7 @@ public async Task PostDataAsync(string id, string key, ValueFromB [Authorize(Policy = AuthorizationRoles.UserPolicy)] public async Task DeleteDataAsync(string id, string key) { - if (String.IsNullOrWhiteSpace(key) || key.StartsWith("-")) + if (String.IsNullOrWhiteSpace(key) || key.StartsWith('-')) return BadRequest(); var project = await GetModelAsync(id, false); diff --git a/src/Exceptionless.Web/Controllers/StackController.cs b/src/Exceptionless.Web/Controllers/StackController.cs index 3f91a51276..e7fad1f095 100644 --- a/src/Exceptionless.Web/Controllers/StackController.cs +++ b/src/Exceptionless.Web/Controllers/StackController.cs @@ -464,13 +464,13 @@ public Task> DeleteAsync(string ids) /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole stack object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole stack object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// Invalid filter. [HttpGet] [Authorize(Policy = AuthorizationRoles.UserPolicy)] - public async Task>> GetAsync(string? filter = null, string? sort = null, string? time = null, string? offset = null, string? mode = null, int page = 1, int limit = 10) + public async Task>> GetAllAsync(string? filter = null, string? sort = null, string? time = null, string? offset = null, string? mode = null, int page = 1, int limit = 10) { var organizations = await GetSelectedOrganizationsAsync(_organizationRepository, _projectRepository, _stackRepository, filter); if (organizations.All(o => o.IsSuspended)) @@ -522,7 +522,7 @@ private async Task>> GetInternalAsync(Ap /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole stack object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole stack object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// Invalid filter. @@ -552,7 +552,7 @@ public async Task>> GetByOrganizationAsy /// Controls the sort order that the data is returned in. In this example -date returns the results descending by date. /// The time filter that limits the data being returned to a specific date range. /// The time offset in minutes that controls what data is returned based on the time filter. This is used for time zone support. - /// If no mode is set then the whole stack object will be returned. If the mode is set to summary than a light weight object will be returned. + /// If no mode is set then the whole stack object will be returned. If the mode is set to summary than a lightweight object will be returned. /// The page parameter is used for pagination. This value must be greater than 0. /// A limit on the number of objects to be returned. Limit can range between 1 and 100 items. /// Invalid filter. diff --git a/src/Exceptionless.Web/Exceptionless.Web.csproj b/src/Exceptionless.Web/Exceptionless.Web.csproj index 81120cf8c8..505f5664e7 100644 --- a/src/Exceptionless.Web/Exceptionless.Web.csproj +++ b/src/Exceptionless.Web/Exceptionless.Web.csproj @@ -16,11 +16,11 @@ - + - - - + + + @@ -29,15 +29,15 @@ - - - - - - - + + + + + + + - + diff --git a/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs b/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs index d85aeb6c44..439eda9ac4 100644 --- a/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs +++ b/tests/Exceptionless.Tests/Controllers/EventControllerTests.cs @@ -503,7 +503,7 @@ await CreateDataAsync(d => [Fact] public async Task WillGetStackEvents() { - (List? stacks, _) = await CreateDataAsync(d => + (var stacks, _) = await CreateDataAsync(d => { d.Event().TestProject(); }); diff --git a/tests/Exceptionless.Tests/Controllers/ProjectControllerTests.cs b/tests/Exceptionless.Tests/Controllers/ProjectControllerTests.cs index 3c6781b533..ed05e404a4 100644 --- a/tests/Exceptionless.Tests/Controllers/ProjectControllerTests.cs +++ b/tests/Exceptionless.Tests/Controllers/ProjectControllerTests.cs @@ -118,7 +118,7 @@ public async Task CanGetProjectListStats() Assert.Equal(0, project.StackCount); Assert.Equal(0, project.EventCount); - (List? stacks, List? events) = await CreateDataAsync(d => + (var stacks, var events) = await CreateDataAsync(d => { d.Event().Message("test"); }); diff --git a/tests/Exceptionless.Tests/Exceptionless.Tests.csproj b/tests/Exceptionless.Tests/Exceptionless.Tests.csproj index 531b59c563..eb979c2adf 100644 --- a/tests/Exceptionless.Tests/Exceptionless.Tests.csproj +++ b/tests/Exceptionless.Tests/Exceptionless.Tests.csproj @@ -6,14 +6,14 @@ - + - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Exceptionless.Tests/GlobalSuppressions.cs b/tests/Exceptionless.Tests/GlobalSuppressions.cs index 4a0a73ae1c..6ba421abe2 100644 --- a/tests/Exceptionless.Tests/GlobalSuppressions.cs +++ b/tests/Exceptionless.Tests/GlobalSuppressions.cs @@ -6,6 +6,6 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "", Scope = "member", Target = "~M:Exceptionless.Tests.Extensions.StringExtensionsTests.LowerUnderscoredWords")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "", Scope = "member", Target = "~M:Exceptionless.Tests.Pipeline.EventPipelineTests.GeneratePerformanceDataAsync~System.Threading.Tasks.Task")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "", Scope = "member", Target = "~M:Exceptionless.Tests.Repositories.EventRepositoryTests.GetAsync~System.Threading.Tasks.Task")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "", Scope = "member", Target = "~M:Exceptionless.Tests.Repositories.EventRepositoryTests.GetAllAsync~System.Threading.Tasks.Task")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "", Scope = "member", Target = "~M:Exceptionless.Tests.Repositories.EventRepositoryTests.GetAsyncPerformanceAsync~System.Threading.Tasks.Task")] diff --git a/tests/Exceptionless.Tests/IntegrationTestsBase.cs b/tests/Exceptionless.Tests/IntegrationTestsBase.cs index 213bbabd05..2052829e3e 100644 --- a/tests/Exceptionless.Tests/IntegrationTestsBase.cs +++ b/tests/Exceptionless.Tests/IntegrationTestsBase.cs @@ -41,7 +41,7 @@ public abstract class IntegrationTestsBase : TestWithLoggingBase, Xunit.IAsyncLi public IntegrationTestsBase(ITestOutputHelper output, AppWebHostFactory factory) : base(output) { - Log.MinimumLevel = LogLevel.Information; + Log.DefaultMinimumLevel = LogLevel.Information; Log.SetLogLevel(LogLevel.Warning); Log.SetLogLevel(LogLevel.Warning); Log.SetLogLevel(LogLevel.Warning); @@ -125,8 +125,6 @@ protected virtual void RegisterServices(IServiceCollection services) await stackRepository.AddAsync(stacks, o => o.ImmediateConsistency()); await eventRepository.AddAsync(events, o => o.ImmediateConsistency()); - await RefreshDataAsync(); - return (stacks.ToList(), events.ToList()); } @@ -135,8 +133,8 @@ protected virtual async Task ResetDataAsync() await _semaphoreSlim.WaitAsync(); try { - var oldLoggingLevel = Log.MinimumLevel; - Log.MinimumLevel = LogLevel.Warning; + var oldLoggingLevel = Log.DefaultMinimumLevel; + Log.DefaultMinimumLevel = LogLevel.Warning; await RefreshDataAsync(); if (!_indexesHaveBeenConfigured) @@ -169,7 +167,7 @@ await _configuration.Client.DeleteByQueryAsync(new DeleteByQueryRequest(indexes) await GetService>().DeleteQueueAsync(); - Log.MinimumLevel = oldLoggingLevel; + Log.DefaultMinimumLevel = oldLoggingLevel; } finally { diff --git a/tests/Exceptionless.Tests/Pipeline/EventPipelineTests.cs b/tests/Exceptionless.Tests/Pipeline/EventPipelineTests.cs index 35b10bd535..42d2871cc7 100644 --- a/tests/Exceptionless.Tests/Pipeline/EventPipelineTests.cs +++ b/tests/Exceptionless.Tests/Pipeline/EventPipelineTests.cs @@ -12,6 +12,7 @@ using Exceptionless.Core.Queues.Models; using Exceptionless.Core.Repositories; using Exceptionless.Core.Repositories.Configuration; +using Exceptionless.Core.Utility; using Exceptionless.DateTimeExtensions; using Exceptionless.Tests.Utility; using Foundatio.Repositories; @@ -243,7 +244,7 @@ public async Task CloseExistingAutoSessionAsync() var contexts = await _pipeline.RunAsync(events, OrganizationData.GenerateSampleOrganization(_billingManager, _plans), ProjectData.GenerateSampleProject()); Assert.DoesNotContain(contexts, c => c.HasError); - Assert.Equal(1, contexts.Count(c => c.IsCancelled && c.IsDiscarded)); + Assert.Equal(1, contexts.Count(c => c is { IsCancelled: true, IsDiscarded: true })); Assert.Contains(contexts, c => c.IsProcessed); await RefreshDataAsync(); @@ -304,7 +305,7 @@ public async Task WillMarkAutoSessionHeartbeatStackHiddenAsync() var contexts = await _pipeline.RunAsync(events, OrganizationData.GenerateSampleOrganization(_billingManager, _plans), ProjectData.GenerateSampleProject()); Assert.DoesNotContain(contexts, c => c.HasError); - Assert.Equal(1, contexts.Count(c => c.IsCancelled && c.IsDiscarded)); + Assert.Equal(1, contexts.Count(c => c is { IsCancelled: true, IsDiscarded: true })); Assert.Equal(0, contexts.Count(c => c.IsProcessed)); await RefreshDataAsync(); @@ -459,7 +460,7 @@ public async Task CloseExistingManualSessionAsync() var contexts = await _pipeline.RunAsync(events, OrganizationData.GenerateSampleOrganization(_billingManager, _plans), ProjectData.GenerateSampleProject()); Assert.DoesNotContain(contexts, c => c.HasError); - Assert.Equal(1, contexts.Count(c => c.IsCancelled && c.IsDiscarded)); + Assert.Equal(1, contexts.Count(c => c is { IsCancelled: true, IsDiscarded: true })); Assert.Contains(contexts, c => c.IsProcessed); events = @@ -518,7 +519,7 @@ public async Task WillMarkManualSessionHeartbeatStackHiddenAsync() var contexts = await _pipeline.RunAsync(events, OrganizationData.GenerateSampleOrganization(_billingManager, _plans), ProjectData.GenerateSampleProject()); Assert.DoesNotContain(contexts, c => c.HasError); - Assert.Equal(1, contexts.Count(c => c.IsCancelled && c.IsDiscarded)); + Assert.Equal(1, contexts.Count(c => c is { IsCancelled: true, IsDiscarded: true })); Assert.Equal(0, contexts.Count(c => c.IsProcessed)); await RefreshDataAsync(); @@ -929,7 +930,7 @@ public async Task WillHandleDiscardedStack() var organization = OrganizationData.GenerateSampleOrganization(_billingManager, _plans); var project = ProjectData.GenerateSampleProject(); - var ev = EventData.GenerateEvent(organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); + var ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); var context = await _pipeline.RunAsync(ev, organization, project); Assert.True(context.IsProcessed); Assert.False(context.HasError); @@ -944,8 +945,7 @@ public async Task WillHandleDiscardedStack() stack.Status = StackStatus.Discarded; stack = await _stackRepository.SaveAsync(stack, o => o.ImmediateConsistency()); - - ev = EventData.GenerateEvent(organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId, stackId: ev.StackId, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); + ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); context = await _pipeline.RunAsync(ev, organization, project); Assert.False(context.IsProcessed); Assert.False(context.HasError); @@ -953,13 +953,93 @@ public async Task WillHandleDiscardedStack() Assert.True(context.IsDiscarded); await RefreshDataAsync(); - ev = EventData.GenerateEvent(organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); + ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); context = await _pipeline.RunAsync(ev, organization, project); Assert.False(context.IsProcessed); Assert.False(context.HasError); Assert.True(context.IsCancelled); Assert.True(context.IsDiscarded); + } + + [Theory] + [InlineData(StackStatus.Regressed, false, null, null)] + [InlineData(StackStatus.Fixed, true, "1.0.0", null)] // A fixed stack should not be marked as regressed if the event has no version. + [InlineData(StackStatus.Regressed, false, null, "1.0.0")] + [InlineData(StackStatus.Regressed, false, "1.0.0", "1.0.0")] // A fixed stack should not be marked as regressed if the event has the same version. + [InlineData(StackStatus.Fixed, true, "2.0.0", "1.0.0")] + [InlineData(StackStatus.Regressed, false, null, "1.0.1")] + [InlineData(StackStatus.Regressed, false, "1.0.0", "1.0.1")] + public async Task CanDiscardStackEventsBasedOnEventVersion(StackStatus expectedStatus, bool expectedDiscard, string? stackFixedInVersion, string? eventSemanticVersion) + { + var organization = await _organizationRepository.GetByIdAsync(TestConstants.OrganizationId, o => o.Cache()); + var project = await _projectRepository.GetByIdAsync(TestConstants.ProjectId, o => o.Cache()); + + var ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); + var context = await _pipeline.RunAsync(ev, organization, project); + + var stack = context.Stack; + Assert.NotNull(stack); + Assert.Equal(StackStatus.Open, stack.Status); + + Assert.True(context.IsProcessed); + Assert.False(context.HasError); + Assert.False(context.IsCancelled); + Assert.False(context.IsDiscarded); + + var semanticVersionParser = GetService(); + var fixedInVersion = semanticVersionParser.Parse(stackFixedInVersion); + stack.MarkFixed(fixedInVersion); + await _stackRepository.SaveAsync(stack, o => o.ImmediateConsistency()); + + await RefreshDataAsync(); + ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow, semver: eventSemanticVersion); + context = await _pipeline.RunAsync(ev, organization, project); + + stack = context.Stack; + Assert.NotNull(stack); + Assert.Equal(expectedStatus, stack.Status); + Assert.Equal(expectedDiscard, context.IsCancelled); + Assert.Equal(expectedDiscard, context.IsDiscarded); + } + + [Theory] + [InlineData("1.0.0", null)] // A fixed stack should not be marked as regressed if the event has no version. + [InlineData("2.0.0", "1.0.0")] + public async Task WillNotDiscardStackEventsBasedOnEventVersionWithFreePlan(string stackFixedInVersion, string? eventSemanticVersion) + { + var organization = await _organizationRepository.GetByIdAsync(TestConstants.OrganizationId3, o => o.Cache()); + + var plans = GetService(); + Assert.Equal(plans.FreePlan.Id, organization.PlanId); + + var project = await _projectRepository.AddAsync(ProjectData.GenerateProject(organizationId: organization.Id), o => o.ImmediateConsistency().Cache()); + + var ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow); + var context = await _pipeline.RunAsync(ev, organization, project); + + var stack = context.Stack; + Assert.NotNull(stack); + Assert.Equal(StackStatus.Open, stack.Status); + + Assert.True(context.IsProcessed); + Assert.False(context.HasError); + Assert.False(context.IsCancelled); + Assert.False(context.IsDiscarded); + + var semanticVersionParser = GetService(); + var fixedInVersion = semanticVersionParser.Parse(stackFixedInVersion); + stack.MarkFixed(fixedInVersion); + await _stackRepository.SaveAsync(stack, o => o.ImmediateConsistency()); + await RefreshDataAsync(); + ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow, semver: eventSemanticVersion); + context = await _pipeline.RunAsync(ev, organization, project); + + stack = context.Stack; + Assert.NotNull(stack); + Assert.Equal(StackStatus.Fixed, stack.Status); + Assert.False(context.IsCancelled); + Assert.False(context.IsDiscarded); } [Theory] @@ -1164,10 +1244,10 @@ private async Task CreateProjectDataAsync(BillingPlan? plan = null) organization.SuspensionDate = SystemClock.UtcNow; } - await _organizationRepository.AddAsync(organization, o => o.Cache()); + await _organizationRepository.AddAsync(organization, o => o.ImmediateConsistency().Cache()); } - await _projectRepository.AddAsync(ProjectData.GenerateSampleProjects(), o => o.Cache()); + await _projectRepository.AddAsync(ProjectData.GenerateSampleProjects(), o => o.ImmediateConsistency().Cache()); foreach (var user in UserData.GenerateSampleUsers()) { @@ -1180,10 +1260,8 @@ private async Task CreateProjectDataAsync(BillingPlan? plan = null) if (!user.IsEmailAddressVerified) user.CreateVerifyEmailAddressToken(); - await _userRepository.AddAsync(user, o => o.Cache()); + await _userRepository.AddAsync(user, o => o.ImmediateConsistency().Cache()); } - - await RefreshDataAsync(); } private static PersistentEvent GenerateEvent(DateTimeOffset? occurrenceDate = null, string? userIdentity = null, string? type = null, string? sessionId = null) diff --git a/tests/Exceptionless.Tests/Repositories/EventRepositoryTests.cs b/tests/Exceptionless.Tests/Repositories/EventRepositoryTests.cs index b5e3b8434c..cba7c1fd38 100644 --- a/tests/Exceptionless.Tests/Repositories/EventRepositoryTests.cs +++ b/tests/Exceptionless.Tests/Repositories/EventRepositoryTests.cs @@ -133,7 +133,6 @@ public async Task GetNextEventIdInStackTestAsync() _logger.LogDebug(""); _logger.LogDebug("Tests:"); - await RefreshDataAsync(); Assert.Equal(_ids.Count, await _repository.CountAsync()); for (int i = 0; i < sortedIds.Count; i++) { @@ -164,9 +163,8 @@ public async Task CanGetPreviousAndNExtEventIdWithFilterTestAsync() public async Task GetByReferenceIdAsync() { string referenceId = ObjectId.GenerateNewId().ToString(); - await _repository.AddAsync(EventData.GenerateEvents(3, TestConstants.OrganizationId, TestConstants.ProjectId, TestConstants.StackId2, referenceId: referenceId).ToList()); + await _repository.AddAsync(EventData.GenerateEvents(3, TestConstants.OrganizationId, TestConstants.ProjectId, TestConstants.StackId2, referenceId: referenceId).ToList(), o => o.ImmediateConsistency()); - await RefreshDataAsync(); var results = await _repository.GetByReferenceIdAsync(TestConstants.ProjectId, referenceId); Assert.True(results.Total > 0); Assert.NotNull(results.Documents.First()); @@ -193,9 +191,8 @@ public async Task GetOpenSessionsAsync() closedSession }; - await _repository.AddAsync(events); + await _repository.AddAsync(events, o => o.ImmediateConsistency()); - await RefreshDataAsync(); var results = await _repository.GetOpenSessionsAsync(SystemClock.UtcNow.SubtractMinutes(30)); Assert.Equal(3, results.Total); } @@ -204,13 +201,12 @@ public async Task GetOpenSessionsAsync() public async Task RemoveAllByClientIpAndDateAsync() { const string _clientIpAddress = "123.123.12.255"; - const int NUMBER_OF_EVENTS_TO_CREATE = 50; + var events = EventData.GenerateEvents(NUMBER_OF_EVENTS_TO_CREATE, TestConstants.OrganizationId, TestConstants.ProjectId, TestConstants.StackId2, startDate: SystemClock.UtcNow.SubtractDays(2), endDate: SystemClock.UtcNow).ToList(); events.ForEach(e => e.AddRequestInfo(new RequestInfo { ClientIpAddress = _clientIpAddress })); - await _repository.AddAsync(events); + await _repository.AddAsync(events, o => o.ImmediateConsistency()); - await RefreshDataAsync(); events = (await _repository.GetByProjectIdAsync(TestConstants.ProjectId, o => o.PageLimit(NUMBER_OF_EVENTS_TO_CREATE))).Documents.ToList(); Assert.Equal(NUMBER_OF_EVENTS_TO_CREATE, events.Count); events.ForEach(e => @@ -220,9 +216,8 @@ public async Task RemoveAllByClientIpAndDateAsync() Assert.Equal(_clientIpAddress, ri.ClientIpAddress); }); - await _repository.RemoveAllAsync(TestConstants.OrganizationId, _clientIpAddress, SystemClock.UtcNow.SubtractDays(3), SystemClock.UtcNow.AddDays(2)); + await _repository.RemoveAllAsync(TestConstants.OrganizationId, _clientIpAddress, SystemClock.UtcNow.SubtractDays(3), SystemClock.UtcNow.AddDays(2), o => o.ImmediateConsistency()); - await RefreshDataAsync(); events = (await _repository.GetByProjectIdAsync(TestConstants.ProjectId, o => o.PageLimit(NUMBER_OF_EVENTS_TO_CREATE))).Documents.ToList(); Assert.Empty(events); } @@ -236,7 +231,7 @@ private async Task CreateDataAsync() var occurrenceDateMid = baseDate; var occurrenceDateEnd = baseDate.AddMinutes(30); - await _stackRepository.AddAsync(StackData.GenerateStack(id: TestConstants.StackId, organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId)); + await _stackRepository.AddAsync(StackData.GenerateStack(id: TestConstants.StackId, organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId), o => o.ImmediateConsistency()); var occurrenceDates = new List { occurrenceDateStart, @@ -255,10 +250,8 @@ private async Task CreateDataAsync() foreach (var date in occurrenceDates) { - var ev = await _repository.AddAsync(EventData.GenerateEvent(projectId: TestConstants.ProjectId, organizationId: TestConstants.OrganizationId, stackId: TestConstants.StackId, occurrenceDate: date)); + var ev = await _repository.AddAsync(EventData.GenerateEvent(projectId: TestConstants.ProjectId, organizationId: TestConstants.OrganizationId, stackId: TestConstants.StackId, occurrenceDate: date), o => o.ImmediateConsistency()); _ids.Add(Tuple.Create(ev.Id, date)); } - - await RefreshDataAsync(); } } diff --git a/tests/Exceptionless.Tests/Repositories/OrganizationRepositoryTests.cs b/tests/Exceptionless.Tests/Repositories/OrganizationRepositoryTests.cs index 5332a85310..7b92db1318 100644 --- a/tests/Exceptionless.Tests/Repositories/OrganizationRepositoryTests.cs +++ b/tests/Exceptionless.Tests/Repositories/OrganizationRepositoryTests.cs @@ -31,8 +31,7 @@ public async Task CanCreateUpdateRemoveAsync() var organization = new Organization { Name = "Test Organization", PlanId = _plans.FreePlan.Id }; Assert.Null(organization.Id); - await _repository.AddAsync(organization); - await RefreshDataAsync(); + await _repository.AddAsync(organization, o => o.ImmediateConsistency()); Assert.NotNull(organization.Id); organization = await _repository.GetByIdAsync(organization.Id); @@ -40,7 +39,6 @@ public async Task CanCreateUpdateRemoveAsync() organization.Name = "New organization"; await _repository.SaveAsync(organization); - await _repository.RemoveAsync(organization.Id); } @@ -51,8 +49,7 @@ public async Task CanAddAndGetByCachedAsync() Assert.Null(organization.Id); Assert.Equal(0, _cache.Count); - await _repository.AddAsync(organization, o => o.Cache()); - await RefreshDataAsync(); + await _repository.AddAsync(organization, o => o.ImmediateConsistency().Cache()); Assert.NotNull(organization.Id); Assert.Equal(1, _cache.Count); @@ -62,8 +59,7 @@ public async Task CanAddAndGetByCachedAsync() Assert.NotNull(organization.Id); Assert.Equal(1, _cache.Count); - await _repository.RemoveAllAsync(); - await RefreshDataAsync(); + await _repository.RemoveAllAsync(o => o.ImmediateConsistency()); Assert.Equal(0, _cache.Count); } } diff --git a/tests/Exceptionless.Tests/Repositories/TokenRepositoryTests.cs b/tests/Exceptionless.Tests/Repositories/TokenRepositoryTests.cs index 60c6057fb1..81042f8b5d 100644 --- a/tests/Exceptionless.Tests/Repositories/TokenRepositoryTests.cs +++ b/tests/Exceptionless.Tests/Repositories/TokenRepositoryTests.cs @@ -36,22 +36,22 @@ await _repository.AddAsync(new List { Assert.Equal(3, (await _repository.GetByProjectIdAsync(TestConstants.ProjectIdWithNoRoles)).Total); await _repository.RemoveAllByProjectIdAsync(TestConstants.OrganizationId, TestConstants.ProjectId); - await RefreshDataAsync(); + Assert.Equal(4, (await _repository.GetByOrganizationIdAsync(TestConstants.OrganizationId)).Total); Assert.Equal(1, (await _repository.GetByProjectIdAsync(TestConstants.ProjectId)).Total); Assert.Equal(3, (await _repository.GetByProjectIdAsync(TestConstants.ProjectIdWithNoRoles)).Total); await _repository.RemoveAllByProjectIdAsync(TestConstants.OrganizationId, TestConstants.ProjectIdWithNoRoles); - await RefreshDataAsync(); + Assert.Equal(3, (await _repository.GetByOrganizationIdAsync(TestConstants.OrganizationId)).Total); Assert.Equal(1, (await _repository.GetByProjectIdAsync(TestConstants.ProjectId)).Total); Assert.Equal(2, (await _repository.GetByProjectIdAsync(TestConstants.ProjectIdWithNoRoles)).Total); await _repository.RemoveAllByOrganizationIdAsync(TestConstants.OrganizationId); - await RefreshDataAsync(); + Assert.Equal(0, (await _repository.GetByOrganizationIdAsync(TestConstants.OrganizationId)).Total); Assert.Equal(0, (await _repository.GetByProjectIdAsync(TestConstants.ProjectId)).Total); Assert.Equal(1, (await _repository.GetByProjectIdAsync(TestConstants.ProjectIdWithNoRoles)).Total); @@ -68,8 +68,7 @@ await _repository.AddAsync(new List { Assert.Equal(1, (await _repository.GetByTypeAndUserIdAsync(TokenType.Access, TestConstants.UserId)).Total); Assert.Equal(1, (await _repository.GetByTypeAndUserIdAsync(TokenType.Authentication, TestConstants.UserId)).Total); - await _repository.RemoveAllByUserIdAsync(TestConstants.UserId); - await RefreshDataAsync(); + await _repository.RemoveAllByUserIdAsync(TestConstants.UserId, o => o.ImmediateConsistency()); Assert.Equal(0, (await _repository.GetByTypeAndUserIdAsync(TokenType.Access, TestConstants.UserId)).Total); Assert.Equal(0, (await _repository.GetByTypeAndUserIdAsync(TokenType.Authentication, TestConstants.UserId)).Total); Assert.Equal(1, (await _repository.GetByOrganizationIdAsync(TestConstants.OrganizationId)).Total); diff --git a/tests/Exceptionless.Tests/Repositories/WebHookRepositoryTests.cs b/tests/Exceptionless.Tests/Repositories/WebHookRepositoryTests.cs index 81c1718a60..7918fe2a0f 100644 --- a/tests/Exceptionless.Tests/Repositories/WebHookRepositoryTests.cs +++ b/tests/Exceptionless.Tests/Repositories/WebHookRepositoryTests.cs @@ -1,6 +1,7 @@ using Exceptionless.Core.Models; using Exceptionless.Core.Repositories; using Exceptionless.Tests.Utility; +using Foundatio.Repositories; using Xunit; using Xunit.Abstractions; @@ -18,34 +19,33 @@ public WebHookRepositoryTests(ITestOutputHelper output, AppWebHostFactory factor [Fact] public async Task GetByOrganizationIdOrProjectIdAsync() { - await _repository.AddAsync(new WebHook + await _repository.AddAsync([new WebHook { OrganizationId = TestConstants.OrganizationId, Url = "http://localhost:40000/test", EventTypes = [WebHook.KnownEventTypes.StackPromoted], Version = WebHook.KnownVersions.Version2 - }); - await _repository.AddAsync(new WebHook - { - OrganizationId = TestConstants.OrganizationId, - ProjectId = TestConstants.ProjectId, - Url = "http://localhost:40000/test1", - EventTypes = + }, + new WebHook + { + OrganizationId = TestConstants.OrganizationId, + ProjectId = TestConstants.ProjectId, + Url = "http://localhost:40000/test1", + EventTypes = [WebHook.KnownEventTypes.StackPromoted], - Version = WebHook.KnownVersions.Version2 - }); - await _repository.AddAsync(new WebHook - { - OrganizationId = TestConstants.OrganizationId, - ProjectId = TestConstants.ProjectIdWithNoRoles, - Url = "http://localhost:40000/test1", - EventTypes = + Version = WebHook.KnownVersions.Version2 + }, + new WebHook + { + OrganizationId = TestConstants.OrganizationId, + ProjectId = TestConstants.ProjectIdWithNoRoles, + Url = "http://localhost:40000/test1", + EventTypes = [WebHook.KnownEventTypes.StackPromoted], - Version = WebHook.KnownVersions.Version2 - }); + Version = WebHook.KnownVersions.Version2 + }], o => o.ImmediateConsistency()); - await RefreshDataAsync(); Assert.Equal(3, (await _repository.GetByOrganizationIdAsync(TestConstants.OrganizationId)).Total); Assert.Equal(2, (await _repository.GetByOrganizationIdOrProjectIdAsync(TestConstants.OrganizationId, TestConstants.ProjectId)).Total); Assert.Equal(1, (await _repository.GetByProjectIdAsync(TestConstants.ProjectId)).Total); @@ -55,7 +55,7 @@ await _repository.AddAsync(new WebHook [Fact] public async Task CanSaveWebHookVersionAsync() { - await _repository.AddAsync(new WebHook + await _repository.AddAsync([new WebHook { OrganizationId = TestConstants.OrganizationId, ProjectId = TestConstants.ProjectId, @@ -63,18 +63,17 @@ await _repository.AddAsync(new WebHook EventTypes = [WebHook.KnownEventTypes.StackPromoted], Version = WebHook.KnownVersions.Version1 - }); - await _repository.AddAsync(new WebHook - { - OrganizationId = TestConstants.OrganizationId, - ProjectId = TestConstants.ProjectIdWithNoRoles, - Url = "http://localhost:40000/test1", - EventTypes = + }, + new WebHook + { + OrganizationId = TestConstants.OrganizationId, + ProjectId = TestConstants.ProjectIdWithNoRoles, + Url = "http://localhost:40000/test1", + EventTypes = [WebHook.KnownEventTypes.StackPromoted], - Version = WebHook.KnownVersions.Version2 - }); + Version = WebHook.KnownVersions.Version2 + }], o => o.ImmediateConsistency()); - await RefreshDataAsync(); Assert.Equal(WebHook.KnownVersions.Version1, (await _repository.GetByProjectIdAsync(TestConstants.ProjectId)).Documents.First().Version); Assert.Equal(WebHook.KnownVersions.Version2, (await _repository.GetByProjectIdAsync(TestConstants.ProjectIdWithNoRoles)).Documents.First().Version); } diff --git a/tests/Exceptionless.Tests/Search/EventStackFilterTests.cs b/tests/Exceptionless.Tests/Search/EventStackFilterTests.cs index 5b77391d6e..d4766cc34f 100644 --- a/tests/Exceptionless.Tests/Search/EventStackFilterTests.cs +++ b/tests/Exceptionless.Tests/Search/EventStackFilterTests.cs @@ -31,13 +31,13 @@ protected override async Task ResetDataAsync() { await base.ResetDataAsync(); - var oldLoggingLevel = Log.MinimumLevel; - Log.MinimumLevel = LogLevel.Warning; + var oldLoggingLevel = Log.DefaultMinimumLevel; + Log.DefaultMinimumLevel = LogLevel.Warning; await StackData.CreateSearchDataAsync(_stackRepository, GetService()); await EventData.CreateSearchDataAsync(GetService(), _eventRepository, GetService()); - Log.MinimumLevel = oldLoggingLevel; + Log.DefaultMinimumLevel = oldLoggingLevel; } [Theory] diff --git a/tests/Exceptionless.Tests/Services/StackServiceTests.cs b/tests/Exceptionless.Tests/Services/StackServiceTests.cs index 8a2abdfa54..c19ba11037 100644 --- a/tests/Exceptionless.Tests/Services/StackServiceTests.cs +++ b/tests/Exceptionless.Tests/Services/StackServiceTests.cs @@ -43,8 +43,8 @@ public async Task IncrementUsage_OnlyChangeCache() Assert.True(occurrenceSet.IsNull || !occurrenceSet.HasValue || occurrenceSet.Value.Count == 0); var firstUtcNow = SystemClock.UtcNow.Floor(TimeSpan.FromMilliseconds(1)); - await RefreshDataAsync(); await _stackService.IncrementStackUsageAsync(TestConstants.OrganizationId, TestConstants.ProjectId, stack.Id, firstUtcNow, firstUtcNow, 1); + await RefreshDataAsync(); // Assert stack state has no change after increment usage stack = await _stackRepository.GetByIdAsync(TestConstants.StackId); @@ -60,7 +60,6 @@ public async Task IncrementUsage_OnlyChangeCache() Assert.Single(occurrenceSet.Value); var secondUtcNow = SystemClock.UtcNow.Floor(TimeSpan.FromMilliseconds(1)); - await RefreshDataAsync(); await _stackService.IncrementStackUsageAsync(TestConstants.OrganizationId, TestConstants.ProjectId, stack.Id, secondUtcNow, secondUtcNow, 2); // Assert state in cache has been changed after increment usage again diff --git a/tests/Exceptionless.Tests/Stats/AggregationTests.cs b/tests/Exceptionless.Tests/Stats/AggregationTests.cs index f33e5cb0ce..e15204fd5c 100644 --- a/tests/Exceptionless.Tests/Stats/AggregationTests.cs +++ b/tests/Exceptionless.Tests/Stats/AggregationTests.cs @@ -207,16 +207,14 @@ public async Task CanGetSessionAggregationsAsync() private async Task CreateDataAsync(int eventCount = 0, bool multipleProjects = true) { - var orgs = OrganizationData.GenerateSampleOrganizations(_billingManager, _plans); - await _organizationRepository.AddAsync(orgs, o => o.Cache()); + var organizations = OrganizationData.GenerateSampleOrganizations(_billingManager, _plans); + await _organizationRepository.AddAsync(organizations, o => o.ImmediateConsistency().Cache()); var projects = ProjectData.GenerateSampleProjects(); - await _projectRepository.AddAsync(projects, o => o.Cache()); - await RefreshDataAsync(); + await _projectRepository.AddAsync(projects, o => o.ImmediateConsistency().Cache()); if (eventCount > 0) - await CreateEventsAsync(eventCount, multipleProjects ? projects.Select(p => p.Id).ToArray() : [TestConstants.ProjectId - ]); + await CreateEventsAsync(eventCount, multipleProjects ? projects.Select(p => p.Id).ToArray() : [TestConstants.ProjectId]); } private async Task CreateEventsAsync(int eventCount, string[]? projectIds, decimal? value = -1) diff --git a/tests/Exceptionless.Tests/TestWithServices.cs b/tests/Exceptionless.Tests/TestWithServices.cs index 760522b953..eff5eb0e1b 100644 --- a/tests/Exceptionless.Tests/TestWithServices.cs +++ b/tests/Exceptionless.Tests/TestWithServices.cs @@ -23,7 +23,7 @@ public class TestWithServices : TestWithLoggingBase, IAsyncLifetime public TestWithServices(ITestOutputHelper output) : base(output) { - Log.MinimumLevel = LogLevel.Information; + Log.DefaultMinimumLevel = LogLevel.Information; Log.SetLogLevel(LogLevel.Warning); Log.SetLogLevel(LogLevel.Warning); Log.SetLogLevel(LogLevel.Warning);