From 927896748e9c054e8ae6bc67cf9c64fd280152c7 Mon Sep 17 00:00:00 2001 From: Eric Wang <37554696+ericwang401@users.noreply.github.com> Date: Mon, 6 Nov 2023 04:07:11 +0000 Subject: [PATCH] so fucking much --- .prettierrc.json | 8 +- .../Admin/AddressPools/AddressController.php | 67 +- .../Admin/Nodes/AddressController.php | 125 ++- .../Addresses/StoreAddressRequest.php | 16 +- .../Addresses/UpdateAddressRequest.php | 5 +- .../Nodes/Addresses/StoreAddressRequest.php | 69 +- .../Nodes/Addresses/UpdateAddressRequest.php | 54 +- .../Eloquent/AddressRepository.php | 4 +- .../Nodes/Addresses/AddressHelpers.php | 45 - app/Validation/ValidateAddressUniqueness.php | 4 +- lang/en_US/validation.php | 1 + package-lock.json | 827 ++++++++++-------- .../addressPools/addresses/createAddress.ts | 4 +- ...{updateAddressPool.ts => updateAddress.ts} | 0 .../{addresses => }/useAddressPoolSWR.ts | 0 .../scripts/api/admin/nodes/useNodeSWR.ts | 21 + .../admin/ipam/PoolContentBlock.tsx | 2 +- .../ipam/addresses/CreateAddressModal.tsx | 51 +- .../admin/ipam/addresses/EditAddressModal.tsx | 4 +- .../nodes/addresses/CreateAddressModal.tsx | 153 ++++ .../nodes/addresses/EditAddressModal.tsx | 12 +- .../addresses/NodeAddressesContainer.tsx | 6 +- .../nodes/addresses/ServersSelectFormik.tsx | 8 +- .../admin/nodes/isos/CreateIsoModal.tsx | 126 ++- .../admin/nodes/isos/EditIsoModal.tsx | 9 +- .../admin/nodes/isos/IsosContainer.tsx | 9 +- .../admin/nodes/isos/QueryFileButton.tsx | 5 +- .../admin/nodes/overview/NodeDetailsBlock.tsx | 3 +- .../nodes/servers/NodeServersContainer.tsx | 10 +- .../nodes/settings/NodeSettingsContainer.tsx | 6 +- .../settings/partials/general/CotermCard.tsx | 24 +- .../partials/general/DeleteNodeCard.tsx | 7 +- .../partials/general/NodeInformationCard.tsx | 6 +- .../templates/EditTemplateGroupModal.tsx | 20 +- .../nodes/templates/EditTemplateModal.tsx | 9 +- .../templates/NodeTemplatesContainer.tsx | 7 +- .../admin/nodes/templates/TemplateCard.tsx | 7 +- .../nodes/templates/TemplateGroupCard.tsx | 10 +- resources/scripts/routers/AdminIpamRouter.tsx | 4 +- resources/scripts/routers/AdminNodeRouter.tsx | 8 +- 40 files changed, 984 insertions(+), 772 deletions(-) delete mode 100644 app/Services/Nodes/Addresses/AddressHelpers.php rename resources/scripts/api/admin/addressPools/addresses/{updateAddressPool.ts => updateAddress.ts} (100%) rename resources/scripts/api/admin/addressPools/{addresses => }/useAddressPoolSWR.ts (100%) create mode 100644 resources/scripts/api/admin/nodes/useNodeSWR.ts create mode 100644 resources/scripts/components/admin/nodes/addresses/CreateAddressModal.tsx diff --git a/.prettierrc.json b/.prettierrc.json index f3bf1dc8d89..9931f23c23f 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -6,7 +6,7 @@ "htmlWhitespaceSensitivity": "css", "insertPragma": false, "jsxSingleQuote": true, - "printWidth": 120, + "printWidth": 80, "proseWrap": "preserve", "quoteProps": "consistent", "requirePragma": false, @@ -16,5 +16,9 @@ "trailingComma": "es5", "useTabs": false, "vueIndentScriptAndStyle": false, - "tabWidth": 4 + "tabWidth": 4, + "importOrderSeparation": true, + "importOrderSortSpecifiers": true, + "importOrder": ["^@/api/(.*)$", "^@/components/elements/(.*)$", "^@/components/(.*)$", "^[./]"], + "plugins": ["@trivago/prettier-plugin-sort-imports"] } \ No newline at end of file diff --git a/app/Http/Controllers/Admin/AddressPools/AddressController.php b/app/Http/Controllers/Admin/AddressPools/AddressController.php index 7d26c11a253..444c64101ce 100644 --- a/app/Http/Controllers/Admin/AddressPools/AddressController.php +++ b/app/Http/Controllers/Admin/AddressPools/AddressController.php @@ -3,12 +3,12 @@ namespace Convoy\Http\Controllers\Admin\AddressPools; use Convoy\Models\Address; -use Illuminate\Support\Facades\Log; use Convoy\Enums\Network\AddressType; use Convoy\Services\Servers\NetworkService; +use Convoy\Jobs\Server\SyncNetworkSettings; use Illuminate\Database\ConnectionInterface; use Convoy\Transformers\Admin\AddressTransformer; -use Convoy\Services\Nodes\Addresses\AddressHelpers; +use Convoy\Repositories\Eloquent\AddressRepository; use Convoy\Http\Controllers\ApplicationApiController; use Convoy\Models\AddressPool; use Convoy\Models\Filters\AllowedNullableFilter; @@ -16,7 +16,6 @@ use Illuminate\Http\Request; use Spatie\QueryBuilder\AllowedFilter; use Spatie\QueryBuilder\QueryBuilder; -use Symfony\Component\HttpKernel\Exception\HttpException; use Convoy\Exceptions\Repository\Proxmox\ProxmoxConnectionException; use Convoy\Http\Requests\Admin\AddressPools\Addresses\StoreAddressRequest; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; @@ -24,7 +23,7 @@ class AddressController extends ApplicationApiController { - public function __construct(private NetworkService $networkService, private AddressHelpers $addressHelpers, private ConnectionInterface $connection) + public function __construct(private NetworkService $networkService, private AddressRepository $repository, private ConnectionInterface $connection) { } @@ -46,27 +45,9 @@ public function index(Request $request, AddressPool $addressPool) public function store(StoreAddressRequest $request, AddressPool $addressPool) { - /** @var Address|Address[] $address */ - $address = $this->connection->transaction(function () use ($request, $addressPool) { - if ($request->boolean('is_bulk_action')) { - $addressesToAdd = $this->addressHelpers->expandIpRange( - $request->enum('type', AddressType::class), - $request->starting_address, - $request->ending_address, - ); - - foreach ($addressesToAdd as &$address) { - $address = [ - 'address' => $address, - 'address_pool_id' => $addressPool->id, - ...$request->safe()->only(['server_id', 'type', 'cidr', 'gateway', 'mac_address']) - ]; - } - - - - - } else { + if (!$request->boolean('is_bulk_action')) { + /** @var Address $address */ + $address = $this->connection->transaction(function () use ($request, $addressPool) { $address = $addressPool->addresses()->create($request->validated()); if ($request->server_id) { @@ -80,10 +61,42 @@ public function store(StoreAddressRequest $request, AddressPool $addressPool) } return $address; + }); + + return fractal($address, new AddressTransformer)->parseIncludes($request->include)->respond(); + } + + if ($request->boolean('is_bulk_action')) { + $this->connection->transaction(function () use ($request, $addressPool) { + if ($request->enum('type', AddressType::class) === AddressType::IPV4) { + $this->repository->bulkCreateIPv4Addresses( + $request->starting_address, + $request->ending_address, + $addressPool->id, + $request->server_id, + $request->cidr, + $request->gateway, + $request->mac_address, + ); + } else { + $this->repository->bulkCreateIPv6Addresses( + $request->starting_address, + $request->ending_address, + $addressPool->id, + $request->server_id, + $request->cidr, + $request->gateway, + $request->mac_address, + ); + } + }); + + if (!is_null($request->server_id)) { + SyncNetworkSettings::dispatch($request->integer('server_id')); } - }); - return fractal($address, new AddressTransformer)->parseIncludes($request->include)->respond(); + return $this->returnNoContent(); + } } public function update(UpdateAddressRequest $request, AddressPool $addressPool, Address $address) diff --git a/app/Http/Controllers/Admin/Nodes/AddressController.php b/app/Http/Controllers/Admin/Nodes/AddressController.php index 3deade55199..08989a77688 100644 --- a/app/Http/Controllers/Admin/Nodes/AddressController.php +++ b/app/Http/Controllers/Admin/Nodes/AddressController.php @@ -2,102 +2,99 @@ namespace Convoy\Http\Controllers\Admin\Nodes; +use Convoy\Models\Node; +use Convoy\Models\Address; +use Illuminate\Http\Request; +use Convoy\Models\AddressPool; +use Spatie\QueryBuilder\QueryBuilder; +use Spatie\QueryBuilder\AllowedFilter; use Convoy\Http\Controllers\Controller; -use Convoy\Http\Requests\Admin\Nodes\Addresses\StoreAddressRequest; -use Convoy\Http\Requests\Admin\Nodes\Addresses\UpdateAddressRequest; -use Convoy\Models\Filters\AllowedNullableFilter; use Convoy\Models\Filters\FiltersAddress; -use Convoy\Models\Address; -use Convoy\Models\Node; use Convoy\Services\Servers\NetworkService; +use Illuminate\Database\ConnectionInterface; +use Convoy\Models\Filters\AllowedNullableFilter; use Convoy\Transformers\Admin\AddressTransformer; -use Exception; -use Illuminate\Http\Request; -use Illuminate\Http\Response; -use Spatie\QueryBuilder\AllowedFilter; -use Spatie\QueryBuilder\QueryBuilder; +use Convoy\Exceptions\Repository\Proxmox\ProxmoxConnectionException; +use Convoy\Http\Requests\Admin\AddressPools\Addresses\UpdateAddressRequest; +use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; class AddressController extends Controller { - public function __construct(private NetworkService $networkService) + public function __construct(private NetworkService $networkService, private ConnectionInterface $connection) { } public function index(Request $request, Node $node) { - $addresses = QueryBuilder::for(Address::query()) + $addresses = QueryBuilder::for($node->addresses()) ->with('server') - ->where('ip_addresses.node_id', $node->id) - ->allowedFilters(['address', AllowedFilter::exact('type'), AllowedFilter::custom('*', new FiltersAddress), AllowedNullableFilter::exact('server_id')]) + ->defaultSort('-id') + ->allowedFilters( + ['address', AllowedFilter::exact('type'), AllowedFilter::custom( + '*', + new FiltersAddress, + ), AllowedNullableFilter::exact('server_id')], + ) ->paginate(min($request->query('per_page', 50), 100))->appends($request->query()); return fractal($addresses, new AddressTransformer)->parseIncludes($request->include)->respond(); } - public function store(StoreAddressRequest $request, Node $node) - { - $address = Address::create(array_merge(['node_id' => $node->id], $request->validated())); - - $address->load('server'); - - try { - if ($request->server_id) { - $this->networkService->syncSettings($address->server); - } - } catch (Exception $e) { - // do nothing - } - - return fractal($address, new AddressTransformer)->parseIncludes(['server'])->respond(); - } - public function update(UpdateAddressRequest $request, Node $node, Address $address) { - $address->load('server'); - - $oldServer = $address->server; - - $address->update($request->validated()); + $address = $this->connection->transaction(function () use ($request, $address) { + $oldLinkedServer = $address->server; - $address->refresh(); + $address->update($request->validated()); - $newServer = $address->server; - - try { - if ($oldServer?->id !== $newServer?->id) { - if ($oldServer) { - $this->networkService->syncSettings($oldServer); + try { + // Detach old server + if ($oldLinkedServer) { + $this->networkService->syncSettings($oldLinkedServer); } - if ($newServer) { - $this->networkService->syncSettings($newServer); + // Attach new server + if ($address->server) { + $this->networkService->syncSettings($address->server); + } + } catch (ProxmoxConnectionException) { + if ($oldLinkedServer && !$address->server) { + throw new ServiceUnavailableHttpException( + message: "Server {$oldLinkedServer->uuid} failed to sync network settings.", + ); + } elseif (!$oldLinkedServer && $address->server) { + throw new ServiceUnavailableHttpException( + message: "Server {$address->server->uuid} failed to sync network settings.", + ); + } elseif ($oldLinkedServer && $address->server) { + throw new ServiceUnavailableHttpException( + message: "Servers {$oldLinkedServer->uuid} and {$address->server->uuid} failed to sync network settings.", + ); } } - } catch (Exception $e) { - // do nothing - } - $address->load('server'); + return $address; + }); - return fractal($address, new AddressTransformer)->parseIncludes(['server'])->respond(); + return fractal($address, new AddressTransformer)->parseIncludes($request->include)->respond(); } - public function destroy(Node $node, Address $address): Response + public function destroy(Node $node, Address $address) { - $address->load('server'); - - $server = $address->server; - - $address->delete(); - - try { - if ($server) { - $this->networkService->syncSettings($server); + $this->connection->transaction(function () use ($address) { + $address->delete(); + + if ($address->server) { + try { + $this->networkService->syncSettings($address->server); + } catch (ProxmoxConnectionException) { + throw new ServiceUnavailableHttpException( + message: "Server {$address->server->uuid} failed to sync network settings.", + ); + } } - } catch (Exception $e) { - // do nothing - } + }); - return response()->noContent(); + return $this->returnNoContent(); } } diff --git a/app/Http/Requests/Admin/AddressPools/Addresses/StoreAddressRequest.php b/app/Http/Requests/Admin/AddressPools/Addresses/StoreAddressRequest.php index 5ecaa5eef0f..57d766a43dd 100644 --- a/app/Http/Requests/Admin/AddressPools/Addresses/StoreAddressRequest.php +++ b/app/Http/Requests/Admin/AddressPools/Addresses/StoreAddressRequest.php @@ -28,16 +28,18 @@ public function rules(): array public function withValidator(Validator $validator): void { - if (!$this->boolean('is_bulk_action')) { - $pool = $this->parameter('address_pool', AddressPool::class); + $rules = []; - $rules = [ - new ValidateAddressType($this->enum('type', AddressType::class), ['address', 'gateway']), - ]; + if ($this->boolean('is_bulk_action')) { + $rules[] = new ValidateAddressType($this->enum('type', AddressType::class), ['starting_address', 'ending_address', 'gateway']); + } + if (!$this->boolean('is_bulk_action')) { + $pool = $this->parameter('address_pool', AddressPool::class); + $rules[] = new ValidateAddressType($this->enum('type', AddressType::class), ['address', 'gateway']); $rules[] = new ValidateAddressUniqueness($pool->id); - - $validator->after($rules); } + + $validator->after($rules); } } diff --git a/app/Http/Requests/Admin/AddressPools/Addresses/UpdateAddressRequest.php b/app/Http/Requests/Admin/AddressPools/Addresses/UpdateAddressRequest.php index 448a5620783..1f5ab283778 100644 --- a/app/Http/Requests/Admin/AddressPools/Addresses/UpdateAddressRequest.php +++ b/app/Http/Requests/Admin/AddressPools/Addresses/UpdateAddressRequest.php @@ -7,6 +7,7 @@ use Convoy\Models\AddressPool; use Illuminate\Validation\Validator; use Convoy\Http\Requests\FormRequest; +use Convoy\Enums\Network\AddressType; use Convoy\Validation\ValidateAddressType; use Convoy\Validation\ValidateAddressUniqueness; @@ -25,8 +26,8 @@ public function withValidator(Validator $validator): void $address = $this->parameter('address', Address::class); $validator->after([ - new ValidateAddressType, - new ValidateAddressUniqueness($pool->id, $address->address), + new ValidateAddressType($this->enum('type', AddressType::class), ['address']), + new ValidateAddressUniqueness($pool->id, $address->address), ]); } } diff --git a/app/Http/Requests/Admin/Nodes/Addresses/StoreAddressRequest.php b/app/Http/Requests/Admin/Nodes/Addresses/StoreAddressRequest.php index ccb1a5bd060..58a9e497046 100644 --- a/app/Http/Requests/Admin/Nodes/Addresses/StoreAddressRequest.php +++ b/app/Http/Requests/Admin/Nodes/Addresses/StoreAddressRequest.php @@ -3,58 +3,43 @@ namespace Convoy\Http\Requests\Admin\Nodes\Addresses; use Convoy\Models\Address; +use Convoy\Models\AddressPool; +use Convoy\Enums\Network\AddressType; +use Convoy\Validation\ValidateAddressType; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Arr; use Illuminate\Validation\Validator; +use Convoy\Validation\ValidateAddressUniqueness; class StoreAddressRequest extends FormRequest { - /** - * Determine if the user is authorized to make this request. - */ - public function authorize(): bool - { - return true; - } - - /** - * Get the validation rules that apply to the request. - * - * @return array - */ public function rules(): array { - return Arr::except(Address::getRules(), ['node_id']); + $rules = Arr::except(Address::getRules(), 'address'); + + return [ + 'is_bulk_action' => 'sometimes|boolean', + 'starting_address' => 'required_if:is_bulk_action,1|exclude_if:is_bulk_action,0|ip', + 'ending_address' => 'required_if:is_bulk_action,1|exclude_if:is_bulk_action,0|ip', + 'address' => 'required_if:is_bulk_action,0|exclude_if:is_bulk_action,1|ip', + ...$rules, + ]; } - public function withValidator(Validator $validator) + public function withValidator(Validator $validator): void { - $validator->after(function ($validator) { - // if the type is ipv4 make sure both the address and gateway are valid ipv4 addresses and do the same for ipv6 - if ($this->type === 'ipv4') { - if (! filter_var($this->address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { - $validator->errors()->add('address', 'The address must be a valid IPv4 address.'); - } - - if (! filter_var($this->gateway, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { - $validator->errors()->add('gateway', 'The gateway must be a valid IPv4 address.'); - } - } elseif ($this->type === 'ipv6') { - if (! filter_var($this->address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { - $validator->errors()->add('address', 'The address must be a valid IPv6 address.'); - } - - if (! filter_var($this->gateway, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { - $validator->errors()->add('gateway', 'The gateway must be a valid IPv6 address.'); - } - } - - $nodeId = $this->route()->originalParameter('node'); - - // check for duplicate addresses - if (Address::where([['node_id', '=', $nodeId], ['address', '=', $this->address]])->exists()) { - $validator->errors()->add('address', 'The address has already been imported.'); - } - }); + $rules = []; + + if ($this->boolean('is_bulk_action')) { + $rules[] = new ValidateAddressType($this->enum('type', AddressType::class), ['starting_address', 'ending_address', 'gateway']); + } + + if (!$this->boolean('is_bulk_action')) { + $pool = $this->parameter('address_pool', AddressPool::class); + $rules[] = new ValidateAddressType($this->enum('type', AddressType::class), ['address', 'gateway']); + $rules[] = new ValidateAddressUniqueness($pool->id); + } + + $validator->after($rules); } } diff --git a/app/Http/Requests/Admin/Nodes/Addresses/UpdateAddressRequest.php b/app/Http/Requests/Admin/Nodes/Addresses/UpdateAddressRequest.php index 19a43f1f014..2fc3b057c05 100644 --- a/app/Http/Requests/Admin/Nodes/Addresses/UpdateAddressRequest.php +++ b/app/Http/Requests/Admin/Nodes/Addresses/UpdateAddressRequest.php @@ -2,60 +2,32 @@ namespace Convoy\Http\Requests\Admin\Nodes\Addresses; +use Convoy\Models\AddressPool; use Convoy\Http\Requests\FormRequest; use Convoy\Models\Address; use Illuminate\Support\Arr; use Illuminate\Validation\Validator; +use Convoy\Enums\Network\AddressType; +use Convoy\Validation\ValidateAddressType; +use Convoy\Validation\ValidateAddressUniqueness; class UpdateAddressRequest extends FormRequest { - /** - * Determine if the user is authorized to make this request. - */ - public function authorize(): bool - { - return true; - } - - /** - * Get the validation rules that apply to the request. - * - * @return array - */ public function rules(): array { - return Arr::except(Address::getRulesForUpdate($this->parameter('address', Address::class)), ['node_id']); + $rules = Address::getRulesForUpdate($this->parameter('address', Address::class)); + + return Arr::except($rules, 'address_pool_id'); } public function withValidator(Validator $validator) { - $validator->after(function ($validator) { - // if the type is ipv4 make sure both the address and gateway are valid ipv4 addresses and do the same for ipv6 - if ($this->type === 'ipv4') { - if (! filter_var($this->address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { - $validator->errors()->add('address', 'The address must be a valid IPv4 address.'); - } - - if (! filter_var($this->gateway, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { - $validator->errors()->add('gateway', 'The gateway must be a valid IPv4 address.'); - } - } elseif ($this->type === 'ipv6') { - if (! filter_var($this->address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { - $validator->errors()->add('address', 'The address must be a valid IPv6 address.'); - } - - if (! filter_var($this->gateway, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { - $validator->errors()->add('gateway', 'The gateway must be a valid IPv6 address.'); - } - } - - $address = $this->parameter('address', Address::class); - $nodeId = $this->route()->originalParameter('node'); + $pool = $this->parameter('address_pool', AddressPool::class); + $address = $this->parameter('address', Address::class); - // check for duplicate addresses - if ($address->address !== $this->address && Address::where([['node_id', '=', $nodeId], ['address', '=', $this->address]])->exists()) { - $validator->errors()->add('address', 'The address has already been imported.'); - } - }); + $validator->after([ + new ValidateAddressType($this->enum('type', AddressType::class), ['address']), + new ValidateAddressUniqueness($pool->id, $address->address), + ]); } } diff --git a/app/Repositories/Eloquent/AddressRepository.php b/app/Repositories/Eloquent/AddressRepository.php index cc882b17801..ee7f40577ee 100644 --- a/app/Repositories/Eloquent/AddressRepository.php +++ b/app/Repositories/Eloquent/AddressRepository.php @@ -14,7 +14,7 @@ public function model(): string return Address::class; } - public function createIPv4AddressesInBulk( + public function bulkCreateIPv4Addresses( string $startingAddress, string $endingAddress, int $addressPoolId, @@ -65,7 +65,7 @@ public function createIPv4AddressesInBulk( ); } - public function createIPv6AddressesInBulk( + public function bulkCreateIPv6Addresses( string $startingAddress, string $endingAddress, int $addressPoolId, diff --git a/app/Services/Nodes/Addresses/AddressHelpers.php b/app/Services/Nodes/Addresses/AddressHelpers.php deleted file mode 100644 index 85a4c2662c0..00000000000 --- a/app/Services/Nodes/Addresses/AddressHelpers.php +++ /dev/null @@ -1,45 +0,0 @@ -existingAddress) { if (Address::where([['address_pool_id', '=', $this->addressPoolId], ['address', '=', $data['address']]], )->exists()) { - $validator->errors()->add('address', 'This address has already been imported.'); + $validator->errors()->add('address', __('validation.unique_exists', ['attribute' => 'address'])); } } else { if ($this->existingAddress !== $data['address'] && Address::where( [['address_pool_id', '=', $this->addressPoolId], ['address', '=', $data['address']]], )->exists()) { - $validator->errors()->add('address', 'This address has already been imported.'); + $validator->errors()->add('address', __('validation.unique_exists', ['attribute' => 'address'])); } } } diff --git a/lang/en_US/validation.php b/lang/en_US/validation.php index 93e7f2b6d3c..09bf66a4d48 100644 --- a/lang/en_US/validation.php +++ b/lang/en_US/validation.php @@ -140,6 +140,7 @@ 'string' => 'The :attribute must be a string.', 'timezone' => 'The :attribute must be a valid timezone.', 'unique' => 'The :attribute has already been taken.', + 'unique_exists' => 'The :attribute already exists.', 'uploaded' => 'The :attribute failed to upload.', 'url' => 'The :attribute must be a valid URL.', 'uuid' => 'The :attribute must be a valid UUID.', diff --git a/package-lock.json b/package-lock.json index 29f18c6cce2..00d46392639 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "name": "www", "dependencies": { "@dnd-kit/core": "^6.0.5", "@dnd-kit/modifiers": "^6.0.0", @@ -50,6 +51,7 @@ "zod-i18n-map": "^2.9.0" }, "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "^4.2.1", "@types/debounce": "^1.2.1", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", @@ -72,11 +74,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -120,12 +123,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -163,31 +167,31 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -242,28 +246,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -290,12 +294,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -303,9 +307,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -353,31 +357,31 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -386,12 +390,12 @@ } }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1195,47 +1199,15 @@ } }, "node_modules/@next/env": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.5.tgz", - "integrity": "sha512-F3KLtiDrUslAZhTYTh8Zk5ZaavbYwLUn3NYPBnOjAXU8hWm0QVGVzKIOuURQ098ofRU4e9oglf3Sj9pFx5nI5w==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.1.tgz", + "integrity": "sha512-Ms8ZswqY65/YfcjrlcIwMPD7Rg/dVjdLapMcSHG26W6O67EJDF435ShW4H4LXi1xKO1oRc97tLXUpx8jpLe86A==", "peer": true }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.0.5.tgz", - "integrity": "sha512-YO691dxHlviy6H0eghgwqn+5kU9J3iQnKERHTDSppqjjGDBl6ab4wz9XfI5AhljjkaTg3TknHoIEWFDoZ4Ve8g==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.0.5.tgz", - "integrity": "sha512-ugbwffkUmp8cd2afehDC8LtQeFUxElRUBBngfB5UYSWBx18HW4OgzkPFIY8jUBH16zifvGZWXbICXJWDHrOLtw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.5.tgz", - "integrity": "sha512-mshlh8QOtOalfZbc17uNAftWgqHTKnrv6QUwBe+mpGz04eqsSUzVz1JGZEdIkmuDxOz00cK2NPoc+VHDXh99IQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.1.tgz", + "integrity": "sha512-JyxnGCS4qT67hdOKQ0CkgFTp+PXub5W1wsGvIq98TNbF3YEIN7iDekYhYsZzc8Ov0pWEsghQt+tANdidITCLaw==", "cpu": [ "arm64" ], @@ -1249,9 +1221,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.0.5.tgz", - "integrity": "sha512-SfigOKW4Z2UB3ruUPyvrlDIkcJq1hiw1wvYApWugD+tQsAkYZKEoz+/8emCmeYZ6Gwgi1WHV+z52Oj8u7bEHPg==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.1.tgz", + "integrity": "sha512-625Z7bb5AyIzswF9hvfZWa+HTwFZw+Jn3lOBNZB87lUS0iuCYDHqk3ujuHCkiyPtSC0xFBtYDLcrZ11mF/ap3w==", "cpu": [ "x64" ], @@ -1264,42 +1236,10 @@ "node": ">= 10" } }, - "node_modules/@next/swc-freebsd-x64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.0.5.tgz", - "integrity": "sha512-0NJg8HZr4yG8ynmMGFXQf+Mahvq4ZgBmUwSlLXXymgxEQgH17erH/LoR69uITtW+KTsALgk9axEt5AAabM4ucg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.0.5.tgz", - "integrity": "sha512-Cye+h3oDT3NDWjACMlRaolL8fokpKie34FlPj9nfoW7bYKmoMBY1d4IO/GgBF+5xEl7HkH0Ny/qex63vQ0pN+A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.0.5.tgz", - "integrity": "sha512-5BfDS/VoRDR5QUGG9oedOCEZGmV2zxUVFYLUJVPMSMeIgqkjxWQBiG2BUHZI6/LGk9yvHmjx7BTvtBCLtRg6IQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.1.tgz", + "integrity": "sha512-iVpn3KG3DprFXzVHM09kvb//4CNNXBQ9NB/pTm8LO+vnnnaObnzFdS5KM+w1okwa32xH0g8EvZIhoB3fI3mS1g==", "cpu": [ "arm64" ], @@ -1313,9 +1253,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.0.5.tgz", - "integrity": "sha512-xenvqlXz+KxVKAB1YR723gnVNszpsCvKZkiFFaAYqDGJ502YuqU2fwLsaSm/ASRizNcBYeo9HPLTyc3r/9cdMQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.1.tgz", + "integrity": "sha512-mVsGyMxTLWZXyD5sen6kGOTYVOO67lZjLApIj/JsTEEohDDt1im2nkspzfV5MvhfS7diDw6Rp/xvAQaWZTv1Ww==", "cpu": [ "arm64" ], @@ -1329,9 +1269,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.0.5.tgz", - "integrity": "sha512-9Ahi1bbdXwhrWQmOyoTod23/hhK05da/FzodiNqd6drrMl1y7+RujoEcU8Dtw3H1mGWB+yuTlWo8B4Iba8hqiQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.1.tgz", + "integrity": "sha512-wMqf90uDWN001NqCM/auRl3+qVVeKfjJdT9XW+RMIOf+rhUzadmYJu++tp2y+hUbb6GTRhT+VjQzcgg/QTD9NQ==", "cpu": [ "x64" ], @@ -1345,9 +1285,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.0.5.tgz", - "integrity": "sha512-V+1mnh49qmS9fOZxVRbzjhBEz9IUGJ7AQ80JPWAYQM5LI4TxfdiF4APLPvJ52rOmNeTqnVz1bbKtVOso+7EZ4w==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.1.tgz", + "integrity": "sha512-ol1X1e24w4j4QwdeNjfX0f+Nza25n+ymY0T2frTyalVczUmzkVD7QGgPTZMHfR1aLrO69hBs0G3QBYaj22J5GQ==", "cpu": [ "x64" ], @@ -1361,9 +1301,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.0.5.tgz", - "integrity": "sha512-wRE9rkp7I+/3Jf2T9PFIJOKq3adMWYEFkPOA7XAkUfYbQHlDJm/U5cVCWUsKByyQq5RThwufI91sgd19MfxRxg==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.1.tgz", + "integrity": "sha512-WEmTEeWs6yRUEnUlahTgvZteh5RJc4sEjCQIodJlZZ5/VJwVP8p2L7l6VhzQhT4h7KvLx/Ed4UViBdne6zpIsw==", "cpu": [ "arm64" ], @@ -1377,9 +1317,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.0.5.tgz", - "integrity": "sha512-Q1XQSLEhFuFhkKFdJIGt7cYQ4T3u6P5wrtUNreg5M+7P+fjSiC8+X+Vjcw+oebaacsdl0pWZlK+oACGafush1w==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.1.tgz", + "integrity": "sha512-oFpHphN4ygAgZUKjzga7SoH2VGbEJXZa/KL8bHCAwCjDWle6R1SpiGOdUdA8EJ9YsG1TYWpzY6FTbUA+iAJeww==", "cpu": [ "ia32" ], @@ -1393,9 +1333,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.0.5.tgz", - "integrity": "sha512-t5gRblrwwiNZP6cT7NkxlgxrFgHWtv9ei5vUraCLgBqzvIsa7X+PnarZUeQCXqz6Jg9JSGGT9j8lvzD97UqeJQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.1.tgz", + "integrity": "sha512-FFp3nOJ/5qSpeWT0BZQ+YE1pSMk4IMpkME/1DwKBwhg4mJLB9L+6EXuJi4JEwaJdl5iN+UUlmUD3IsR1kx5fAg==", "cpu": [ "x64" ], @@ -1769,9 +1709,9 @@ } }, "node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", "peer": true, "dependencies": { "tslib": "^2.4.0" @@ -1819,6 +1759,56 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@trivago/prettier-plugin-sort-imports": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.2.1.tgz", + "integrity": "sha512-iuy2MPVURGdxILTchHr15VAioItuYBejKfcTmQFlxIuqA7jeaT6ngr5aUIG6S6U096d6a6lJCgaOwlRrPLlOPg==", + "dev": true, + "dependencies": { + "@babel/generator": "7.17.7", + "@babel/parser": "^7.20.5", + "@babel/traverse": "7.23.2", + "@babel/types": "7.17.0", + "javascript-natural-sort": "0.7.1", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "@vue/compiler-sfc": "3.x", + "prettier": "2.x - 3.x" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/generator": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -2124,6 +2114,18 @@ "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==", "peer": true }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "peer": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2791,6 +2793,12 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "peer": true + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -2799,6 +2807,12 @@ "node": ">=4" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "peer": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -3057,6 +3071,12 @@ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "peer": true }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3222,50 +3242,44 @@ } }, "node_modules/next": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/next/-/next-13.0.5.tgz", - "integrity": "sha512-awpc3DkphyKydwCotcBnuKwh6hMqkT5xdiBK4OatJtOZurDPBYLP62jtM2be/4OunpmwIbsS0Eyv+ZGU97ciEg==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/next/-/next-14.0.1.tgz", + "integrity": "sha512-s4YaLpE4b0gmb3ggtmpmV+wt+lPRuGtANzojMQ2+gmBpgX9w5fTbjsy6dXByBuENsdCX5pukZH/GxdFgO62+pA==", "peer": true, "dependencies": { - "@next/env": "13.0.5", - "@swc/helpers": "0.4.14", + "@next/env": "14.0.1", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.0" + "postcss": "8.4.31", + "styled-jsx": "5.1.1", + "watchpack": "2.4.0" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=14.6.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-android-arm-eabi": "13.0.5", - "@next/swc-android-arm64": "13.0.5", - "@next/swc-darwin-arm64": "13.0.5", - "@next/swc-darwin-x64": "13.0.5", - "@next/swc-freebsd-x64": "13.0.5", - "@next/swc-linux-arm-gnueabihf": "13.0.5", - "@next/swc-linux-arm64-gnu": "13.0.5", - "@next/swc-linux-arm64-musl": "13.0.5", - "@next/swc-linux-x64-gnu": "13.0.5", - "@next/swc-linux-x64-musl": "13.0.5", - "@next/swc-win32-arm64-msvc": "13.0.5", - "@next/swc-win32-ia32-msvc": "13.0.5", - "@next/swc-win32-x64-msvc": "13.0.5" + "@next/swc-darwin-arm64": "14.0.1", + "@next/swc-darwin-x64": "14.0.1", + "@next/swc-linux-arm64-gnu": "14.0.1", + "@next/swc-linux-arm64-musl": "14.0.1", + "@next/swc-linux-x64-gnu": "14.0.1", + "@next/swc-linux-x64-musl": "14.0.1", + "@next/swc-win32-arm64-msvc": "14.0.1", + "@next/swc-win32-ia32-msvc": "14.0.1", + "@next/swc-win32-x64-msvc": "14.0.1" }, "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", + "@opentelemetry/api": "^1.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { + "@opentelemetry/api": { "optional": true }, "sass": { @@ -3273,30 +3287,6 @@ } } }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -3442,9 +3432,9 @@ } }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -3955,9 +3945,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -3978,6 +3968,15 @@ "node": ">=0.10.0" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "peer": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -4027,9 +4026,9 @@ } }, "node_modules/styled-jsx": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz", - "integrity": "sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "peer": true, "dependencies": { "client-only": "0.0.1" @@ -4468,6 +4467,19 @@ "node": ">=0.10.0" } }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -4602,9 +4614,9 @@ } }, "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -4630,11 +4642,12 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -4665,12 +4678,13 @@ } }, "@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "requires": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -4698,25 +4712,25 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-imports": { @@ -4756,22 +4770,22 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -4789,19 +4803,19 @@ } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" }, "@babel/plugin-syntax-jsx": { "version": "7.18.6", @@ -4828,39 +4842,39 @@ } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -5343,99 +5357,71 @@ "requires": {} }, "@next/env": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.5.tgz", - "integrity": "sha512-F3KLtiDrUslAZhTYTh8Zk5ZaavbYwLUn3NYPBnOjAXU8hWm0QVGVzKIOuURQ098ofRU4e9oglf3Sj9pFx5nI5w==", - "peer": true - }, - "@next/swc-android-arm-eabi": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.0.5.tgz", - "integrity": "sha512-YO691dxHlviy6H0eghgwqn+5kU9J3iQnKERHTDSppqjjGDBl6ab4wz9XfI5AhljjkaTg3TknHoIEWFDoZ4Ve8g==", - "optional": true, - "peer": true - }, - "@next/swc-android-arm64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.0.5.tgz", - "integrity": "sha512-ugbwffkUmp8cd2afehDC8LtQeFUxElRUBBngfB5UYSWBx18HW4OgzkPFIY8jUBH16zifvGZWXbICXJWDHrOLtw==", - "optional": true, + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.1.tgz", + "integrity": "sha512-Ms8ZswqY65/YfcjrlcIwMPD7Rg/dVjdLapMcSHG26W6O67EJDF435ShW4H4LXi1xKO1oRc97tLXUpx8jpLe86A==", "peer": true }, "@next/swc-darwin-arm64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.5.tgz", - "integrity": "sha512-mshlh8QOtOalfZbc17uNAftWgqHTKnrv6QUwBe+mpGz04eqsSUzVz1JGZEdIkmuDxOz00cK2NPoc+VHDXh99IQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.1.tgz", + "integrity": "sha512-JyxnGCS4qT67hdOKQ0CkgFTp+PXub5W1wsGvIq98TNbF3YEIN7iDekYhYsZzc8Ov0pWEsghQt+tANdidITCLaw==", "optional": true, "peer": true }, "@next/swc-darwin-x64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.0.5.tgz", - "integrity": "sha512-SfigOKW4Z2UB3ruUPyvrlDIkcJq1hiw1wvYApWugD+tQsAkYZKEoz+/8emCmeYZ6Gwgi1WHV+z52Oj8u7bEHPg==", - "optional": true, - "peer": true - }, - "@next/swc-freebsd-x64": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.0.5.tgz", - "integrity": "sha512-0NJg8HZr4yG8ynmMGFXQf+Mahvq4ZgBmUwSlLXXymgxEQgH17erH/LoR69uITtW+KTsALgk9axEt5AAabM4ucg==", - "optional": true, - "peer": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.0.5.tgz", - "integrity": "sha512-Cye+h3oDT3NDWjACMlRaolL8fokpKie34FlPj9nfoW7bYKmoMBY1d4IO/GgBF+5xEl7HkH0Ny/qex63vQ0pN+A==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.1.tgz", + "integrity": "sha512-625Z7bb5AyIzswF9hvfZWa+HTwFZw+Jn3lOBNZB87lUS0iuCYDHqk3ujuHCkiyPtSC0xFBtYDLcrZ11mF/ap3w==", "optional": true, "peer": true }, "@next/swc-linux-arm64-gnu": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.0.5.tgz", - "integrity": "sha512-5BfDS/VoRDR5QUGG9oedOCEZGmV2zxUVFYLUJVPMSMeIgqkjxWQBiG2BUHZI6/LGk9yvHmjx7BTvtBCLtRg6IQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.1.tgz", + "integrity": "sha512-iVpn3KG3DprFXzVHM09kvb//4CNNXBQ9NB/pTm8LO+vnnnaObnzFdS5KM+w1okwa32xH0g8EvZIhoB3fI3mS1g==", "optional": true, "peer": true }, "@next/swc-linux-arm64-musl": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.0.5.tgz", - "integrity": "sha512-xenvqlXz+KxVKAB1YR723gnVNszpsCvKZkiFFaAYqDGJ502YuqU2fwLsaSm/ASRizNcBYeo9HPLTyc3r/9cdMQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.1.tgz", + "integrity": "sha512-mVsGyMxTLWZXyD5sen6kGOTYVOO67lZjLApIj/JsTEEohDDt1im2nkspzfV5MvhfS7diDw6Rp/xvAQaWZTv1Ww==", "optional": true, "peer": true }, "@next/swc-linux-x64-gnu": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.0.5.tgz", - "integrity": "sha512-9Ahi1bbdXwhrWQmOyoTod23/hhK05da/FzodiNqd6drrMl1y7+RujoEcU8Dtw3H1mGWB+yuTlWo8B4Iba8hqiQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.1.tgz", + "integrity": "sha512-wMqf90uDWN001NqCM/auRl3+qVVeKfjJdT9XW+RMIOf+rhUzadmYJu++tp2y+hUbb6GTRhT+VjQzcgg/QTD9NQ==", "optional": true, "peer": true }, "@next/swc-linux-x64-musl": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.0.5.tgz", - "integrity": "sha512-V+1mnh49qmS9fOZxVRbzjhBEz9IUGJ7AQ80JPWAYQM5LI4TxfdiF4APLPvJ52rOmNeTqnVz1bbKtVOso+7EZ4w==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.1.tgz", + "integrity": "sha512-ol1X1e24w4j4QwdeNjfX0f+Nza25n+ymY0T2frTyalVczUmzkVD7QGgPTZMHfR1aLrO69hBs0G3QBYaj22J5GQ==", "optional": true, "peer": true }, "@next/swc-win32-arm64-msvc": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.0.5.tgz", - "integrity": "sha512-wRE9rkp7I+/3Jf2T9PFIJOKq3adMWYEFkPOA7XAkUfYbQHlDJm/U5cVCWUsKByyQq5RThwufI91sgd19MfxRxg==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.1.tgz", + "integrity": "sha512-WEmTEeWs6yRUEnUlahTgvZteh5RJc4sEjCQIodJlZZ5/VJwVP8p2L7l6VhzQhT4h7KvLx/Ed4UViBdne6zpIsw==", "optional": true, "peer": true }, "@next/swc-win32-ia32-msvc": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.0.5.tgz", - "integrity": "sha512-Q1XQSLEhFuFhkKFdJIGt7cYQ4T3u6P5wrtUNreg5M+7P+fjSiC8+X+Vjcw+oebaacsdl0pWZlK+oACGafush1w==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.1.tgz", + "integrity": "sha512-oFpHphN4ygAgZUKjzga7SoH2VGbEJXZa/KL8bHCAwCjDWle6R1SpiGOdUdA8EJ9YsG1TYWpzY6FTbUA+iAJeww==", "optional": true, "peer": true }, "@next/swc-win32-x64-msvc": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.0.5.tgz", - "integrity": "sha512-t5gRblrwwiNZP6cT7NkxlgxrFgHWtv9ei5vUraCLgBqzvIsa7X+PnarZUeQCXqz6Jg9JSGGT9j8lvzD97UqeJQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.1.tgz", + "integrity": "sha512-FFp3nOJ/5qSpeWT0BZQ+YE1pSMk4IMpkME/1DwKBwhg4mJLB9L+6EXuJi4JEwaJdl5iN+UUlmUD3IsR1kx5fAg==", "optional": true, "peer": true }, @@ -5657,9 +5643,9 @@ "optional": true }, "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", "peer": true, "requires": { "tslib": "^2.4.0" @@ -5686,6 +5672,43 @@ "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.7.0.tgz", "integrity": "sha512-DRiRbOAmDHapzUBd4/C4Yy+FTug4fdGp5sdZWWfCq4wxRoaXQraQgbzmK23a3QcbwLFtLeNezPkZrqbJWuX+VA==" }, + "@trivago/prettier-plugin-sort-imports": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.2.1.tgz", + "integrity": "sha512-iuy2MPVURGdxILTchHr15VAioItuYBejKfcTmQFlxIuqA7jeaT6ngr5aUIG6S6U096d6a6lJCgaOwlRrPLlOPg==", + "dev": true, + "requires": { + "@babel/generator": "7.17.7", + "@babel/parser": "^7.20.5", + "@babel/traverse": "7.23.2", + "@babel/types": "7.17.0", + "javascript-natural-sort": "0.7.1", + "lodash": "^4.17.21" + }, + "dependencies": { + "@babel/generator": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + } + } + }, "@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -5913,6 +5936,15 @@ "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==", "peer": true }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "peer": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -6385,11 +6417,23 @@ "is-glob": "^4.0.3" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "peer": true + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "peer": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -6575,6 +6619,12 @@ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "peer": true }, + "javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -6692,42 +6742,27 @@ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" }, "next": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/next/-/next-13.0.5.tgz", - "integrity": "sha512-awpc3DkphyKydwCotcBnuKwh6hMqkT5xdiBK4OatJtOZurDPBYLP62jtM2be/4OunpmwIbsS0Eyv+ZGU97ciEg==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/next/-/next-14.0.1.tgz", + "integrity": "sha512-s4YaLpE4b0gmb3ggtmpmV+wt+lPRuGtANzojMQ2+gmBpgX9w5fTbjsy6dXByBuENsdCX5pukZH/GxdFgO62+pA==", "peer": true, "requires": { - "@next/env": "13.0.5", - "@next/swc-android-arm-eabi": "13.0.5", - "@next/swc-android-arm64": "13.0.5", - "@next/swc-darwin-arm64": "13.0.5", - "@next/swc-darwin-x64": "13.0.5", - "@next/swc-freebsd-x64": "13.0.5", - "@next/swc-linux-arm-gnueabihf": "13.0.5", - "@next/swc-linux-arm64-gnu": "13.0.5", - "@next/swc-linux-arm64-musl": "13.0.5", - "@next/swc-linux-x64-gnu": "13.0.5", - "@next/swc-linux-x64-musl": "13.0.5", - "@next/swc-win32-arm64-msvc": "13.0.5", - "@next/swc-win32-ia32-msvc": "13.0.5", - "@next/swc-win32-x64-msvc": "13.0.5", - "@swc/helpers": "0.4.14", + "@next/env": "14.0.1", + "@next/swc-darwin-arm64": "14.0.1", + "@next/swc-darwin-x64": "14.0.1", + "@next/swc-linux-arm64-gnu": "14.0.1", + "@next/swc-linux-arm64-musl": "14.0.1", + "@next/swc-linux-x64-gnu": "14.0.1", + "@next/swc-linux-x64-musl": "14.0.1", + "@next/swc-win32-arm64-msvc": "14.0.1", + "@next/swc-win32-ia32-msvc": "14.0.1", + "@next/swc-win32-x64-msvc": "14.0.1", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.0" - }, - "dependencies": { - "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "peer": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - } + "postcss": "8.4.31", + "styled-jsx": "5.1.1", + "watchpack": "2.4.0" } }, "node-fetch": { @@ -6825,9 +6860,9 @@ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" }, "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -7134,9 +7169,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" }, "source-map": { "version": "0.5.7", @@ -7148,6 +7183,12 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "peer": true + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -7191,9 +7232,9 @@ } }, "styled-jsx": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz", - "integrity": "sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "peer": true, "requires": { "client-only": "0.0.1" @@ -7474,6 +7515,16 @@ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "peer": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -7577,9 +7628,9 @@ } }, "zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==" + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==" }, "zod-i18n-map": { "version": "2.9.0", diff --git a/resources/scripts/api/admin/addressPools/addresses/createAddress.ts b/resources/scripts/api/admin/addressPools/addresses/createAddress.ts index 706224c1a6b..7ed4030aada 100644 --- a/resources/scripts/api/admin/addressPools/addresses/createAddress.ts +++ b/resources/scripts/api/admin/addressPools/addresses/createAddress.ts @@ -36,7 +36,7 @@ type CreateAddressParameters = z.infer & { const createAddress = async ( poolId: number, { isBulkAction, startingAddress, endingAddress, macAddress, serverId, include, ...payload }: CreateAddressParameters -): Promise
=> { +): Promise
=> { const { data: { data }, } = await http.post( @@ -56,7 +56,7 @@ const createAddress = async ( } ) - return Array.isArray(data) ? data.map(rawDataToAddress) : rawDataToAddress(data) + return data ? rawDataToAddress(data) : null } export default createAddress diff --git a/resources/scripts/api/admin/addressPools/addresses/updateAddressPool.ts b/resources/scripts/api/admin/addressPools/addresses/updateAddress.ts similarity index 100% rename from resources/scripts/api/admin/addressPools/addresses/updateAddressPool.ts rename to resources/scripts/api/admin/addressPools/addresses/updateAddress.ts diff --git a/resources/scripts/api/admin/addressPools/addresses/useAddressPoolSWR.ts b/resources/scripts/api/admin/addressPools/useAddressPoolSWR.ts similarity index 100% rename from resources/scripts/api/admin/addressPools/addresses/useAddressPoolSWR.ts rename to resources/scripts/api/admin/addressPools/useAddressPoolSWR.ts diff --git a/resources/scripts/api/admin/nodes/useNodeSWR.ts b/resources/scripts/api/admin/nodes/useNodeSWR.ts new file mode 100644 index 00000000000..b4c187bcce5 --- /dev/null +++ b/resources/scripts/api/admin/nodes/useNodeSWR.ts @@ -0,0 +1,21 @@ +import useSWR, { Key, SWRResponse } from 'swr' +import { useMatch, useParams } from 'react-router-dom' +import { Optimistic } from '@/lib/swr' +import { AddressPool } from '@/api/admin/addressPools/getAddressPools' +import getAddressPool from '@/api/admin/addressPools/getAddressPool' +import { match } from '@headlessui/react/dist/utils/match' +import getNode from '@/api/admin/nodes/getNode' +import { Node } from '@/api/admin/nodes/getNodes' + +export const getKey = (id: number): Key => ['admin.nodes', id] + +const useNodeSWR = () => { + const { nodeId } = useParams() + const id = parseInt(nodeId!) + + return useSWR(getKey(id), () => getNode(id), { + revalidateOnMount: false, + }) as Optimistic> +} + +export default useNodeSWR diff --git a/resources/scripts/components/admin/ipam/PoolContentBlock.tsx b/resources/scripts/components/admin/ipam/PoolContentBlock.tsx index f77453f1800..e1d7fbc5f1e 100644 --- a/resources/scripts/components/admin/ipam/PoolContentBlock.tsx +++ b/resources/scripts/components/admin/ipam/PoolContentBlock.tsx @@ -1,5 +1,5 @@ import PageContentBlock, { PageContentBlockProps } from '@/components/elements/PageContentBlock' -import useAddressPoolSWR from '@/api/admin/addressPools/addresses/useAddressPoolSWR' +import useAddressPoolSWR from '@/api/admin/addressPools/useAddressPoolSWR' import Breadcrumbs from '@/components/elements/Breadcrumbs' interface Props extends PageContentBlockProps { diff --git a/resources/scripts/components/admin/ipam/addresses/CreateAddressModal.tsx b/resources/scripts/components/admin/ipam/addresses/CreateAddressModal.tsx index f73ccd40cdc..49117882481 100644 --- a/resources/scripts/components/admin/ipam/addresses/CreateAddressModal.tsx +++ b/resources/scripts/components/admin/ipam/addresses/CreateAddressModal.tsx @@ -1,4 +1,4 @@ -import useAddressPoolSWR from '@/api/admin/addressPools/addresses/useAddressPoolSWR' +import useAddressPoolSWR from '@/api/admin/addressPools/useAddressPoolSWR' import FlashMessageRender from '@/components/elements/FlashMessageRenderer' import Modal from '@/components/elements/Modal' import RadioGroupForm from '@/components/elements/forms/RadioGroupForm' @@ -26,25 +26,6 @@ interface Props { mutate: KeyedMutator } -const calculateAddressBlockSize = (address: string, cidr: number): number => { - const isIPv4 = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(address) - const isIPv6 = /^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$/.test(address) - - if (!isIPv4 && !isIPv6) { - return 0 - } - - if (isIPv4) { - if (address.endsWith('.0')) { - return Math.pow(2, 32 - cidr) - } else { - return 0 - } - } else { - return 2 ** (128 - cidr) - } -} - const CreateAddressModal = ({ open, onClose, mutate }: Props) => { const { t: tStrings } = useTranslation('strings') const { t } = useTranslation('admin.addressPools.addresses') @@ -94,23 +75,19 @@ const CreateAddressModal = ({ open, onClose, mutate }: Props) => { ...data, }) - mutate(data => { - if (!data) return data - if (data.pagination.currentPage !== 1) return data - - let items = data.items - - if (Array.isArray(address)) { - items = [...address, ...items] - } else { - items = [address, ...items] - } - - return { - ...data, - items, - } - }, false) + if (address) { + mutate(data => { + if (!data) return data + if (data.pagination.currentPage !== 1) return data + + return { + ...data, + items: [address, ...data.items], + } + }, false) + } else { + mutate() + } handleClose() } catch (e) { diff --git a/resources/scripts/components/admin/ipam/addresses/EditAddressModal.tsx b/resources/scripts/components/admin/ipam/addresses/EditAddressModal.tsx index d2b7ed9641a..82b431e1494 100644 --- a/resources/scripts/components/admin/ipam/addresses/EditAddressModal.tsx +++ b/resources/scripts/components/admin/ipam/addresses/EditAddressModal.tsx @@ -1,4 +1,4 @@ -import useAddressPoolSWR from '@/api/admin/addressPools/addresses/useAddressPoolSWR' +import useAddressPoolSWR from '@/api/admin/addressPools/useAddressPoolSWR' import FlashMessageRender from '@/components/elements/FlashMessageRenderer' import Modal from '@/components/elements/Modal' import RadioGroupForm from '@/components/elements/forms/RadioGroupForm' @@ -16,7 +16,7 @@ import { KeyedMutator, mutate } from 'swr' import { AddressResponse } from '@/api/admin/nodes/addresses/getAddresses' import { Address } from '@/api/server/getServer' import { useEffect } from 'react' -import updateAddress from '@/api/admin/addressPools/addresses/updateAddressPool' +import updateAddress from '@/api/admin/addressPools/addresses/updateAddress' interface Props { address: Address | null diff --git a/resources/scripts/components/admin/nodes/addresses/CreateAddressModal.tsx b/resources/scripts/components/admin/nodes/addresses/CreateAddressModal.tsx new file mode 100644 index 00000000000..41cd446b423 --- /dev/null +++ b/resources/scripts/components/admin/nodes/addresses/CreateAddressModal.tsx @@ -0,0 +1,153 @@ +import FlashMessageRender from '@/components/elements/FlashMessageRenderer' +import Modal from '@/components/elements/Modal' +import RadioGroupForm from '@/components/elements/forms/RadioGroupForm' +import TextInputForm from '@/components/elements/forms/TextInputForm' +import Radio from '@/components/elements/inputs/Radio' +import { useFlashKey } from '@/util/useFlash' +import { zodResolver } from '@hookform/resolvers/zod' +import { FormProvider, useForm } from 'react-hook-form' +import { Trans, useTranslation } from 'react-i18next' +import { z } from 'zod' +import ServersSelectForm from '@/components/admin/ipam/addresses/ServersSelectForm' +import createAddress, { schema } from '@/api/admin/addressPools/addresses/createAddress' +import { KeyedMutator } from 'swr' +import { AddressResponse } from '@/api/admin/nodes/addresses/getAddresses' +import { useMemo } from 'react' +import { AddressType } from '@/api/server/getServer' +import SegmentedControl from '@/components/elements/SegmentedControl' +import { countIPsInRange } from '@/util/helpers' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' + +interface Props { + open: boolean + onClose: () => void + mutate: KeyedMutator +} + +const CreateAddressModal = ({ open, onClose, mutate }: Props) => { + const { t: tStrings } = useTranslation('strings') + const { t } = useTranslation('admin.addressPools.addresses') + const { data: node } = useNodeSWR() + const { clearFlashes, clearAndAddHttpError } = useFlashKey(`admin.nodes.${node.id}`) + + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: { + isBulkAction: false, + type: 'ipv4', + startingAddress: '', + endingAddress: '', + address: '', + cidr: '', + gateway: '', + macAddress: '', + serverId: '', + }, + }) + + const watchIsBulkAction = form.watch('isBulkAction') + const watchType = form.watch('type') as AddressType + const watchStartingAddress = form.watch('startingAddress') + const watchEndingAddress = form.watch('endingAddress') + + const addressCount = useMemo(() => { + if (!watchIsBulkAction) return 0 + + return countIPsInRange(watchType, watchStartingAddress, watchEndingAddress) + }, [watchIsBulkAction, watchType, watchStartingAddress, watchEndingAddress]) + + const handleClose = () => { + form.reset() + onClose() + } + + const submit = async (_data: any) => { + const { macAddress, serverId, ...data } = _data as z.infer + + clearFlashes() + try { + const address = await createAddress(pool.id, { + macAddress: macAddress && macAddress.length > 0 ? macAddress : null, + serverId: serverId !== '' ? serverId : null, + include: ['server'], + ...data, + }) + + if (address) { + mutate(data => { + if (!data) return data + if (data.pagination.currentPage !== 1) return data + + return { + ...data, + items: [address, ...data.items], + } + }, false) + } else { + mutate() + } + + handleClose() + } catch (e) { + clearAndAddHttpError(e as Error) + } + } + + return ( + + + {t('create_address')} + + + +
+ + + form.setValue('isBulkAction', val === 'multiple')} + data={[ + { value: 'single', label: tStrings('single') }, + { value: 'multiple', label: tStrings('multiple') }, + ]} + /> + + + + + {watchIsBulkAction ? ( + <> + + +

+ + {{ addressCount }} address + +

+ + ) : ( + + )} + + + + +
+ + + + {tStrings('cancel')} + + + {tStrings('create')} + + +
+
+
+ ) +} + +export default CreateAddressModal diff --git a/resources/scripts/components/admin/nodes/addresses/EditAddressModal.tsx b/resources/scripts/components/admin/nodes/addresses/EditAddressModal.tsx index c121ef32552..19e959ce31f 100644 --- a/resources/scripts/components/admin/nodes/addresses/EditAddressModal.tsx +++ b/resources/scripts/components/admin/nodes/addresses/EditAddressModal.tsx @@ -3,7 +3,6 @@ import { Address } from '@/api/server/getServer' import FlashMessageRender from '@/components/elements/FlashMessageRenderer' import TextInputFormik from '@/components/elements/formik/TextInputFormik' import Modal from '@/components/elements/Modal' -import { NodeContext } from '@/state/admin/node' import useFlash from '@/util/useFlash' import { FormikProvider, useFormik } from 'formik' import Radio from '@/components/elements/inputs/Radio' @@ -13,6 +12,7 @@ import * as yup from 'yup' import createAddress from '@/api/admin/nodes/addresses/createAddress' import updateAddress from '@/api/admin/nodes/addresses/updateAddress' import usePagination from '@/util/usePagination' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' interface Props { open: boolean @@ -22,14 +22,14 @@ interface Props { const EditAddressModal = ({ open, onClose, address }: Props) => { const { clearFlashes, clearAndAddHttpError } = useFlash() - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) + const { data: node } = useNodeSWR() const [page] = usePagination() - const { mutate } = useAddressesSWR(nodeId, { page, include: ['server'] }) + const { mutate } = useAddressesSWR(node.id, { page, include: ['server'] }) const form = useFormik({ enableReinitialize: true, initialValues: { - serverId: address?.server?.internalId.toString() ?? '', + serverId: address?.server?.id.toString() ?? '', address: address?.address ?? '', cidr: address?.cidr ?? '', gateway: address?.gateway ?? '', @@ -48,7 +48,7 @@ const EditAddressModal = ({ open, onClose, address }: Props) => { setSubmitting(true) try { if (address) { - const updatedAddress = await updateAddress(nodeId, address.id, { + const updatedAddress = await updateAddress(node.id, address.id, { ...values, serverId: parseInt(serverId as string), cidr: parseInt(cidr as string), @@ -69,7 +69,7 @@ const EditAddressModal = ({ open, onClose, address }: Props) => { } }, false) } else { - const address = await createAddress(nodeId, { + const address = await createAddress(node.id, { ...values, serverId: parseInt(serverId as string), cidr: parseInt(cidr as string), diff --git a/resources/scripts/components/admin/nodes/addresses/NodeAddressesContainer.tsx b/resources/scripts/components/admin/nodes/addresses/NodeAddressesContainer.tsx index fe5c31b6429..3cea8f20909 100644 --- a/resources/scripts/components/admin/nodes/addresses/NodeAddressesContainer.tsx +++ b/resources/scripts/components/admin/nodes/addresses/NodeAddressesContainer.tsx @@ -8,10 +8,10 @@ import Table, { Actions, ColumnArray, RowActionsProps } from '@/components/eleme import Menu from '@/components/elements/Menu' import Pagination from '@/components/elements/Pagination' import Spinner from '@/components/elements/Spinner' -import { NodeContext } from '@/state/admin/node' import usePagination from '@/util/usePagination' import { useState } from 'react' import { Link } from 'react-router-dom' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const columns: ColumnArray
= [ { @@ -47,9 +47,9 @@ const columns: ColumnArray
= [ ] const NodeAddressesContainer = () => { - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) + const { data: node } = useNodeSWR() const [page, setPage] = usePagination() - const { mutate, data } = useAddressesSWR(nodeId, { page, include: ['server'] }) + const { mutate, data } = useAddressesSWR(node.id, { page, include: ['server'] }) const [open, setOpen] = useState(false) const rowActions = ({ row }: RowActionsProps
) => { diff --git a/resources/scripts/components/admin/nodes/addresses/ServersSelectFormik.tsx b/resources/scripts/components/admin/nodes/addresses/ServersSelectFormik.tsx index a76c3dad608..d40cf5c0d12 100644 --- a/resources/scripts/components/admin/nodes/addresses/ServersSelectFormik.tsx +++ b/resources/scripts/components/admin/nodes/addresses/ServersSelectFormik.tsx @@ -1,19 +1,19 @@ import useServersSWR from '@/api/admin/servers/useServersSWR' import DescriptiveItemComponent from '@/components/elements/DescriptiveItemComponent' import SelectFormik from '@/components/elements/formik/SelectFormik' -import { NodeContext } from '@/state/admin/node' import { useDebouncedValue } from '@mantine/hooks' import { useField } from 'formik' -import { useCallback, useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const ServersSelectFormik = () => { const [{ value }] = useField('serverId') const [query, setQuery] = useState(value as string) - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) + const { data: node } = useNodeSWR() const [debouncedQuery] = useDebouncedValue(query, 200) - const { data, isLoading, isValidating } = useServersSWR({ nodeId, query: debouncedQuery }) + const { data, isLoading, isValidating } = useServersSWR({ nodeId: node.id, query: debouncedQuery }) const servers = useMemo( () => data?.items.map(server => ({ diff --git a/resources/scripts/components/admin/nodes/isos/CreateIsoModal.tsx b/resources/scripts/components/admin/nodes/isos/CreateIsoModal.tsx index d4db21cba47..cea5a04f215 100644 --- a/resources/scripts/components/admin/nodes/isos/CreateIsoModal.tsx +++ b/resources/scripts/components/admin/nodes/isos/CreateIsoModal.tsx @@ -1,23 +1,22 @@ -import FlashMessageRender from '@/components/elements/FlashMessageRenderer' -import SelectFormik from '@/components/elements/formik/SelectFormik' -import Modal from '@/components/elements/Modal' -import { NodeContext } from '@/state/admin/node' import { useFlashKey } from '@/util/useFlash' -import createIso from '@/api/admin/nodes/isos/createIso' -import QueryFileButton from '@/components/admin/nodes/isos/QueryFileButton' -import { FileMetadata } from '@/api/admin/tools/queryRemoteFile' -import { useTranslation } from 'react-i18next' -import { z } from 'zod' -import { FormProvider, useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' -import { useCallback, useMemo, useState } from 'react' -import TextInputForm from '@/components/elements/forms/TextInputForm' +import { FormProvider, useForm } from 'react-hook-form' +import { useTranslation } from 'react-i18next' import { KeyedMutator } from 'swr' +import { z } from 'zod' + +import createIso from '@/api/admin/nodes/isos/createIso' import { ISO, IsoResponse } from '@/api/admin/nodes/isos/getIsos' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' + +import FlashMessageRender from '@/components/elements/FlashMessageRenderer' +import Modal from '@/components/elements/Modal' +import SegmentedControl from '@/components/elements/SegmentedControl' import CheckboxForm from '@/components/elements/forms/CheckboxForm' -import { data } from 'autoprefixer' import SelectForm from '@/components/elements/forms/SelectForm' -import SegmentedControl from '@/components/elements/SegmentedControl' +import TextInputForm from '@/components/elements/forms/TextInputForm' + +import QueryFileButton from '@/components/admin/nodes/isos/QueryFileButton' interface Props { open: boolean @@ -26,8 +25,10 @@ interface Props { } const CreateIsoModal = ({ open, onClose, mutate }: Props) => { - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) - const { clearFlashes, clearAndAddHttpError } = useFlashKey(`admin.nodes.${nodeId}.isos.create`) + const { data: node } = useNodeSWR() + const { clearFlashes, clearAndAddHttpError } = useFlashKey( + `admin.nodes.${node.id}.isos.create` + ) const { t: tStrings } = useTranslation('strings') const { t } = useTranslation('admin.nodes.isos') @@ -36,7 +37,11 @@ const CreateIsoModal = ({ open, onClose, mutate }: Props) => { name: z.string().max(40).nonempty(), fileName: z .string() - .regex(/\.iso$/, t('create_modal.non_iso_file_name_error') ?? 'The file extension must end in .iso') + .regex( + /\.iso$/, + t('create_modal.non_iso_file_name_error') ?? + 'The file extension must end in .iso' + ) .max(191) .nonempty(), hidden: z.boolean(), @@ -48,7 +53,11 @@ const CreateIsoModal = ({ open, onClose, mutate }: Props) => { link: z.string().url().max(191).nonempty(), fileName: z .string() - .regex(/\.iso$/, t('create_modal.non_iso_file_name_error') ?? 'The file extension must end in .iso') + .regex( + /\.iso$/, + t('create_modal.non_iso_file_name_error') ?? + 'The file extension must end in .iso' + ) .max(191) .nonempty(), checksumAlgorithm: z.literal('none'), @@ -62,17 +71,35 @@ const CreateIsoModal = ({ open, onClose, mutate }: Props) => { link: z.string().url().max(191).nonempty(), fileName: z .string() - .regex(/\.iso$/, t('create_modal.non_iso_file_name_error') ?? 'The file extension must end in .iso') + .regex( + /\.iso$/, + t('create_modal.non_iso_file_name_error') ?? + 'The file extension must end in .iso' + ) .max(191) .nonempty(), - checksumAlgorithm: z.enum(['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512']), + checksumAlgorithm: z.enum([ + 'md5', + 'sha1', + 'sha224', + 'sha256', + 'sha384', + 'sha512', + ]), checksum: z.string().max(191).nonempty(), hidden: z.boolean(), }) - const schemaWithDownloading = z.discriminatedUnion('checksumAlgorithm', [schemaWithoutChecksum, schemaWithChecksum]) + const schemaWithDownloading = z.discriminatedUnion('checksumAlgorithm', [ + schemaWithoutChecksum, + schemaWithChecksum, + ]) - const schema = z.union([schemaWithoutDownloading, schemaWithoutChecksum, schemaWithChecksum]) + const schema = z.union([ + schemaWithoutDownloading, + schemaWithoutChecksum, + schemaWithChecksum, + ]) const form = useForm({ resolver: zodResolver(schema), @@ -99,8 +126,11 @@ const CreateIsoModal = ({ open, onClose, mutate }: Props) => { const { checksumAlgorithm, ...params } = data try { - const iso = await createIso(nodeId, { - checksumAlgorithm: checksumAlgorithm !== 'none' ? checksumAlgorithm : undefined, + const iso = await createIso(node.id, { + checksumAlgorithm: + checksumAlgorithm !== 'none' + ? checksumAlgorithm + : undefined, ...params, }) @@ -114,7 +144,7 @@ const CreateIsoModal = ({ open, onClose, mutate }: Props) => { if (!data.shouldDownload) { try { - const iso = await createIso(nodeId, data) + const iso = await createIso(node.id, data) appendToSWR(iso) } catch (e) { @@ -132,7 +162,8 @@ const CreateIsoModal = ({ open, onClose, mutate }: Props) => { if (!isoResponse) return isoResponse if ( isoResponse.pagination.totalPages > 1 && - isoResponse.pagination.currentPage !== isoResponse.pagination.totalPages + isoResponse.pagination.currentPage !== + isoResponse.pagination.totalPages ) return isoResponse @@ -168,20 +199,37 @@ const CreateIsoModal = ({ open, onClose, mutate }: Props) => {
- + form.setValue('shouldDownload', val === 'download')} + onChange={val => + form.setValue( + 'shouldDownload', + val === 'download' + ) + } data={[ - { value: 'download', label: tStrings('download') }, + { + value: 'download', + label: tStrings('download'), + }, { value: 'import', label: tStrings('import') }, ]} /> - + {watchShouldDownload && ( -
+
{
)} - + {watchShouldDownload && ( <> { /> )} - + {tStrings('cancel')} - + {tStrings('create')} diff --git a/resources/scripts/components/admin/nodes/isos/EditIsoModal.tsx b/resources/scripts/components/admin/nodes/isos/EditIsoModal.tsx index 91e76b0ffb9..94c177b5d09 100644 --- a/resources/scripts/components/admin/nodes/isos/EditIsoModal.tsx +++ b/resources/scripts/components/admin/nodes/isos/EditIsoModal.tsx @@ -9,6 +9,7 @@ import { NodeContext } from '@/state/admin/node' import useFlash from '@/util/useFlash' import { FormikProvider, useFormik } from 'formik' import * as yup from 'yup' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' interface Props { open: boolean @@ -17,9 +18,9 @@ interface Props { } const EditIsoModal = ({ open, onClose, iso }: Props) => { - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) + const { data: node } = useNodeSWR() const { clearFlashes, clearAndAddHttpError } = useFlash() - const { mutate } = useIsosSWR({ nodeId }) + const { mutate } = useIsosSWR({ nodeId: node.id }) const form = useFormik({ enableReinitialize: true, @@ -34,14 +35,14 @@ const EditIsoModal = ({ open, onClose, iso }: Props) => { onSubmit: ({ name, hidden }, { setSubmitting }) => { setSubmitting(true) clearFlashes('admin:node:iso.update') - updateIso(nodeId, iso.uuid, name, hidden) + updateIso(node.id, iso.uuid, name, hidden) .then(newIso => { mutate( mutateData => ({ ...mutateData, items: mutateData!.items.map(item => (item.uuid === newIso.uuid ? newIso : item)), - } as IsoResponse), + }) as IsoResponse, false ) setSubmitting(false) diff --git a/resources/scripts/components/admin/nodes/isos/IsosContainer.tsx b/resources/scripts/components/admin/nodes/isos/IsosContainer.tsx index 81992350388..d0355d71806 100644 --- a/resources/scripts/components/admin/nodes/isos/IsosContainer.tsx +++ b/resources/scripts/components/admin/nodes/isos/IsosContainer.tsx @@ -16,6 +16,7 @@ import Menu from '@/components/elements/Menu' import deleteIso from '@/api/admin/nodes/isos/deleteIso' import EditIsoModal from '@/components/admin/nodes/isos/EditIsoModal' import { useTranslation } from 'react-i18next' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const columns: ColumnArray = [ { @@ -62,9 +63,9 @@ const columns: ColumnArray = [ ] const IsosContainer = () => { - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) + const { data: node } = useNodeSWR() const [page, setPage] = usePagination() - const { data, mutate } = useIsosSWR({ nodeId }) + const { data, mutate } = useIsosSWR({ nodeId: node.id }) const [showCreateModal, setShowCreateModal] = useState(false) const { t } = useTranslation('admin.nodes.isos') @@ -72,13 +73,13 @@ const IsosContainer = () => { const [open, setOpen] = useState(false) const handleDelete = () => { - deleteIso(nodeId, iso.uuid).then(() => { + deleteIso(node.id, iso.uuid).then(() => { mutate( mutateData => ({ ...mutateData, items: mutateData!.items.filter(datum => datum.uuid !== iso.uuid), - } as IsoResponse), + }) as IsoResponse, false ) }) diff --git a/resources/scripts/components/admin/nodes/isos/QueryFileButton.tsx b/resources/scripts/components/admin/nodes/isos/QueryFileButton.tsx index 1708e129498..a37d2001b77 100644 --- a/resources/scripts/components/admin/nodes/isos/QueryFileButton.tsx +++ b/resources/scripts/components/admin/nodes/isos/QueryFileButton.tsx @@ -4,10 +4,11 @@ import { NodeContext } from '@/state/admin/node' import { useState } from 'react' import { useFormContext } from 'react-hook-form' import { useTranslation } from 'react-i18next' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const QueryFileButton = () => { const { getValues, setError, setValue } = useFormContext() - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) + const { data: node } = useNodeSWR() const [loading, setLoading] = useState(false) const { t: tStrings } = useTranslation('strings') const { t } = useTranslation('admin.nodes.isos') @@ -16,7 +17,7 @@ const QueryFileButton = () => { setLoading(true) try { - const metadata = await queryRemoteFile(nodeId, getValues('link')) + const metadata = await queryRemoteFile(node.id, getValues('link')) setValue('fileName', metadata.fileName) } catch { diff --git a/resources/scripts/components/admin/nodes/overview/NodeDetailsBlock.tsx b/resources/scripts/components/admin/nodes/overview/NodeDetailsBlock.tsx index fc41d051fd0..ea7952f8fb3 100644 --- a/resources/scripts/components/admin/nodes/overview/NodeDetailsBlock.tsx +++ b/resources/scripts/components/admin/nodes/overview/NodeDetailsBlock.tsx @@ -3,9 +3,10 @@ import { NodeContext } from '@/state/admin/node' import { formatBytes } from '@/util/helpers' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const NodeDetailsBlock = () => { - const node = NodeContext.useStoreState(state => state.node.data!) + const { data: node } = useNodeSWR() const { t } = useTranslation('admin.nodes.index') const memory = useMemo(() => { diff --git a/resources/scripts/components/admin/nodes/servers/NodeServersContainer.tsx b/resources/scripts/components/admin/nodes/servers/NodeServersContainer.tsx index b99d7ee520f..d3754f7ed7e 100644 --- a/resources/scripts/components/admin/nodes/servers/NodeServersContainer.tsx +++ b/resources/scripts/components/admin/nodes/servers/NodeServersContainer.tsx @@ -5,18 +5,24 @@ import { useState } from 'react' import CreateServerModal from '@/components/admin/servers/CreateServerModal' import SearchBar from '@/components/admin/SearchBar' import { useDebouncedValue } from '@mantine/hooks' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const NodeServersContainer = () => { const [query, setQuery] = useState('') const [debouncedQuery] = useDebouncedValue(query, 200) const [open, setOpen] = useState(false) - const node = NodeContext.useStoreState(state => state.node.data!) + const { data: node } = useNodeSWR() return (
setOpen(false)} nodeId={node.id} /> - setQuery(e.target.value)} buttonText='New Server' onClick={() => setOpen(true)} /> + setQuery(e.target.value)} + buttonText='New Server' + onClick={() => setOpen(true)} + />
diff --git a/resources/scripts/components/admin/nodes/settings/NodeSettingsContainer.tsx b/resources/scripts/components/admin/nodes/settings/NodeSettingsContainer.tsx index 4d021c93f02..0ba8dcc0aa7 100644 --- a/resources/scripts/components/admin/nodes/settings/NodeSettingsContainer.tsx +++ b/resources/scripts/components/admin/nodes/settings/NodeSettingsContainer.tsx @@ -7,12 +7,12 @@ const NodeSettingsContainer = () => { return ( } routes={[ { - path: '/admin/nodes/:id/settings/general', + path: '/admin/nodes/:nodeId/settings/general', name: tStrings('general'), }, ]} diff --git a/resources/scripts/components/admin/nodes/settings/partials/general/CotermCard.tsx b/resources/scripts/components/admin/nodes/settings/partials/general/CotermCard.tsx index 8a0b64c8750..b6298ac8efe 100644 --- a/resources/scripts/components/admin/nodes/settings/partials/general/CotermCard.tsx +++ b/resources/scripts/components/admin/nodes/settings/partials/general/CotermCard.tsx @@ -16,10 +16,10 @@ import { useState } from 'react' import CotermTokenModal from '@/components/admin/nodes/settings/partials/general/CotermTokenModal' import CotermResetModal from '@/components/admin/nodes/settings/partials/general/CotermResetModal' import FlashMessageRender from '@/components/elements/FlashMessageRenderer' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const CotermCard = () => { - const node = NodeContext.useStoreState(state => state.node.data!) - const setNode = NodeContext.useStoreActions(actions => actions.node.setNode) + const { data: node, mutate } = useNodeSWR() const { clearFlashes, clearAndAddHttpError } = useFlashKey(`admin.nodes.${node.id}.settings.general.coterm`) const { t: tStrings } = useTranslation('strings') const { t } = useTranslation('admin.nodes.settings') @@ -55,7 +55,7 @@ const CotermCard = () => { const isEnabled = form.watch('isEnabled') const submit = async (_data: any) => { - const {fqdn, ...data} = _data as z.infer + const { fqdn, ...data } = _data as z.infer clearFlashes() try { @@ -75,7 +75,16 @@ const CotermCard = () => { isTlsEnabled: details.isTlsEnabled, }) - setNode({ ...node, ...details }) + mutate( + data => ({ + ...data!, + cotermEnabled: details.isEnabled, + cotermFqdn: details.fqdn, + cotermPort: details.port, + cotermTlsEnabled: details.isTlsEnabled, + }), + false + ) } catch (e) { clearAndAddHttpError(e as Error) } @@ -126,7 +135,12 @@ const CotermCard = () => { label={t('coterm.tls')} disabled={!isEnabled} /> -
diff --git a/resources/scripts/components/admin/nodes/settings/partials/general/DeleteNodeCard.tsx b/resources/scripts/components/admin/nodes/settings/partials/general/DeleteNodeCard.tsx index 1b7b37fa019..be09e45def3 100644 --- a/resources/scripts/components/admin/nodes/settings/partials/general/DeleteNodeCard.tsx +++ b/resources/scripts/components/admin/nodes/settings/partials/general/DeleteNodeCard.tsx @@ -8,10 +8,11 @@ import { useFlashKey } from '@/util/useFlash' import { useNavigate } from 'react-router-dom' import deleteNode from '@/api/admin/nodes/deleteNode' import { useState } from 'react' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const DeleteNodeCard = () => { - const { clearFlashes, clearAndAddHttpError } = useFlashKey('admin:node:settings:delete') - const node = NodeContext.useStoreState(state => state.node.data!) + const { data: node } = useNodeSWR() + const { clearFlashes, clearAndAddHttpError } = useFlashKey(`admin.nodes.${node.id}.settings.general.delete`) const navigate = useNavigate() const [loading, setLoading] = useState(false) @@ -33,7 +34,7 @@ const DeleteNodeCard = () => { Delete Node
- +

The node will be permanently deleted from Convoy. This action is irreversible and can not be diff --git a/resources/scripts/components/admin/nodes/settings/partials/general/NodeInformationCard.tsx b/resources/scripts/components/admin/nodes/settings/partials/general/NodeInformationCard.tsx index 95580aac662..92667bd062c 100644 --- a/resources/scripts/components/admin/nodes/settings/partials/general/NodeInformationCard.tsx +++ b/resources/scripts/components/admin/nodes/settings/partials/general/NodeInformationCard.tsx @@ -11,10 +11,10 @@ import { FormProvider, useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { useTranslation } from 'react-i18next' import TextInputForm from '@/components/elements/forms/TextInputForm' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const NodeInformationCard = () => { - const node = NodeContext.useStoreState(state => state.node.data!) - const setNode = NodeContext.useStoreActions(actions => actions.node.setNode) + const { data: node, mutate } = useNodeSWR() const { clearFlashes, clearAndAddHttpError } = useFlashKey(`admin.nodes.${node.id}.settings.general.info`) const { t: tStrings } = useTranslation('strings') const { t } = useTranslation('admin.nodes.settings') @@ -69,7 +69,7 @@ const NodeInformationCard = () => { disk: disk * 1048576, }) - setNode(updatedNode) + mutate(() => updatedNode, false) form.reset({ name: data.name, diff --git a/resources/scripts/components/admin/nodes/templates/EditTemplateGroupModal.tsx b/resources/scripts/components/admin/nodes/templates/EditTemplateGroupModal.tsx index ef3700e2946..c389f19497c 100644 --- a/resources/scripts/components/admin/nodes/templates/EditTemplateGroupModal.tsx +++ b/resources/scripts/components/admin/nodes/templates/EditTemplateGroupModal.tsx @@ -10,6 +10,7 @@ import { NodeContext } from '@/state/admin/node' import useFlash from '@/util/useFlash' import { FormikProvider, useFormik } from 'formik' import * as yup from 'yup' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' interface Props { open: boolean @@ -19,8 +20,8 @@ interface Props { const EditTemplateGroupModal = ({ open, onClose, group }: Props) => { const { clearFlashes, clearAndAddHttpError } = useFlash() - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) - const { mutate } = useTemplateGroupsSWR(nodeId) + const { data: node } = useNodeSWR() + const { mutate } = useTemplateGroupsSWR(node.id) const form = useFormik({ enableReinitialize: true, @@ -37,7 +38,7 @@ const EditTemplateGroupModal = ({ open, onClose, group }: Props) => { clearFlashes('admin:node:template-groups.edit') if (group) { - updateTemplateGroup(nodeId, group.uuid, values) + updateTemplateGroup(node.id, group.uuid, values) .then(({ name, hidden }) => { handleClose() @@ -49,7 +50,7 @@ const EditTemplateGroupModal = ({ open, onClose, group }: Props) => { setSubmitting(false) }) } else { - createTemplateGroup(nodeId, values) + createTemplateGroup(node.id, values) .then(newGroup => { handleClose() @@ -64,17 +65,6 @@ const EditTemplateGroupModal = ({ open, onClose, group }: Props) => { }, ] }, false) - - // mutate( - // groups => [ - // ...groups, - // { - // ...newGroup, - // templates: [], - // }, - // ], - // false - // ) }) .catch(error => { clearAndAddHttpError({ key: 'admin:node:template-groups.edit', error }) diff --git a/resources/scripts/components/admin/nodes/templates/EditTemplateModal.tsx b/resources/scripts/components/admin/nodes/templates/EditTemplateModal.tsx index 22fcb971123..c8bbd9aa546 100644 --- a/resources/scripts/components/admin/nodes/templates/EditTemplateModal.tsx +++ b/resources/scripts/components/admin/nodes/templates/EditTemplateModal.tsx @@ -10,6 +10,7 @@ import { NodeContext } from '@/state/admin/node' import useFlash from '@/util/useFlash' import { FormikProvider, useFormik } from 'formik' import * as yup from 'yup' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' interface Props { open: boolean @@ -20,8 +21,8 @@ interface Props { const EditTemplateModal = ({ open, onClose, template, group }: Props) => { const { clearFlashes, clearAndAddHttpError } = useFlash() - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) - const { mutate } = useTemplateGroupsSWR(nodeId) + const { data: node } = useNodeSWR() + const { mutate } = useTemplateGroupsSWR(node.id) const form = useFormik({ enableReinitialize: true, @@ -45,7 +46,7 @@ const EditTemplateModal = ({ open, onClose, template, group }: Props) => { try { if (template) { - await updateTemplate(nodeId, group.uuid, template.uuid, { + await updateTemplate(node.id, group.uuid, template.uuid, { ...values, vmid: vmid as number, }) @@ -78,7 +79,7 @@ const EditTemplateModal = ({ open, onClose, template, group }: Props) => { false ) } else { - const template = await createTemplate(nodeId, group.uuid, { + const template = await createTemplate(node.id, group.uuid, { ...values, vmid: vmid as number, }) diff --git a/resources/scripts/components/admin/nodes/templates/NodeTemplatesContainer.tsx b/resources/scripts/components/admin/nodes/templates/NodeTemplatesContainer.tsx index a566793617f..abfc6064d89 100644 --- a/resources/scripts/components/admin/nodes/templates/NodeTemplatesContainer.tsx +++ b/resources/scripts/components/admin/nodes/templates/NodeTemplatesContainer.tsx @@ -27,10 +27,11 @@ import TemplateGroupCard from '@/components/admin/nodes/templates/TemplateGroupC import EditTemplateGroupModal from '@/components/admin/nodes/templates/EditTemplateGroupModal' import useFlash from '@/util/useFlash' import { httpErrorToHuman } from '@/api/http' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' const NodeTemplatesContainer = () => { - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) - const { data, mutate } = useTemplatesGroupSWR(nodeId, []) + const { data: node } = useNodeSWR() + const { data, mutate } = useTemplatesGroupSWR(node.id, []) const notify = useNotify() const [showCreateModal, setShowCreateModal] = useState(false) const [activeId, setActiveId] = useState() @@ -55,7 +56,7 @@ const NodeTemplatesContainer = () => { disallowClose: true, }) - reorderTemplateGroups(nodeId, groups) + reorderTemplateGroups(node.id, groups) .then(() => { updateNotification({ id: 'admin:node:template-groups.reorder', diff --git a/resources/scripts/components/admin/nodes/templates/TemplateCard.tsx b/resources/scripts/components/admin/nodes/templates/TemplateCard.tsx index f7348106971..14efbcf42e9 100644 --- a/resources/scripts/components/admin/nodes/templates/TemplateCard.tsx +++ b/resources/scripts/components/admin/nodes/templates/TemplateCard.tsx @@ -10,6 +10,7 @@ import useFlash from '@/util/useFlash' import { EyeSlashIcon } from '@heroicons/react/20/solid' import { useState } from 'react' import DottedButton from '@/components/elements/DottedButton' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' interface Props { template: Template @@ -19,15 +20,15 @@ interface Props { const TemplateCard = ({ template, group, className }: Props) => { const [showEditModal, setShowEditModal] = useState(false) - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) - const { mutate } = useTemplateGroupsSWR(nodeId) + const { data: node } = useNodeSWR() + const { mutate } = useTemplateGroupsSWR(node.id) const { clearFlashes, clearAndAddHttpError } = useFlash() const handleDelete = async () => { clearFlashes('admin:node:template-groups') try { - await deleteTemplate(nodeId, group!.uuid, template.uuid) + await deleteTemplate(node.id, group!.uuid, template.uuid) mutate( groups => diff --git a/resources/scripts/components/admin/nodes/templates/TemplateGroupCard.tsx b/resources/scripts/components/admin/nodes/templates/TemplateGroupCard.tsx index 8f5e788c2d3..e7b01d0d2cd 100644 --- a/resources/scripts/components/admin/nodes/templates/TemplateGroupCard.tsx +++ b/resources/scripts/components/admin/nodes/templates/TemplateGroupCard.tsx @@ -31,7 +31,7 @@ import useNotify from '@/util/useNotify' import reorderTemplates from '@/api/admin/nodes/templateGroups/templates/reorderTemplates' import { updateNotification } from '@mantine/notifications' import { httpErrorToHuman } from '@/api/http' -import { DottedButton } from '@/components/elements/DottedButton' +import useNodeSWR from '@/api/admin/nodes/useNodeSWR' interface Props { group: TemplateGroup @@ -41,9 +41,9 @@ interface Props { const TemplateGroupCard = ({ group, className }: Props) => { const [showEditModal, setShowEditModal] = useState(false) const [showCreateModal, setShowCreateModal] = useState(false) - const nodeId = NodeContext.useStoreState(state => state.node.data!.id) + const { data: node } = useNodeSWR() const { clearFlashes, clearAndAddHttpError } = useFlash() - const { mutate } = useTemplateGroupsSWR(nodeId) + const { mutate } = useTemplateGroupsSWR(node.id) const [activeTemplate, setActiveTemplate] = useState